merge upstream
This commit is contained in:
commit
51d0fe1b5d
202 changed files with 36870 additions and 32114 deletions
|
|
@ -1,4 +1,4 @@
|
|||
/lib
|
||||
/docs
|
||||
/__tests__/fixtures/cli-utils.js
|
||||
defaultConfig.stub.js
|
||||
/stubs/*
|
||||
|
|
|
|||
|
|
@ -3,11 +3,8 @@
|
|||
"jest": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": ["eslint-config-postcss", "prettier"],
|
||||
"plugins": ["prettier"],
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,4 +1,6 @@
|
|||
/node_modules
|
||||
/lib
|
||||
/example
|
||||
index.html
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/__tests__/
|
||||
/jest/
|
||||
/src/
|
||||
index.html
|
||||
yarn-error.log
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ For help, discussion about best practices, or any other conversation that would
|
|||
|
||||
For casual chit-chat with others using the framework:
|
||||
|
||||
[Join the Tailwind CSS Slack Community](https://join.slack.com/t/tailwindcss/shared_invite/enQtNDQ1MDYyNDA0NzA3LTAzOGEzYTRmMjE2OWUwMGViMGM2NGM5OWVmN2UzZjlmNzQ0ZTA2NGUwODYyOWMzNzM0M2MzMmE1NGYyNjk5NTI)
|
||||
[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
import postcss from 'postcss'
|
||||
import substituteClassApplyAtRules from '../src/lib/substituteClassApplyAtRules'
|
||||
import processPlugins from '../src/util/processPlugins'
|
||||
import resolveConfig from '../src/util/resolveConfig'
|
||||
import corePlugins from '../src/corePlugins'
|
||||
import defaultConfig from '../defaultConfig.stub.js'
|
||||
import defaultConfig from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
const { utilities: defaultUtilities } = processPlugins(corePlugins(defaultConfig), defaultConfig)
|
||||
const resolvedDefaultConfig = resolveConfig([defaultConfig])
|
||||
|
||||
function run(input, config = defaultConfig, utilities = defaultUtilities) {
|
||||
const { utilities: defaultUtilities } = processPlugins(
|
||||
corePlugins(resolvedDefaultConfig),
|
||||
resolvedDefaultConfig
|
||||
)
|
||||
|
||||
function run(input, config = resolvedDefaultConfig, utilities = defaultUtilities) {
|
||||
return postcss([substituteClassApplyAtRules(config, utilities)]).process(input, {
|
||||
from: undefined,
|
||||
})
|
||||
|
|
@ -200,10 +206,12 @@ test('you can apply utility classes without using the given prefix', () => {
|
|||
.foo { margin-top: 1rem; margin-bottom: 1rem; }
|
||||
`
|
||||
|
||||
const config = {
|
||||
...defaultConfig,
|
||||
prefix: 'tw-',
|
||||
}
|
||||
const config = resolveConfig([
|
||||
{
|
||||
...defaultConfig,
|
||||
prefix: 'tw-',
|
||||
},
|
||||
])
|
||||
|
||||
return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => {
|
||||
expect(result.css).toEqual(expected)
|
||||
|
|
@ -220,12 +228,14 @@ test('you can apply utility classes without using the given prefix when using a
|
|||
.foo { margin-top: 1rem; margin-bottom: 1rem; }
|
||||
`
|
||||
|
||||
const config = {
|
||||
...defaultConfig,
|
||||
prefix: () => {
|
||||
return 'tw-'
|
||||
const config = resolveConfig([
|
||||
{
|
||||
...defaultConfig,
|
||||
prefix: () => {
|
||||
return 'tw-'
|
||||
},
|
||||
},
|
||||
}
|
||||
])
|
||||
|
||||
return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => {
|
||||
expect(result.css).toEqual(expected)
|
||||
|
|
|
|||
19
__tests__/cli.compile.test.js
Normal file
19
__tests__/cli.compile.test.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import path from 'path'
|
||||
|
||||
import autoprefixer from 'autoprefixer'
|
||||
|
||||
import tailwind from '../src'
|
||||
import compile from '../src/cli/compile'
|
||||
|
||||
describe('cli compile', () => {
|
||||
const inputFile = path.resolve(__dirname, 'fixtures/tailwind-input.css')
|
||||
const outputFile = 'output.css'
|
||||
const plugins = [tailwind(), autoprefixer]
|
||||
|
||||
it('compiles CSS file', () => {
|
||||
return compile({ inputFile, outputFile, plugins }).then(result => {
|
||||
expect(result.css).toContain('.example')
|
||||
expect(result.css).toContain('-ms-input-placeholder')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,36 +1,43 @@
|
|||
import path from 'path'
|
||||
|
||||
import cli from '../src/cli/main'
|
||||
import * as constants from '../src/cli/constants'
|
||||
import * as constants from '../src/constants'
|
||||
import * as utils from '../src/cli/utils'
|
||||
import runInTempDirectory from '../jest/runInTempDirectory'
|
||||
|
||||
describe('cli', () => {
|
||||
const inputCssPath = path.resolve(__dirname, 'fixtures/tailwind-input.css')
|
||||
const customConfigPath = path.resolve(__dirname, 'fixtures/custom-config.js')
|
||||
const defaultConfigFixture = utils.readFile(constants.defaultConfigStubFile)
|
||||
const simpleConfigFixture = utils.readFile(constants.simpleConfigStubFile)
|
||||
|
||||
beforeEach(() => {
|
||||
console.log = jest.fn()
|
||||
process.stdout.write = jest.fn()
|
||||
utils.writeFile = jest.fn()
|
||||
})
|
||||
|
||||
describe('init', () => {
|
||||
it('creates a Tailwind config file', () => {
|
||||
return cli(['init']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][0]).toEqual(constants.defaultConfigFile)
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['init']).then(() => {
|
||||
expect(utils.readFile(constants.defaultConfigFile)).toEqual(simpleConfigFixture)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a full Tailwind config file', () => {
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['init', '--full']).then(() => {
|
||||
expect(utils.readFile(constants.defaultConfigFile)).toEqual(defaultConfigFixture)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a Tailwind config file in a custom location', () => {
|
||||
return cli(['init', 'custom.js']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][0]).toEqual('custom.js')
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a Tailwind config file without comments', () => {
|
||||
return cli(['init', '--no-comments']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][1]).not.toContain('/**')
|
||||
expect(utils.writeFile.mock.calls[0][1]).toContain('//')
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['init', 'custom.js']).then(() => {
|
||||
expect(utils.exists('custom.js')).toEqual(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -49,9 +56,10 @@ describe('cli', () => {
|
|||
})
|
||||
|
||||
it('creates compiled CSS file', () => {
|
||||
return cli(['build', inputCssPath, '--output', 'output.css']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][0]).toEqual('output.css')
|
||||
expect(utils.writeFile.mock.calls[0][1]).toContain('.example')
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['build', inputCssPath, '--output', 'output.css']).then(() => {
|
||||
expect(utils.readFile('output.css')).toContain('.example')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import path from 'path'
|
||||
import * as utils from '../src/cli/utils'
|
||||
|
||||
describe('cli utils', () => {
|
||||
const fixture = utils.readFile(path.resolve(__dirname, 'fixtures/cli-utils.js'))
|
||||
|
||||
describe('parseCliParams', () => {
|
||||
it('parses CLI parameters', () => {
|
||||
const result = utils.parseCliParams(['a', 'b', '-c', 'd'])
|
||||
|
|
@ -60,52 +57,17 @@ describe('cli utils', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('stripBlockComments', () => {
|
||||
it('does not strip code', () => {
|
||||
const result = utils.stripBlockComments(fixture)
|
||||
describe('getSimplePath', () => {
|
||||
it('strips leading ./', () => {
|
||||
const result = utils.getSimplePath('./test')
|
||||
|
||||
expect(result).toEqual(expect.stringContaining('__code_no_comment__'))
|
||||
expect(result).toEqual(expect.stringContaining('__code_comment_line__'))
|
||||
expect(result).toEqual(expect.stringContaining('__code_comment_block__'))
|
||||
expect(result).toEqual(expect.stringContaining('__code_comment_line_important__'))
|
||||
expect(result).toEqual(expect.stringContaining('__code_comment_block_important__'))
|
||||
expect(result).toEqual('test')
|
||||
})
|
||||
|
||||
it('strips block comments', () => {
|
||||
const result = utils.stripBlockComments(fixture)
|
||||
it('returns unchanged path if it does not begin with ./', () => {
|
||||
const result = utils.getSimplePath('../test')
|
||||
|
||||
expect(result).not.toEqual(expect.stringContaining('__comment_block__'))
|
||||
expect(result).not.toEqual(expect.stringContaining('__comment_block_multiline__'))
|
||||
expect(result).not.toEqual(expect.stringContaining('__comment_block_code__'))
|
||||
})
|
||||
|
||||
it('strips docblock comments', () => {
|
||||
const result = utils.stripBlockComments(fixture)
|
||||
|
||||
expect(result).not.toEqual(expect.stringContaining('__comment_docblock__'))
|
||||
})
|
||||
|
||||
it('does not strip line comments', () => {
|
||||
const result = utils.stripBlockComments(fixture)
|
||||
|
||||
expect(result).toEqual(expect.stringContaining('__comment_line__'))
|
||||
expect(result).toEqual(expect.stringContaining('__comment_line_important__'))
|
||||
expect(result).toEqual(expect.stringContaining('__comment_line_code__'))
|
||||
expect(result).toEqual(expect.stringContaining('__comment_line_important_code__'))
|
||||
})
|
||||
|
||||
it('does not strip important block comments', () => {
|
||||
const result = utils.stripBlockComments(fixture)
|
||||
|
||||
expect(result).toEqual(expect.stringContaining('__comment_block_important__'))
|
||||
expect(result).toEqual(expect.stringContaining('__comment_block_multiline_important__'))
|
||||
expect(result).toEqual(expect.stringContaining('__comment_block_important_code__'))
|
||||
})
|
||||
|
||||
it('does not strip important docblock comments', () => {
|
||||
const result = utils.stripBlockComments(fixture)
|
||||
|
||||
expect(result).toEqual(expect.stringContaining('__comment_docblock_important__'))
|
||||
expect(result).toEqual('../test')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,180 +2,41 @@ import configurePlugins from '../src/util/configurePlugins'
|
|||
|
||||
test('setting a plugin to false removes it', () => {
|
||||
const plugins = {
|
||||
fontSize: options => {
|
||||
return {
|
||||
plugin: 'fontSize',
|
||||
options,
|
||||
}
|
||||
},
|
||||
display: options => {
|
||||
return {
|
||||
plugin: 'display',
|
||||
options,
|
||||
}
|
||||
},
|
||||
backgroundPosition: options => {
|
||||
return {
|
||||
plugin: 'backgroundPosition',
|
||||
options,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const configuredPlugins = configurePlugins(plugins, {
|
||||
fontSize: {},
|
||||
display: false,
|
||||
backgroundPosition: {},
|
||||
})
|
||||
|
||||
expect(configuredPlugins).toEqual([
|
||||
{ plugin: 'fontSize', options: {} },
|
||||
{ plugin: 'backgroundPosition', options: {} },
|
||||
])
|
||||
})
|
||||
|
||||
test('setting a plugin to an object configures that plugin', () => {
|
||||
const plugins = {
|
||||
fontSize: options => {
|
||||
return {
|
||||
plugin: 'fontSize',
|
||||
options,
|
||||
}
|
||||
},
|
||||
display: options => {
|
||||
return {
|
||||
plugin: 'display',
|
||||
options,
|
||||
}
|
||||
},
|
||||
backgroundPosition: options => {
|
||||
return {
|
||||
plugin: 'backgroundPosition',
|
||||
options,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const configuredPlugins = configurePlugins(plugins, {
|
||||
fontSize: {
|
||||
variants: ['responsive', 'hover'],
|
||||
values: { '12': '12px', '14': '14px', '16': '16px' },
|
||||
},
|
||||
display: { variants: ['responsive'] },
|
||||
backgroundPosition: {},
|
||||
})
|
||||
|
||||
expect(configuredPlugins).toEqual([
|
||||
{
|
||||
plugin: 'fontSize',
|
||||
options: {
|
||||
variants: ['responsive', 'hover'],
|
||||
values: { '12': '12px', '14': '14px', '16': '16px' },
|
||||
},
|
||||
},
|
||||
{ plugin: 'display', options: { variants: ['responsive'] } },
|
||||
{ plugin: 'backgroundPosition', options: {} },
|
||||
])
|
||||
})
|
||||
|
||||
test('plugins are configured with their default configuration if no custom config is provided', () => {
|
||||
const plugins = {
|
||||
fontSize: options => {
|
||||
return {
|
||||
plugin: 'fontSize',
|
||||
options,
|
||||
}
|
||||
},
|
||||
display: options => {
|
||||
return {
|
||||
plugin: 'display',
|
||||
options,
|
||||
}
|
||||
},
|
||||
backgroundPosition: options => {
|
||||
return {
|
||||
plugin: 'backgroundPosition',
|
||||
options,
|
||||
}
|
||||
},
|
||||
fontSize: () => 'fontSize',
|
||||
display: () => 'display',
|
||||
backgroundPosition: () => 'backgroundPosition',
|
||||
}
|
||||
|
||||
const configuredPlugins = configurePlugins(
|
||||
plugins,
|
||||
{
|
||||
fontSize: {
|
||||
variants: ['responsive', 'hover'],
|
||||
values: { '12': '12px', '14': '14px', '16': '16px' },
|
||||
},
|
||||
backgroundPosition: {},
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
display: { variants: ['responsive'] },
|
||||
}
|
||||
plugins
|
||||
)
|
||||
|
||||
expect(configuredPlugins).toEqual([
|
||||
{
|
||||
plugin: 'fontSize',
|
||||
options: {
|
||||
variants: ['responsive', 'hover'],
|
||||
values: { '12': '12px', '14': '14px', '16': '16px' },
|
||||
},
|
||||
},
|
||||
{ plugin: 'display', options: { variants: ['responsive'] } },
|
||||
{ plugin: 'backgroundPosition', options: {} },
|
||||
])
|
||||
expect(configuredPlugins).toEqual(['fontSize', 'backgroundPosition'])
|
||||
})
|
||||
|
||||
test('custom plugin configuration overrides default plugin configuration', () => {
|
||||
test('passing only false removes all plugins', () => {
|
||||
const plugins = {
|
||||
fontSize: options => {
|
||||
return {
|
||||
plugin: 'fontSize',
|
||||
options,
|
||||
}
|
||||
},
|
||||
display: options => {
|
||||
return {
|
||||
plugin: 'display',
|
||||
options,
|
||||
}
|
||||
},
|
||||
backgroundPosition: options => {
|
||||
return {
|
||||
plugin: 'backgroundPosition',
|
||||
options,
|
||||
}
|
||||
},
|
||||
fontSize: () => 'fontSize',
|
||||
display: () => 'display',
|
||||
backgroundPosition: () => 'backgroundPosition',
|
||||
}
|
||||
|
||||
const configuredPlugins = configurePlugins(
|
||||
plugins,
|
||||
{
|
||||
fontSize: {
|
||||
variants: ['responsive', 'hover'],
|
||||
values: { '12': '12px', '14': '14px', '16': '16px' },
|
||||
},
|
||||
display: { variants: ['responsive'] },
|
||||
backgroundPosition: {},
|
||||
},
|
||||
{
|
||||
fontSize: {
|
||||
variants: ['focus', 'active'],
|
||||
values: { sm: '.75rem', md: '1rem', lg: '1.5rem' },
|
||||
},
|
||||
}
|
||||
)
|
||||
const configuredPlugins = configurePlugins(false, plugins)
|
||||
|
||||
expect(configuredPlugins).toEqual([
|
||||
{
|
||||
plugin: 'fontSize',
|
||||
options: {
|
||||
variants: ['responsive', 'hover'],
|
||||
values: { '12': '12px', '14': '14px', '16': '16px' },
|
||||
},
|
||||
},
|
||||
{ plugin: 'display', options: { variants: ['responsive'] } },
|
||||
{ plugin: 'backgroundPosition', options: {} },
|
||||
])
|
||||
expect(configuredPlugins).toEqual([])
|
||||
})
|
||||
|
||||
test('passing an array whitelists plugins', () => {
|
||||
const plugins = {
|
||||
fontSize: () => 'fontSize',
|
||||
display: () => 'display',
|
||||
backgroundPosition: () => 'backgroundPosition',
|
||||
}
|
||||
|
||||
const configuredPlugins = configurePlugins(['display'], plugins)
|
||||
|
||||
expect(configuredPlugins).toEqual(['display'])
|
||||
})
|
||||
|
|
|
|||
|
|
@ -41,38 +41,16 @@ test.only('options are not required', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
test.only('screens can be specified explicitly', () => {
|
||||
test.only('screens can be passed explicitly', () => {
|
||||
const { components } = processPlugins(
|
||||
[
|
||||
container({
|
||||
screens: {
|
||||
sm: '400px',
|
||||
lg: '500px',
|
||||
[container()],
|
||||
config({
|
||||
theme: {
|
||||
container: {
|
||||
screens: ['400px', '500px'],
|
||||
},
|
||||
}),
|
||||
],
|
||||
config()
|
||||
)
|
||||
|
||||
expect(css(components)).toMatchCss(`
|
||||
.container { width: 100% }
|
||||
@media (min-width: 400px) {
|
||||
.container { max-width: 400px }
|
||||
}
|
||||
@media (min-width: 500px) {
|
||||
.container { max-width: 500px }
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
test.only('screens can be an array', () => {
|
||||
const { components } = processPlugins(
|
||||
[
|
||||
container({
|
||||
screens: ['400px', '500px'],
|
||||
}),
|
||||
],
|
||||
config()
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(css(components)).toMatchCss(`
|
||||
|
|
@ -88,12 +66,14 @@ test.only('screens can be an array', () => {
|
|||
|
||||
test.only('the container can be centered by default', () => {
|
||||
const { components } = processPlugins(
|
||||
[
|
||||
container({
|
||||
center: true,
|
||||
}),
|
||||
],
|
||||
config()
|
||||
[container()],
|
||||
config({
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(css(components)).toMatchCss(`
|
||||
|
|
@ -119,12 +99,14 @@ test.only('the container can be centered by default', () => {
|
|||
|
||||
test.only('horizontal padding can be included by default', () => {
|
||||
const { components } = processPlugins(
|
||||
[
|
||||
container({
|
||||
padding: '2rem',
|
||||
}),
|
||||
],
|
||||
config()
|
||||
[container()],
|
||||
config({
|
||||
theme: {
|
||||
container: {
|
||||
padding: '2rem',
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(css(components)).toMatchCss(`
|
||||
|
|
@ -150,17 +132,16 @@ test.only('horizontal padding can be included by default', () => {
|
|||
|
||||
test.only('setting all options at once', () => {
|
||||
const { components } = processPlugins(
|
||||
[
|
||||
container({
|
||||
screens: {
|
||||
sm: '400px',
|
||||
lg: '500px',
|
||||
[container()],
|
||||
config({
|
||||
theme: {
|
||||
container: {
|
||||
screens: ['400px', '500px'],
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
},
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
}),
|
||||
],
|
||||
config()
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(css(components)).toMatchCss(`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import postcss from 'postcss'
|
||||
import tailwind from '../src/index'
|
||||
import { defaultConfigFile } from '../src/constants'
|
||||
import inTempDirectory from '../jest/runInTempDirectory'
|
||||
|
||||
test('it uses the values from the custom config file', () => {
|
||||
return postcss([tailwind(path.resolve(`${__dirname}/fixtures/custom-config.js`))])
|
||||
|
|
@ -25,7 +28,6 @@ test('it uses the values from the custom config file', () => {
|
|||
}
|
||||
}
|
||||
`
|
||||
|
||||
expect(result.css).toMatchCss(expected)
|
||||
})
|
||||
})
|
||||
|
|
@ -65,3 +67,42 @@ test('custom config can be passed as an object', () => {
|
|||
expect(result.css).toMatchCss(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('tailwind.config.js is picked up by default', () => {
|
||||
return inTempDirectory(() => {
|
||||
fs.writeFileSync(
|
||||
path.resolve(defaultConfigFile),
|
||||
`module.exports = {
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
}`
|
||||
)
|
||||
|
||||
return postcss([tailwind])
|
||||
.process(
|
||||
`
|
||||
@responsive {
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ from: undefined }
|
||||
)
|
||||
.then(result => {
|
||||
expect(result.css).toMatchCss(`
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.mobile\\:foo {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import config from '../defaultConfig.js'
|
||||
import configStub from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
test('the default config matches the stub', () => {
|
||||
expect(config()).toEqual(require('../defaultConfig.stub.js'))
|
||||
expect(config).toEqual(configStub)
|
||||
})
|
||||
|
||||
test('modifying the default config does not affect the stub', () => {
|
||||
config.theme = {}
|
||||
expect(config).not.toEqual(configStub)
|
||||
})
|
||||
|
|
|
|||
11
__tests__/defaultTheme.test.js
Normal file
11
__tests__/defaultTheme.test.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import theme from '../defaultTheme.js'
|
||||
import configStub from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
test('the default theme matches the stub', () => {
|
||||
expect(theme).toEqual(configStub.theme)
|
||||
})
|
||||
|
||||
test('modifying the default theme does not affect the stub', () => {
|
||||
theme.colors = {}
|
||||
expect(theme).not.toEqual(configStub.theme)
|
||||
})
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// __comment_line__
|
||||
|
||||
//! __comment_line_important__
|
||||
|
||||
/* __comment_block__ */
|
||||
|
||||
/*! __comment_block_important__ */
|
||||
|
||||
/*
|
||||
__comment_block_multiline__
|
||||
*/
|
||||
|
||||
/*!
|
||||
__comment_block_multiline_important__
|
||||
*/
|
||||
|
||||
/**
|
||||
__comment_docblock__
|
||||
*/
|
||||
|
||||
/**!
|
||||
__comment_docblock_important__
|
||||
*/
|
||||
|
||||
const __code_no_comment__ = 'test'
|
||||
const __code_comment_line__ = 'test' // __comment_line_code__
|
||||
const __code_comment_block__ = 'test' /* __comment_block_code__ */
|
||||
const __code_comment_line_important__ = 'test' //! __comment_line_important_code__
|
||||
const __code_comment_block_important__ = 'test' /*! __comment_block_important_code__ */
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
@tailwind preflight;
|
||||
@tailwind base;
|
||||
|
||||
@tailwind components;
|
||||
|
||||
|
|
@ -7,6 +7,6 @@
|
|||
@responsive {
|
||||
.example {
|
||||
@apply .font-bold;
|
||||
color: config('theme.colors.red');
|
||||
color: theme('colors.red.500');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
color: red;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
@media (min-width: 640px) {
|
||||
.sm\:example {
|
||||
color: red;
|
||||
}
|
||||
|
|
@ -14,13 +14,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:example {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
@media (min-width: 1280px) {
|
||||
.xl\:example {
|
||||
color: red;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,302 +0,0 @@
|
|||
import mergeConfigWithDefaults from '../src/util/mergeConfigWithDefaults'
|
||||
|
||||
test('prefix key overrides default prefix', () => {
|
||||
const userConfig = {
|
||||
prefix: 'tw-',
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = mergeConfigWithDefaults(userConfig, defaultConfig)
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: 'tw-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('important key overrides default important', () => {
|
||||
const userConfig = {
|
||||
important: true,
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = mergeConfigWithDefaults(userConfig, defaultConfig)
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '',
|
||||
important: true,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('separator key overrides default separator', () => {
|
||||
const userConfig = {
|
||||
separator: '__',
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = mergeConfigWithDefaults(userConfig, defaultConfig)
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: '__',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme key is merged instead of replaced', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = mergeConfigWithDefaults(userConfig, defaultConfig)
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('variants key is merged instead of replaced', () => {
|
||||
const userConfig = {
|
||||
variants: {
|
||||
backgroundAttachment: [],
|
||||
borderColors: ['responsive', 'hover', 'focus', 'active'],
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
borderRadius: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = mergeConfigWithDefaults(userConfig, defaultConfig)
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: [],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus', 'active'],
|
||||
borderRadius: ['responsive'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('missing top level keys are pulled from the default config', () => {
|
||||
const userConfig = {}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: { green: '#00ff00' },
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = mergeConfigWithDefaults(userConfig, defaultConfig)
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: { green: '#00ff00' },
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
83
__tests__/plugins/backgroundColor.test.js
Normal file
83
__tests__/plugins/backgroundColor.test.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import _ from 'lodash'
|
||||
import escapeClassName from '../../src/util/escapeClassName'
|
||||
import plugin from '../../src/plugins/backgroundColor'
|
||||
|
||||
test('colors can be a nested object', () => {
|
||||
const addedUtilities = []
|
||||
|
||||
const config = {
|
||||
theme: {
|
||||
backgroundColor: {
|
||||
purple: 'purple',
|
||||
white: {
|
||||
25: 'rgba(255,255,255,.25)',
|
||||
50: 'rgba(255,255,255,.5)',
|
||||
75: 'rgba(255,255,255,.75)',
|
||||
default: '#fff',
|
||||
},
|
||||
red: {
|
||||
1: 'rgb(33,0,0)',
|
||||
2: 'rgb(67,0,0)',
|
||||
3: 'rgb(100,0,0)',
|
||||
},
|
||||
green: {
|
||||
1: 'rgb(0,33,0)',
|
||||
2: 'rgb(0,67,0)',
|
||||
3: 'rgb(0,100,0)',
|
||||
},
|
||||
blue: {
|
||||
1: 'rgb(0,0,33)',
|
||||
2: 'rgb(0,0,67)',
|
||||
3: 'rgb(0,0,100)',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColor: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const getConfigValue = (path, defaultValue) => _.get(config, path, defaultValue)
|
||||
const pluginApi = {
|
||||
config: getConfigValue,
|
||||
e: escapeClassName,
|
||||
theme: (path, defaultValue) => getConfigValue(`theme.${path}`, defaultValue),
|
||||
variants: (path, defaultValue) => {
|
||||
if (_.isArray(config.variants)) {
|
||||
return config.variants
|
||||
}
|
||||
|
||||
return getConfigValue(`variants.${path}`, defaultValue)
|
||||
},
|
||||
addUtilities(utilities, variants) {
|
||||
addedUtilities.push({
|
||||
utilities,
|
||||
variants,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
plugin()(pluginApi)
|
||||
|
||||
expect(addedUtilities).toEqual([
|
||||
{
|
||||
utilities: {
|
||||
'.bg-purple': { 'background-color': 'purple' },
|
||||
'.bg-white-25': { 'background-color': 'rgba(255,255,255,.25)' },
|
||||
'.bg-white-50': { 'background-color': 'rgba(255,255,255,.5)' },
|
||||
'.bg-white-75': { 'background-color': 'rgba(255,255,255,.75)' },
|
||||
'.bg-white': { 'background-color': '#fff' },
|
||||
'.bg-red-1': { 'background-color': 'rgb(33,0,0)' },
|
||||
'.bg-red-2': { 'background-color': 'rgb(67,0,0)' },
|
||||
'.bg-red-3': { 'background-color': 'rgb(100,0,0)' },
|
||||
'.bg-green-1': { 'background-color': 'rgb(0,33,0)' },
|
||||
'.bg-green-2': { 'background-color': 'rgb(0,67,0)' },
|
||||
'.bg-green-3': { 'background-color': 'rgb(0,100,0)' },
|
||||
'.bg-blue-1': { 'background-color': 'rgb(0,0,33)' },
|
||||
'.bg-blue-2': { 'background-color': 'rgb(0,0,67)' },
|
||||
'.bg-blue-3': { 'background-color': 'rgb(0,0,100)' },
|
||||
},
|
||||
variants: ['responsive'],
|
||||
},
|
||||
])
|
||||
})
|
||||
83
__tests__/plugins/borderColor.test.js
Normal file
83
__tests__/plugins/borderColor.test.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import _ from 'lodash'
|
||||
import escapeClassName from '../../src/util/escapeClassName'
|
||||
import plugin from '../../src/plugins/borderColor'
|
||||
|
||||
test('colors can be a nested object', () => {
|
||||
const addedUtilities = []
|
||||
|
||||
const config = {
|
||||
theme: {
|
||||
borderColor: {
|
||||
purple: 'purple',
|
||||
white: {
|
||||
25: 'rgba(255,255,255,.25)',
|
||||
50: 'rgba(255,255,255,.5)',
|
||||
75: 'rgba(255,255,255,.75)',
|
||||
default: '#fff',
|
||||
},
|
||||
red: {
|
||||
1: 'rgb(33,0,0)',
|
||||
2: 'rgb(67,0,0)',
|
||||
3: 'rgb(100,0,0)',
|
||||
},
|
||||
green: {
|
||||
1: 'rgb(0,33,0)',
|
||||
2: 'rgb(0,67,0)',
|
||||
3: 'rgb(0,100,0)',
|
||||
},
|
||||
blue: {
|
||||
1: 'rgb(0,0,33)',
|
||||
2: 'rgb(0,0,67)',
|
||||
3: 'rgb(0,0,100)',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const getConfigValue = (path, defaultValue) => _.get(config, path, defaultValue)
|
||||
const pluginApi = {
|
||||
config: getConfigValue,
|
||||
e: escapeClassName,
|
||||
theme: (path, defaultValue) => getConfigValue(`theme.${path}`, defaultValue),
|
||||
variants: (path, defaultValue) => {
|
||||
if (_.isArray(config.variants)) {
|
||||
return config.variants
|
||||
}
|
||||
|
||||
return getConfigValue(`variants.${path}`, defaultValue)
|
||||
},
|
||||
addUtilities(utilities, variants) {
|
||||
addedUtilities.push({
|
||||
utilities,
|
||||
variants,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
plugin()(pluginApi)
|
||||
|
||||
expect(addedUtilities).toEqual([
|
||||
{
|
||||
utilities: {
|
||||
'.border-purple': { 'border-color': 'purple' },
|
||||
'.border-white-25': { 'border-color': 'rgba(255,255,255,.25)' },
|
||||
'.border-white-50': { 'border-color': 'rgba(255,255,255,.5)' },
|
||||
'.border-white-75': { 'border-color': 'rgba(255,255,255,.75)' },
|
||||
'.border-white': { 'border-color': '#fff' },
|
||||
'.border-red-1': { 'border-color': 'rgb(33,0,0)' },
|
||||
'.border-red-2': { 'border-color': 'rgb(67,0,0)' },
|
||||
'.border-red-3': { 'border-color': 'rgb(100,0,0)' },
|
||||
'.border-green-1': { 'border-color': 'rgb(0,33,0)' },
|
||||
'.border-green-2': { 'border-color': 'rgb(0,67,0)' },
|
||||
'.border-green-3': { 'border-color': 'rgb(0,100,0)' },
|
||||
'.border-blue-1': { 'border-color': 'rgb(0,0,33)' },
|
||||
'.border-blue-2': { 'border-color': 'rgb(0,0,67)' },
|
||||
'.border-blue-3': { 'border-color': 'rgb(0,0,100)' },
|
||||
},
|
||||
variants: ['responsive'],
|
||||
},
|
||||
])
|
||||
})
|
||||
83
__tests__/plugins/fill.test.js
Normal file
83
__tests__/plugins/fill.test.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import _ from 'lodash'
|
||||
import escapeClassName from '../../src/util/escapeClassName'
|
||||
import plugin from '../../src/plugins/fill'
|
||||
|
||||
test('colors can be a nested object', () => {
|
||||
const addedUtilities = []
|
||||
|
||||
const config = {
|
||||
theme: {
|
||||
fill: {
|
||||
purple: 'purple',
|
||||
white: {
|
||||
25: 'rgba(255,255,255,.25)',
|
||||
50: 'rgba(255,255,255,.5)',
|
||||
75: 'rgba(255,255,255,.75)',
|
||||
default: '#fff',
|
||||
},
|
||||
red: {
|
||||
1: 'rgb(33,0,0)',
|
||||
2: 'rgb(67,0,0)',
|
||||
3: 'rgb(100,0,0)',
|
||||
},
|
||||
green: {
|
||||
1: 'rgb(0,33,0)',
|
||||
2: 'rgb(0,67,0)',
|
||||
3: 'rgb(0,100,0)',
|
||||
},
|
||||
blue: {
|
||||
1: 'rgb(0,0,33)',
|
||||
2: 'rgb(0,0,67)',
|
||||
3: 'rgb(0,0,100)',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
fill: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const getConfigValue = (path, defaultValue) => _.get(config, path, defaultValue)
|
||||
const pluginApi = {
|
||||
config: getConfigValue,
|
||||
e: escapeClassName,
|
||||
theme: (path, defaultValue) => getConfigValue(`theme.${path}`, defaultValue),
|
||||
variants: (path, defaultValue) => {
|
||||
if (_.isArray(config.variants)) {
|
||||
return config.variants
|
||||
}
|
||||
|
||||
return getConfigValue(`variants.${path}`, defaultValue)
|
||||
},
|
||||
addUtilities(utilities, variants) {
|
||||
addedUtilities.push({
|
||||
utilities,
|
||||
variants,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
plugin()(pluginApi)
|
||||
|
||||
expect(addedUtilities).toEqual([
|
||||
{
|
||||
utilities: {
|
||||
'.fill-purple': { fill: 'purple' },
|
||||
'.fill-white-25': { fill: 'rgba(255,255,255,.25)' },
|
||||
'.fill-white-50': { fill: 'rgba(255,255,255,.5)' },
|
||||
'.fill-white-75': { fill: 'rgba(255,255,255,.75)' },
|
||||
'.fill-white': { fill: '#fff' },
|
||||
'.fill-red-1': { fill: 'rgb(33,0,0)' },
|
||||
'.fill-red-2': { fill: 'rgb(67,0,0)' },
|
||||
'.fill-red-3': { fill: 'rgb(100,0,0)' },
|
||||
'.fill-green-1': { fill: 'rgb(0,33,0)' },
|
||||
'.fill-green-2': { fill: 'rgb(0,67,0)' },
|
||||
'.fill-green-3': { fill: 'rgb(0,100,0)' },
|
||||
'.fill-blue-1': { fill: 'rgb(0,0,33)' },
|
||||
'.fill-blue-2': { fill: 'rgb(0,0,67)' },
|
||||
'.fill-blue-3': { fill: 'rgb(0,0,100)' },
|
||||
},
|
||||
variants: ['responsive'],
|
||||
},
|
||||
])
|
||||
})
|
||||
83
__tests__/plugins/stroke.test.js
Normal file
83
__tests__/plugins/stroke.test.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import _ from 'lodash'
|
||||
import escapeClassName from '../../src/util/escapeClassName'
|
||||
import plugin from '../../src/plugins/stroke'
|
||||
|
||||
test('colors can be a nested object', () => {
|
||||
const addedUtilities = []
|
||||
|
||||
const config = {
|
||||
theme: {
|
||||
stroke: {
|
||||
purple: 'purple',
|
||||
white: {
|
||||
25: 'rgba(255,255,255,.25)',
|
||||
50: 'rgba(255,255,255,.5)',
|
||||
75: 'rgba(255,255,255,.75)',
|
||||
default: '#fff',
|
||||
},
|
||||
red: {
|
||||
1: 'rgb(33,0,0)',
|
||||
2: 'rgb(67,0,0)',
|
||||
3: 'rgb(100,0,0)',
|
||||
},
|
||||
green: {
|
||||
1: 'rgb(0,33,0)',
|
||||
2: 'rgb(0,67,0)',
|
||||
3: 'rgb(0,100,0)',
|
||||
},
|
||||
blue: {
|
||||
1: 'rgb(0,0,33)',
|
||||
2: 'rgb(0,0,67)',
|
||||
3: 'rgb(0,0,100)',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
stroke: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const getConfigValue = (path, defaultValue) => _.get(config, path, defaultValue)
|
||||
const pluginApi = {
|
||||
config: getConfigValue,
|
||||
e: escapeClassName,
|
||||
theme: (path, defaultValue) => getConfigValue(`theme.${path}`, defaultValue),
|
||||
variants: (path, defaultValue) => {
|
||||
if (_.isArray(config.variants)) {
|
||||
return config.variants
|
||||
}
|
||||
|
||||
return getConfigValue(`variants.${path}`, defaultValue)
|
||||
},
|
||||
addUtilities(utilities, variants) {
|
||||
addedUtilities.push({
|
||||
utilities,
|
||||
variants,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
plugin()(pluginApi)
|
||||
|
||||
expect(addedUtilities).toEqual([
|
||||
{
|
||||
utilities: {
|
||||
'.stroke-purple': { stroke: 'purple' },
|
||||
'.stroke-white-25': { stroke: 'rgba(255,255,255,.25)' },
|
||||
'.stroke-white-50': { stroke: 'rgba(255,255,255,.5)' },
|
||||
'.stroke-white-75': { stroke: 'rgba(255,255,255,.75)' },
|
||||
'.stroke-white': { stroke: '#fff' },
|
||||
'.stroke-red-1': { stroke: 'rgb(33,0,0)' },
|
||||
'.stroke-red-2': { stroke: 'rgb(67,0,0)' },
|
||||
'.stroke-red-3': { stroke: 'rgb(100,0,0)' },
|
||||
'.stroke-green-1': { stroke: 'rgb(0,33,0)' },
|
||||
'.stroke-green-2': { stroke: 'rgb(0,67,0)' },
|
||||
'.stroke-green-3': { stroke: 'rgb(0,100,0)' },
|
||||
'.stroke-blue-1': { stroke: 'rgb(0,0,33)' },
|
||||
'.stroke-blue-2': { stroke: 'rgb(0,0,67)' },
|
||||
'.stroke-blue-3': { stroke: 'rgb(0,0,100)' },
|
||||
},
|
||||
variants: ['responsive'],
|
||||
},
|
||||
])
|
||||
})
|
||||
83
__tests__/plugins/textColor.test.js
Normal file
83
__tests__/plugins/textColor.test.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import _ from 'lodash'
|
||||
import escapeClassName from '../../src/util/escapeClassName'
|
||||
import plugin from '../../src/plugins/textColor'
|
||||
|
||||
test('colors can be a nested object', () => {
|
||||
const addedUtilities = []
|
||||
|
||||
const config = {
|
||||
theme: {
|
||||
textColor: {
|
||||
purple: 'purple',
|
||||
white: {
|
||||
25: 'rgba(255,255,255,.25)',
|
||||
50: 'rgba(255,255,255,.5)',
|
||||
75: 'rgba(255,255,255,.75)',
|
||||
default: '#fff',
|
||||
},
|
||||
red: {
|
||||
1: 'rgb(33,0,0)',
|
||||
2: 'rgb(67,0,0)',
|
||||
3: 'rgb(100,0,0)',
|
||||
},
|
||||
green: {
|
||||
1: 'rgb(0,33,0)',
|
||||
2: 'rgb(0,67,0)',
|
||||
3: 'rgb(0,100,0)',
|
||||
},
|
||||
blue: {
|
||||
1: 'rgb(0,0,33)',
|
||||
2: 'rgb(0,0,67)',
|
||||
3: 'rgb(0,0,100)',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
textColor: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const getConfigValue = (path, defaultValue) => _.get(config, path, defaultValue)
|
||||
const pluginApi = {
|
||||
config: getConfigValue,
|
||||
e: escapeClassName,
|
||||
theme: (path, defaultValue) => getConfigValue(`theme.${path}`, defaultValue),
|
||||
variants: (path, defaultValue) => {
|
||||
if (_.isArray(config.variants)) {
|
||||
return config.variants
|
||||
}
|
||||
|
||||
return getConfigValue(`variants.${path}`, defaultValue)
|
||||
},
|
||||
addUtilities(utilities, variants) {
|
||||
addedUtilities.push({
|
||||
utilities,
|
||||
variants,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
plugin()(pluginApi)
|
||||
|
||||
expect(addedUtilities).toEqual([
|
||||
{
|
||||
utilities: {
|
||||
'.text-purple': { color: 'purple' },
|
||||
'.text-white-25': { color: 'rgba(255,255,255,.25)' },
|
||||
'.text-white-50': { color: 'rgba(255,255,255,.5)' },
|
||||
'.text-white-75': { color: 'rgba(255,255,255,.75)' },
|
||||
'.text-white': { color: '#fff' },
|
||||
'.text-red-1': { color: 'rgb(33,0,0)' },
|
||||
'.text-red-2': { color: 'rgb(67,0,0)' },
|
||||
'.text-red-3': { color: 'rgb(100,0,0)' },
|
||||
'.text-green-1': { color: 'rgb(0,33,0)' },
|
||||
'.text-green-2': { color: 'rgb(0,67,0)' },
|
||||
'.text-green-3': { color: 'rgb(0,100,0)' },
|
||||
'.text-blue-1': { color: 'rgb(0,0,33)' },
|
||||
'.text-blue-2': { color: 'rgb(0,0,67)' },
|
||||
'.text-blue-3': { color: 'rgb(0,0,100)' },
|
||||
},
|
||||
variants: ['responsive'],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import _ from 'lodash'
|
||||
import postcss from 'postcss'
|
||||
import _postcss from 'postcss'
|
||||
import processPlugins from '../src/util/processPlugins'
|
||||
|
||||
function css(nodes) {
|
||||
return postcss.root({ nodes }).toString()
|
||||
return _postcss.root({ nodes }).toString()
|
||||
}
|
||||
|
||||
function makeConfig(overrides) {
|
||||
|
|
@ -95,7 +95,7 @@ test('plugins can create utilities with arrays of objects', () => {
|
|||
test('plugins can create utilities with raw PostCSS nodes', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
function({ addUtilities }) {
|
||||
function({ addUtilities, postcss }) {
|
||||
addUtilities([
|
||||
postcss.rule({ selector: '.object-fill' }).append([
|
||||
postcss.decl({
|
||||
|
|
@ -140,7 +140,7 @@ test('plugins can create utilities with raw PostCSS nodes', () => {
|
|||
test('plugins can create utilities with mixed object styles and PostCSS nodes', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
function({ addUtilities }) {
|
||||
function({ addUtilities, postcss }) {
|
||||
addUtilities([
|
||||
{
|
||||
'.object-fill': {
|
||||
|
|
@ -254,10 +254,70 @@ test('plugins can create components with object syntax', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
test('plugins can add base styles with object syntax', () => {
|
||||
const { base } = processPlugins(
|
||||
[
|
||||
function({ addBase }) {
|
||||
addBase({
|
||||
img: {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
button: {
|
||||
fontFamily: 'inherit',
|
||||
},
|
||||
})
|
||||
},
|
||||
],
|
||||
makeConfig()
|
||||
)
|
||||
|
||||
expect(css(base)).toMatchCss(`
|
||||
img {
|
||||
max-width: 100%
|
||||
}
|
||||
button {
|
||||
font-family: inherit
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
test('plugins can add base styles with raw PostCSS nodes', () => {
|
||||
const { base } = processPlugins(
|
||||
[
|
||||
function({ addBase, postcss }) {
|
||||
addBase([
|
||||
postcss.rule({ selector: 'img' }).append([
|
||||
postcss.decl({
|
||||
prop: 'max-width',
|
||||
value: '100%',
|
||||
}),
|
||||
]),
|
||||
postcss.rule({ selector: 'button' }).append([
|
||||
postcss.decl({
|
||||
prop: 'font-family',
|
||||
value: 'inherit',
|
||||
}),
|
||||
]),
|
||||
])
|
||||
},
|
||||
],
|
||||
makeConfig()
|
||||
)
|
||||
|
||||
expect(css(base)).toMatchCss(`
|
||||
img {
|
||||
max-width: 100%
|
||||
}
|
||||
button {
|
||||
font-family: inherit
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
test('plugins can create components with raw PostCSS nodes', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
function({ addComponents }) {
|
||||
function({ addComponents, postcss }) {
|
||||
addComponents([
|
||||
postcss.rule({ selector: '.btn-blue' }).append([
|
||||
postcss.decl({
|
||||
|
|
@ -306,7 +366,7 @@ test('plugins can create components with raw PostCSS nodes', () => {
|
|||
test('plugins can create components with mixed object styles and raw PostCSS nodes', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
function({ addComponents }) {
|
||||
function({ addComponents, postcss }) {
|
||||
addComponents([
|
||||
postcss.rule({ selector: '.btn-blue' }).append([
|
||||
postcss.decl({
|
||||
|
|
@ -597,6 +657,91 @@ test('plugins can access the current config', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
test('plugins can access the variants config directly', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
function({ addUtilities, variants }) {
|
||||
addUtilities(
|
||||
{
|
||||
'.object-fill': {
|
||||
'object-fit': 'fill',
|
||||
},
|
||||
'.object-contain': {
|
||||
'object-fit': 'contain',
|
||||
},
|
||||
'.object-cover': {
|
||||
'object-fit': 'cover',
|
||||
},
|
||||
},
|
||||
variants('objectFit')
|
||||
)
|
||||
},
|
||||
],
|
||||
makeConfig({
|
||||
variants: {
|
||||
objectFit: ['responsive', 'focus', 'hover'],
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(components.length).toBe(0)
|
||||
expect(css(utilities)).toMatchCss(`
|
||||
@variants responsive, focus, hover {
|
||||
.object-fill {
|
||||
object-fit: fill
|
||||
}
|
||||
.object-contain {
|
||||
object-fit: contain
|
||||
}
|
||||
.object-cover {
|
||||
object-fit: cover
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
test('plugins apply all global variants when variants are configured globally', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
function({ addUtilities, variants }) {
|
||||
addUtilities(
|
||||
{
|
||||
'.object-fill': {
|
||||
'object-fit': 'fill',
|
||||
},
|
||||
},
|
||||
variants('objectFit')
|
||||
)
|
||||
addUtilities(
|
||||
{
|
||||
'.rotate-90deg': {
|
||||
transform: 'rotate(90deg)',
|
||||
},
|
||||
},
|
||||
variants('rotate')
|
||||
)
|
||||
},
|
||||
],
|
||||
makeConfig({
|
||||
variants: ['responsive', 'focus', 'hover'],
|
||||
})
|
||||
)
|
||||
|
||||
expect(components.length).toBe(0)
|
||||
expect(css(utilities)).toMatchCss(`
|
||||
@variants responsive, focus, hover {
|
||||
.object-fill {
|
||||
object-fit: fill
|
||||
}
|
||||
}
|
||||
@variants responsive, focus, hover {
|
||||
.rotate-90deg {
|
||||
transform: rotate(90deg)
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
test('plugins can provide fallbacks to keys missing from the config', () => {
|
||||
const { components, utilities } = processPlugins(
|
||||
[
|
||||
|
|
|
|||
946
__tests__/resolveConfig.test.js
Normal file
946
__tests__/resolveConfig.test.js
Normal file
|
|
@ -0,0 +1,946 @@
|
|||
import resolveConfig from '../src/util/resolveConfig'
|
||||
|
||||
test('prefix key overrides default prefix', () => {
|
||||
const userConfig = {
|
||||
prefix: 'tw-',
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: 'tw-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('important key overrides default important', () => {
|
||||
const userConfig = {
|
||||
important: true,
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '',
|
||||
important: true,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('separator key overrides default separator', () => {
|
||||
const userConfig = {
|
||||
separator: '__',
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: '__',
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme key is merged instead of replaced', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('variants key is merged instead of replaced', () => {
|
||||
const userConfig = {
|
||||
variants: {
|
||||
backgroundAttachment: [],
|
||||
borderColors: ['responsive', 'hover', 'focus', 'active'],
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
borderRadius: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
},
|
||||
fonts: {
|
||||
sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],
|
||||
serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],
|
||||
},
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: [],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus', 'active'],
|
||||
borderRadius: ['responsive'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('missing top level keys are pulled from the default config', () => {
|
||||
const userConfig = {}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: { green: '#00ff00' },
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: { green: '#00ff00' },
|
||||
screens: {
|
||||
mobile: '400px',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
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: theme => theme('colors'),
|
||||
textColors: theme => theme('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: theme => ({
|
||||
...theme('colors'),
|
||||
customBackground: '#bada55',
|
||||
}),
|
||||
textColors: theme => ({
|
||||
...theme('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'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme values in the extend section extend the existing theme', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
extend: {
|
||||
opacity: {
|
||||
'25': '25',
|
||||
'75': '.75',
|
||||
},
|
||||
backgroundColors: {
|
||||
customBackground: '#bada55',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
},
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'50': '.5',
|
||||
'100': '1',
|
||||
},
|
||||
backgroundColors: theme => theme('colors'),
|
||||
},
|
||||
variants: {
|
||||
backgroundColors: ['responsive', 'hover', 'focus'],
|
||||
opacity: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
},
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'50': '.5',
|
||||
'100': '1',
|
||||
'25': '25',
|
||||
'75': '.75',
|
||||
},
|
||||
backgroundColors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
customBackground: '#bada55',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColors: ['responsive', 'hover', 'focus'],
|
||||
opacity: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme values in the extend section extend the user theme', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'20': '.2',
|
||||
'40': '.4',
|
||||
},
|
||||
height: theme => theme('width'),
|
||||
extend: {
|
||||
opacity: {
|
||||
'60': '.6',
|
||||
'80': '.8',
|
||||
'100': '1',
|
||||
},
|
||||
height: {
|
||||
customHeight: '500vh',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'50': '.5',
|
||||
'100': '1',
|
||||
},
|
||||
height: {
|
||||
'0': 0,
|
||||
full: '100%',
|
||||
},
|
||||
width: {
|
||||
'0': 0,
|
||||
'1': '.25rem',
|
||||
'2': '.5rem',
|
||||
'3': '.75rem',
|
||||
'4': '1rem',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
opacity: ['responsive', 'hover', 'focus'],
|
||||
height: ['responsive'],
|
||||
width: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'20': '.2',
|
||||
'40': '.4',
|
||||
'60': '.6',
|
||||
'80': '.8',
|
||||
'100': '1',
|
||||
},
|
||||
height: {
|
||||
'0': 0,
|
||||
'1': '.25rem',
|
||||
'2': '.5rem',
|
||||
'3': '.75rem',
|
||||
'4': '1rem',
|
||||
customHeight: '500vh',
|
||||
},
|
||||
width: {
|
||||
'0': 0,
|
||||
'1': '.25rem',
|
||||
'2': '.5rem',
|
||||
'3': '.75rem',
|
||||
'4': '1rem',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
opacity: ['responsive', 'hover', 'focus'],
|
||||
height: ['responsive'],
|
||||
width: ['responsive'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme values in the extend section can extend values that are depended on lazily', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
backgroundColors: {
|
||||
customBackground: '#bada55',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
},
|
||||
backgroundColors: theme => theme('colors'),
|
||||
},
|
||||
variants: {
|
||||
backgroundColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
backgroundColors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
customBackground: '#bada55',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColors: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme values in the extend section are not deeply merged', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
extend: {
|
||||
fonts: {
|
||||
sans: ['Comic Sans'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
fonts: {
|
||||
sans: ['system-ui', 'Helvetica Neue', 'sans-serif'],
|
||||
serif: ['Constantia', 'Georgia', 'serif'],
|
||||
mono: ['Menlo', 'Courier New', 'monospace'],
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
fonts: ['responsive'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
fonts: {
|
||||
sans: ['Comic Sans'],
|
||||
serif: ['Constantia', 'Georgia', 'serif'],
|
||||
mono: ['Menlo', 'Courier New', 'monospace'],
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
fonts: ['responsive'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('the theme function can use a default value if the key is missing', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
},
|
||||
borderColor: theme => ({
|
||||
default: theme('colors.gray', 'currentColor'),
|
||||
...theme('colors'),
|
||||
}),
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
borderColor: {
|
||||
default: 'currentColor',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('the theme function can resolve function values', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
textColor: theme => ({
|
||||
lime: 'lime',
|
||||
...theme('colors'),
|
||||
}),
|
||||
backgroundColor: theme => ({
|
||||
orange: 'orange',
|
||||
...theme('textColor'),
|
||||
}),
|
||||
borderColor: theme => theme('backgroundColor'),
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColor: ['responsive', 'hover', 'focus'],
|
||||
borderColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
textColor: {
|
||||
lime: 'lime',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
backgroundColor: {
|
||||
lime: 'lime',
|
||||
orange: 'orange',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
borderColor: {
|
||||
lime: 'lime',
|
||||
orange: 'orange',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColor: ['responsive', 'hover', 'focus'],
|
||||
borderColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('theme values in the extend section are lazily evaluated', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
orange: 'orange',
|
||||
},
|
||||
borderColor: theme => ({
|
||||
foo: theme('colors.orange'),
|
||||
bar: theme('colors.red'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
},
|
||||
borderColor: theme => ({
|
||||
default: theme('colors.yellow', 'currentColor'),
|
||||
...theme('colors'),
|
||||
}),
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
orange: 'orange',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
borderColor: {
|
||||
default: 'currentColor',
|
||||
foo: 'orange',
|
||||
bar: 'red',
|
||||
orange: 'orange',
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('the original theme is not mutated', () => {
|
||||
const userConfig = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
orange: 'orange',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive', 'hover'],
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
colors: {
|
||||
cyan: 'cyan',
|
||||
magenta: 'magenta',
|
||||
yellow: 'yellow',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
resolveConfig([userConfig, defaultConfig])
|
||||
|
||||
expect(userConfig).toEqual({
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
orange: 'orange',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
borderColor: ['responsive', 'hover'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import postcss from 'postcss'
|
||||
import plugin from '../src/lib/substituteResponsiveAtRules'
|
||||
import config from '../defaultConfig.stub.js'
|
||||
import config from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
function run(input, opts = config) {
|
||||
return postcss([plugin(opts)]).process(input, { from: undefined })
|
||||
|
|
@ -172,6 +172,136 @@ test('responsive variants are grouped', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test('it can generate responsive variants for nested at-rules', () => {
|
||||
const input = `
|
||||
@responsive {
|
||||
.banana { color: yellow; }
|
||||
|
||||
@supports(display: grid) {
|
||||
.grid\\:banana { color: blue; }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.banana {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@supports(display: grid) {
|
||||
.grid\\:banana {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
.sm\\:banana {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@supports(display: grid) {
|
||||
.sm\\:grid\\:banana {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
.lg\\:banana {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@supports(display: grid) {
|
||||
.lg\\:grid\\:banana {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '500px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
separator: ':',
|
||||
}).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('it can generate responsive variants for deeply nested at-rules', () => {
|
||||
const input = `
|
||||
@responsive {
|
||||
.banana { color: yellow; }
|
||||
|
||||
@supports(display: grid) {
|
||||
@supports(display: flex) {
|
||||
.flex-grid\\:banana { color: blue; }
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.banana {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@supports(display: grid) {
|
||||
@supports(display: flex) {
|
||||
.flex-grid\\:banana {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
.sm\\:banana {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@supports(display: grid) {
|
||||
@supports(display: flex) {
|
||||
.sm\\:flex-grid\\:banana {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
.lg\\:banana {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@supports(display: grid) {
|
||||
@supports(display: flex) {
|
||||
.lg\\:flex-grid\\:banana {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '500px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
separator: ':',
|
||||
}).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('screen prefix is only applied to the last class in a selector', () => {
|
||||
const input = `
|
||||
@responsive {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import fs from 'fs'
|
|||
import path from 'path'
|
||||
import postcss from 'postcss'
|
||||
import tailwind from '../src/index'
|
||||
import config from '../defaultConfig.js'
|
||||
import config from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
it('generates the right CSS', () => {
|
||||
const inputPath = path.resolve(`${__dirname}/fixtures/tailwind-input.css`)
|
||||
|
|
|
|||
47
__tests__/screenAtRule.test.js
Normal file
47
__tests__/screenAtRule.test.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import postcss from 'postcss'
|
||||
import plugin from '../src/lib/substituteScreenAtRules'
|
||||
import config from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
function run(input, opts = config) {
|
||||
return postcss([plugin(opts)]).process(input, { from: undefined })
|
||||
}
|
||||
|
||||
test('it can generate media queries from configured screen sizes', () => {
|
||||
const input = `
|
||||
@screen sm {
|
||||
.banana { color: yellow; }
|
||||
}
|
||||
@screen md {
|
||||
.banana { color: red; }
|
||||
}
|
||||
@screen lg {
|
||||
.banana { color: green; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
@media (min-width: 500px) {
|
||||
.banana { color: yellow; }
|
||||
}
|
||||
@media (min-width: 750px) {
|
||||
.banana { color: red; }
|
||||
}
|
||||
@media (min-width: 1000px) {
|
||||
.banana { color: green; }
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '500px',
|
||||
md: '750px',
|
||||
lg: '1000px',
|
||||
},
|
||||
},
|
||||
separator: ':',
|
||||
}).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
|
@ -5,9 +5,9 @@ function run(input, opts = {}) {
|
|||
return postcss([plugin(opts)]).process(input, { from: undefined })
|
||||
}
|
||||
|
||||
test('it looks up values in the config using dot notation', () => {
|
||||
test('it looks up values in the theme using dot notation', () => {
|
||||
const input = `
|
||||
.banana { color: config('theme.colors.yellow'); }
|
||||
.banana { color: theme('colors.yellow'); }
|
||||
`
|
||||
|
||||
const output = `
|
||||
|
|
@ -28,7 +28,7 @@ test('it looks up values in the config using dot notation', () => {
|
|||
|
||||
test('quotes are optional around the lookup path', () => {
|
||||
const input = `
|
||||
.banana { color: config(theme.colors.yellow); }
|
||||
.banana { color: theme(colors.yellow); }
|
||||
`
|
||||
|
||||
const output = `
|
||||
|
|
@ -49,7 +49,7 @@ test('quotes are optional around the lookup path', () => {
|
|||
|
||||
test('a default value can be provided', () => {
|
||||
const input = `
|
||||
.cookieMonster { color: config('theme.colors.blue', #0000ff); }
|
||||
.cookieMonster { color: theme('colors.blue', #0000ff); }
|
||||
`
|
||||
|
||||
const output = `
|
||||
|
|
@ -70,7 +70,7 @@ test('a default value can be provided', () => {
|
|||
|
||||
test('quotes are preserved around default values', () => {
|
||||
const input = `
|
||||
.heading { font-family: config('theme.fonts.sans', "Helvetica Neue"); }
|
||||
.heading { font-family: theme('fonts.sans', "Helvetica Neue"); }
|
||||
`
|
||||
|
||||
const output = `
|
||||
|
|
@ -88,3 +88,24 @@ test('quotes are preserved around default values', () => {
|
|||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('an unquoted list is valid as a default value', () => {
|
||||
const input = `
|
||||
.heading { font-family: theme('fonts.sans', Helvetica, Arial, sans-serif); }
|
||||
`
|
||||
|
||||
const output = `
|
||||
.heading { font-family: Helvetica, Arial, sans-serif; }
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
theme: {
|
||||
fonts: {
|
||||
serif: 'Constantia',
|
||||
},
|
||||
},
|
||||
}).then(result => {
|
||||
expect(result.css).toEqual(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import postcss from 'postcss'
|
||||
import plugin from '../src/lib/substituteVariantsAtRules'
|
||||
import config from '../defaultConfig.stub.js'
|
||||
import processPlugins from '../src/util/processPlugins'
|
||||
import config from '../stubs/defaultConfig.stub.js'
|
||||
|
||||
function run(input, opts = config) {
|
||||
return postcss([plugin(opts, processPlugins(opts.plugins, opts))]).process(input, {
|
||||
|
|
@ -218,6 +218,33 @@ test('variants are generated in the order specified', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test('the default variant can be generated in a specified position', () => {
|
||||
const input = `
|
||||
@variants focus, active, default, hover {
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.focus\\:banana:focus { color: yellow; }
|
||||
.focus\\:chocolate:focus { color: brown; }
|
||||
.active\\:banana:active { color: yellow; }
|
||||
.active\\:chocolate:active { color: brown; }
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
.hover\\:banana:hover { color: yellow; }
|
||||
.hover\\:chocolate:hover { color: brown; }
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
...config,
|
||||
}).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('plugin variants can modify rules using the raw PostCSS API', () => {
|
||||
const input = `
|
||||
@variants important {
|
||||
|
|
@ -273,10 +300,43 @@ test('plugin variants can modify selectors with a simplified API', () => {
|
|||
...config,
|
||||
plugins: [
|
||||
...config.plugins,
|
||||
function({ addVariant }) {
|
||||
function({ addVariant, e }) {
|
||||
addVariant('first-child', ({ modifySelectors, separator }) => {
|
||||
modifySelectors(({ className }) => {
|
||||
return `.first-child${separator}${className}:first-child`
|
||||
return `.${e(`first-child${separator}${className}`)}:first-child`
|
||||
})
|
||||
})
|
||||
},
|
||||
],
|
||||
}).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('plugin variants that use modify selectors need to manually escape the class name they are modifying', () => {
|
||||
const input = `
|
||||
@variants first-child {
|
||||
.banana-1\\/2 { color: yellow; }
|
||||
.chocolate-1\\.5 { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.banana-1\\/2 { color: yellow; }
|
||||
.chocolate-1\\.5 { color: brown; }
|
||||
.first-child\\:banana-1\\/2:first-child { color: yellow; }
|
||||
.first-child\\:chocolate-1\\.5:first-child { color: brown; }
|
||||
`
|
||||
|
||||
return run(input, {
|
||||
...config,
|
||||
plugins: [
|
||||
...config.plugins,
|
||||
function({ addVariant, e }) {
|
||||
addVariant('first-child', ({ modifySelectors, separator }) => {
|
||||
modifySelectors(({ className }) => {
|
||||
return `.${e(`first-child${separator}${className}`)}:first-child`
|
||||
})
|
||||
})
|
||||
},
|
||||
|
|
@ -308,13 +368,13 @@ test('plugin variants can wrap rules in another at-rule using the raw PostCSS AP
|
|||
...config,
|
||||
plugins: [
|
||||
...config.plugins,
|
||||
function({ addVariant }) {
|
||||
function({ addVariant, e }) {
|
||||
addVariant('supports-grid', ({ container, separator }) => {
|
||||
const supportsRule = postcss.atRule({ name: 'supports', params: '(display: grid)' })
|
||||
supportsRule.nodes = container.nodes
|
||||
container.nodes = [supportsRule]
|
||||
supportsRule.walkRules(rule => {
|
||||
rule.selector = `.supports-grid${separator}${rule.selector.slice(1)}`
|
||||
rule.selector = `.${e(`supports-grid${separator}${rule.selector.slice(1)}`)}`
|
||||
})
|
||||
})
|
||||
},
|
||||
|
|
|
|||
1
base.css
Normal file
1
base.css
Normal file
|
|
@ -0,0 +1 @@
|
|||
@tailwind base;
|
||||
|
|
@ -1,475 +0,0 @@
|
|||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the `main` element consistently in IE.
|
||||
*/
|
||||
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background on active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57-
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers.
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE 10+.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10.
|
||||
* 2. Remove the padding in IE 10.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||
*/
|
||||
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Misc
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10+.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually forked from SUIT CSS Base: https://github.com/suitcss/base
|
||||
* A thin layer on top of normalize.css that provides a starting point more
|
||||
* suitable for web applications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1. Prevent padding and border from affecting element width
|
||||
* https://goo.gl/pYtbK7
|
||||
* 2. Change the default font family in all browsers (opinionated)
|
||||
*/
|
||||
|
||||
html {
|
||||
box-sizing: border-box; /* 1 */
|
||||
font-family: sans-serif; /* 2 */
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the default spacing and border for appropriate elements.
|
||||
*/
|
||||
|
||||
blockquote,
|
||||
dl,
|
||||
dd,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
figure,
|
||||
p,
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work around a Firefox/IE bug where the transparent `button` background
|
||||
* results in a loss of the default `button` focus styles.
|
||||
*/
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tailwind custom reset styles
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allow adding a border to an element by just adding a border-width.
|
||||
*
|
||||
* By default, the way the browser specifies that an element should have no
|
||||
* border is by setting it's border-style to `none` in the user-agent
|
||||
* stylesheet.
|
||||
*
|
||||
* In order to easily add borders to elements by just setting the `border-width`
|
||||
* property, we change the default border-style for all elements to `solid`, and
|
||||
* use border-width to hide them instead. This way our `border` utilities only
|
||||
* need to set the `border-width` property instead of the entire `border`
|
||||
* shorthand, making our border utilities much more straightforward to compose.
|
||||
*
|
||||
* https://github.com/tailwindcss/tailwindcss/pull/116
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
border-color: config('theme.borderColors.default', currentColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the `border-style: none` reset that Normalize applies to images so that
|
||||
* our `border-{width}` utilities have the expected effect.
|
||||
*
|
||||
* The Normalize reset is unnecessary for us since we default the border-width
|
||||
* to 0 on all elements.
|
||||
*
|
||||
* https://github.com/tailwindcss/tailwindcss/issues/362
|
||||
*/
|
||||
img {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
color: inherit;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
button,
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
module.exports = function() {
|
||||
return require('lodash').cloneDeep(require('./defaultConfig.stub.js'))
|
||||
}
|
||||
const cloneDeep = require('lodash/cloneDeep')
|
||||
const defaultConfig = require('./stubs/defaultConfig.stub.js')
|
||||
|
||||
module.exports = cloneDeep(defaultConfig)
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
const defaultTheme = require('./defaultTheme')()
|
||||
|
||||
module.exports = {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: defaultTheme,
|
||||
variants: {
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: ['responsive'],
|
||||
backgroundColors: ['responsive', 'hover', 'focus'],
|
||||
backgroundPosition: ['responsive'],
|
||||
backgroundRepeat: ['responsive'],
|
||||
backgroundSize: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
borderRadius: ['responsive'],
|
||||
borderStyle: ['responsive'],
|
||||
borderWidths: ['responsive'],
|
||||
cursor: ['responsive'],
|
||||
display: ['responsive'],
|
||||
flexbox: ['responsive'],
|
||||
float: ['responsive'],
|
||||
fonts: ['responsive'],
|
||||
fontWeights: ['responsive', 'hover', 'focus'],
|
||||
height: ['responsive'],
|
||||
leading: ['responsive'],
|
||||
lists: ['responsive'],
|
||||
margin: ['responsive'],
|
||||
maxHeight: ['responsive'],
|
||||
maxWidth: ['responsive'],
|
||||
minHeight: ['responsive'],
|
||||
minWidth: ['responsive'],
|
||||
negativeMargin: ['responsive'],
|
||||
objectFit: [],
|
||||
objectPosition: [],
|
||||
opacity: ['responsive'],
|
||||
outline: ['focus'],
|
||||
overflow: ['responsive'],
|
||||
padding: ['responsive'],
|
||||
pointerEvents: ['responsive'],
|
||||
position: ['responsive'],
|
||||
resize: ['responsive'],
|
||||
shadows: ['responsive', 'hover', 'focus'],
|
||||
svgFill: [],
|
||||
svgStroke: [],
|
||||
tableLayout: ['responsive'],
|
||||
textAlign: ['responsive'],
|
||||
textColors: ['responsive', 'hover', 'focus'],
|
||||
textSizes: ['responsive'],
|
||||
textStyle: ['responsive', 'hover', 'focus'],
|
||||
tracking: ['responsive'],
|
||||
userSelect: ['responsive'],
|
||||
verticalAlign: ['responsive'],
|
||||
visibility: ['responsive'],
|
||||
whitespace: ['responsive'],
|
||||
width: ['responsive'],
|
||||
zIndex: ['responsive'],
|
||||
},
|
||||
corePlugins: {
|
||||
objectFit: false,
|
||||
objectPosition: false,
|
||||
},
|
||||
plugins: [
|
||||
require('./plugins/container')({
|
||||
// center: true,
|
||||
// padding: '1rem',
|
||||
}),
|
||||
],
|
||||
}
|
||||
356
defaultTheme.js
356
defaultTheme.js
|
|
@ -1,354 +1,4 @@
|
|||
module.exports = function() {
|
||||
const colors = {
|
||||
transparent: 'transparent',
|
||||
const cloneDeep = require('lodash/cloneDeep')
|
||||
const defaultConfig = require('./stubs/defaultConfig.stub.js')
|
||||
|
||||
black: '#22292f',
|
||||
'grey-darkest': '#3d4852',
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
grey: '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
'grey-lightest': '#f8fafc',
|
||||
white: '#ffffff',
|
||||
|
||||
'red-darkest': '#3b0d0c',
|
||||
'red-darker': '#621b18',
|
||||
'red-dark': '#cc1f1a',
|
||||
red: '#e3342f',
|
||||
'red-light': '#ef5753',
|
||||
'red-lighter': '#f9acaa',
|
||||
'red-lightest': '#fcebea',
|
||||
|
||||
'orange-darkest': '#462a16',
|
||||
'orange-darker': '#613b1f',
|
||||
'orange-dark': '#de751f',
|
||||
orange: '#f6993f',
|
||||
'orange-light': '#faad63',
|
||||
'orange-lighter': '#fcd9b6',
|
||||
'orange-lightest': '#fff5eb',
|
||||
|
||||
'yellow-darkest': '#453411',
|
||||
'yellow-darker': '#684f1d',
|
||||
'yellow-dark': '#f2d024',
|
||||
yellow: '#ffed4a',
|
||||
'yellow-light': '#fff382',
|
||||
'yellow-lighter': '#fff9c2',
|
||||
'yellow-lightest': '#fcfbeb',
|
||||
|
||||
'green-darkest': '#0f2f21',
|
||||
'green-darker': '#1a4731',
|
||||
'green-dark': '#1f9d55',
|
||||
green: '#38c172',
|
||||
'green-light': '#51d88a',
|
||||
'green-lighter': '#a2f5bf',
|
||||
'green-lightest': '#e3fcec',
|
||||
|
||||
'teal-darkest': '#0d3331',
|
||||
'teal-darker': '#20504f',
|
||||
'teal-dark': '#38a89d',
|
||||
teal: '#4dc0b5',
|
||||
'teal-light': '#64d5ca',
|
||||
'teal-lighter': '#a0f0ed',
|
||||
'teal-lightest': '#e8fffe',
|
||||
|
||||
'blue-darkest': '#12283a',
|
||||
'blue-darker': '#1c3d5a',
|
||||
'blue-dark': '#2779bd',
|
||||
blue: '#3490dc',
|
||||
'blue-light': '#6cb2eb',
|
||||
'blue-lighter': '#bcdefa',
|
||||
'blue-lightest': '#eff8ff',
|
||||
|
||||
'indigo-darkest': '#191e38',
|
||||
'indigo-darker': '#2f365f',
|
||||
'indigo-dark': '#5661b3',
|
||||
indigo: '#6574cd',
|
||||
'indigo-light': '#7886d7',
|
||||
'indigo-lighter': '#b2b7ff',
|
||||
'indigo-lightest': '#e6e8ff',
|
||||
|
||||
'purple-darkest': '#21183c',
|
||||
'purple-darker': '#382b5f',
|
||||
'purple-dark': '#794acf',
|
||||
purple: '#9561e2',
|
||||
'purple-light': '#a779e9',
|
||||
'purple-lighter': '#d6bbfc',
|
||||
'purple-lightest': '#f3ebff',
|
||||
|
||||
'pink-darkest': '#451225',
|
||||
'pink-darker': '#6f213f',
|
||||
'pink-dark': '#eb5286',
|
||||
pink: '#f66d9b',
|
||||
'pink-light': '#fa7ea8',
|
||||
'pink-lighter': '#ffbbca',
|
||||
'pink-lightest': '#ffebef',
|
||||
}
|
||||
|
||||
return {
|
||||
colors,
|
||||
screens: {
|
||||
sm: '576px',
|
||||
md: '768px',
|
||||
lg: '992px',
|
||||
xl: '1200px',
|
||||
},
|
||||
fonts: {
|
||||
sans: [
|
||||
'system-ui',
|
||||
'BlinkMacSystemFont',
|
||||
'-apple-system',
|
||||
'Segoe UI',
|
||||
'Roboto',
|
||||
'Oxygen',
|
||||
'Ubuntu',
|
||||
'Cantarell',
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
'sans-serif',
|
||||
],
|
||||
serif: [
|
||||
'Constantia',
|
||||
'Lucida Bright',
|
||||
'Lucidabright',
|
||||
'Lucida Serif',
|
||||
'Lucida',
|
||||
'DejaVu Serif',
|
||||
'Bitstream Vera Serif',
|
||||
'Liberation Serif',
|
||||
'Georgia',
|
||||
'serif',
|
||||
],
|
||||
mono: ['Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace'],
|
||||
},
|
||||
textSizes: {
|
||||
xs: '.75rem', // 12px
|
||||
sm: '.875rem', // 14px
|
||||
base: '1rem', // 16px
|
||||
lg: '1.125rem', // 18px
|
||||
xl: '1.25rem', // 20px
|
||||
'2xl': '1.5rem', // 24px
|
||||
'3xl': '1.875rem', // 30px
|
||||
'4xl': '2.25rem', // 36px
|
||||
'5xl': '3rem', // 48px
|
||||
},
|
||||
fontWeights: {
|
||||
hairline: 100,
|
||||
thin: 200,
|
||||
light: 300,
|
||||
normal: 400,
|
||||
medium: 500,
|
||||
semibold: 600,
|
||||
bold: 700,
|
||||
extrabold: 800,
|
||||
black: 900,
|
||||
},
|
||||
leading: {
|
||||
none: 1,
|
||||
tight: 1.25,
|
||||
normal: 1.5,
|
||||
loose: 2,
|
||||
},
|
||||
tracking: {
|
||||
tight: '-0.05em',
|
||||
normal: '0',
|
||||
wide: '0.05em',
|
||||
},
|
||||
textColors: colors,
|
||||
backgroundColors: colors,
|
||||
backgroundSize: {
|
||||
auto: 'auto',
|
||||
cover: 'cover',
|
||||
contain: 'contain',
|
||||
},
|
||||
borderWidths: {
|
||||
default: '1px',
|
||||
'0': '0',
|
||||
'2': '2px',
|
||||
'4': '4px',
|
||||
'8': '8px',
|
||||
},
|
||||
borderColors: global.Object.assign({ default: colors['grey-light'] }, colors),
|
||||
borderRadius: {
|
||||
none: '0',
|
||||
sm: '.125rem',
|
||||
default: '.25rem',
|
||||
lg: '.5rem',
|
||||
full: '9999px',
|
||||
},
|
||||
width: {
|
||||
auto: 'auto',
|
||||
px: '1px',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
'48': '12rem',
|
||||
'64': '16rem',
|
||||
'1/2': '50%',
|
||||
'1/3': '33.33333%',
|
||||
'2/3': '66.66667%',
|
||||
'1/4': '25%',
|
||||
'2/4': '50%',
|
||||
'3/4': '75%',
|
||||
'1/5': '20%',
|
||||
'2/5': '40%',
|
||||
'3/5': '60%',
|
||||
'4/5': '80%',
|
||||
'1/6': '16.66667%',
|
||||
'2/6': '33.33333%',
|
||||
'3/6': '50%',
|
||||
'4/6': '66.66667%',
|
||||
'5/6': '83.33333%',
|
||||
'1/12': '8.33333%',
|
||||
'2/12': '16.66667%',
|
||||
'3/12': '25%',
|
||||
'4/12': '33.33333%',
|
||||
'5/12': '41.66667%',
|
||||
'6/12': '50%',
|
||||
'7/12': '58.33333%',
|
||||
'8/12': '66.66667%',
|
||||
'9/12': '75%',
|
||||
'10/12': '83.33333%',
|
||||
'11/12': '91.66667%',
|
||||
full: '100%',
|
||||
screen: '100vw',
|
||||
},
|
||||
height: {
|
||||
auto: 'auto',
|
||||
px: '1px',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
'48': '12rem',
|
||||
'64': '16rem',
|
||||
full: '100%',
|
||||
screen: '100vh',
|
||||
},
|
||||
minWidth: {
|
||||
'0': '0',
|
||||
full: '100%',
|
||||
},
|
||||
minHeight: {
|
||||
'0': '0',
|
||||
full: '100%',
|
||||
screen: '100vh',
|
||||
},
|
||||
maxWidth: {
|
||||
xs: '20rem',
|
||||
sm: '30rem',
|
||||
md: '40rem',
|
||||
lg: '50rem',
|
||||
xl: '60rem',
|
||||
'2xl': '70rem',
|
||||
'3xl': '80rem',
|
||||
'4xl': '90rem',
|
||||
'5xl': '100rem',
|
||||
full: '100%',
|
||||
},
|
||||
maxHeight: {
|
||||
full: '100%',
|
||||
screen: '100vh',
|
||||
},
|
||||
padding: {
|
||||
px: '1px',
|
||||
'0': '0',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'20': '5rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
},
|
||||
margin: {
|
||||
auto: 'auto',
|
||||
px: '1px',
|
||||
'0': '0',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'20': '5rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
},
|
||||
negativeMargin: {
|
||||
px: '1px',
|
||||
'0': '0',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'20': '5rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
},
|
||||
shadows: {
|
||||
default: '0 2px 4px 0 rgba(0,0,0,0.10)',
|
||||
md: '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)',
|
||||
lg: '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)',
|
||||
inner: 'inset 0 2px 4px 0 rgba(0,0,0,0.06)',
|
||||
outline: '0 0 0 3px rgba(52,144,220,0.5)',
|
||||
none: 'none',
|
||||
},
|
||||
zIndex: {
|
||||
auto: 'auto',
|
||||
'0': 0,
|
||||
'10': 10,
|
||||
'20': 20,
|
||||
'30': 30,
|
||||
'40': 40,
|
||||
'50': 50,
|
||||
},
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'25': '.25',
|
||||
'50': '.5',
|
||||
'75': '.75',
|
||||
'100': '1',
|
||||
},
|
||||
svgFill: {
|
||||
current: 'currentColor',
|
||||
},
|
||||
svgStroke: {
|
||||
current: 'currentColor',
|
||||
},
|
||||
}
|
||||
}
|
||||
module.exports = cloneDeep(defaultConfig.theme)
|
||||
|
|
|
|||
21
jest/runInTempDirectory.js
Normal file
21
jest/runInTempDirectory.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import rimraf from 'rimraf'
|
||||
|
||||
const tmpPath = path.resolve(__dirname, '../__tmp')
|
||||
|
||||
export default function(callback) {
|
||||
return new Promise(resolve => {
|
||||
const currentPath = process.cwd()
|
||||
|
||||
rimraf.sync(tmpPath)
|
||||
fs.mkdirSync(tmpPath)
|
||||
process.chdir(tmpPath)
|
||||
|
||||
callback().then(() => {
|
||||
process.chdir(currentPath)
|
||||
rimraf(tmpPath, resolve)
|
||||
})
|
||||
})
|
||||
}
|
||||
7729
package-lock.json
generated
7729
package-lock.json
generated
File diff suppressed because it is too large
Load diff
53
package.json
53
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tailwindcss",
|
||||
"version": "0.7.3",
|
||||
"version": "1.0.0-beta.5",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
|
|
@ -18,44 +18,40 @@
|
|||
],
|
||||
"scripts": {
|
||||
"prebabelify": "rimraf lib",
|
||||
"babelify": "babel src --out-dir lib",
|
||||
"babelify": "babel src --out-dir lib --copy-files",
|
||||
"prepare": "npm run babelify && babel-node src/build.js",
|
||||
"style": "eslint .",
|
||||
"test": "jest && eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.6.5",
|
||||
"babel-core": "^6.7.2",
|
||||
"babel-jest": "^20.0.3",
|
||||
"babel-preset-env": "^1.0.0",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"@babel/cli": "^7.0.0",
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/node": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"babel-jest": "^24.3.1",
|
||||
"clean-css": "^4.1.9",
|
||||
"eslint": "^4.10.0",
|
||||
"eslint": "^5.15.1",
|
||||
"eslint-config-postcss": "^2.0.2",
|
||||
"eslint-config-prettier": "^2.7.0",
|
||||
"eslint-plugin-prettier": "^2.3.1",
|
||||
"jest": "^23.6.0",
|
||||
"eslint-config-prettier": "^4.1.0",
|
||||
"eslint-plugin-prettier": "^3.0.1",
|
||||
"jest": "^24.3.1",
|
||||
"prettier": "^1.7.4",
|
||||
"rimraf": "^2.6.1"
|
||||
"rimraf": "^2.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"autoprefixer": "^9.4.5",
|
||||
"bytes": "^3.0.0",
|
||||
"chalk": "^2.4.1",
|
||||
"css.escape": "^1.5.1",
|
||||
"fs-extra": "^4.0.2",
|
||||
"lodash": "^4.17.5",
|
||||
"fs-extra": "^7.0.1",
|
||||
"lodash": "^4.17.11",
|
||||
"node-emoji": "^1.8.1",
|
||||
"perfectionist": "^2.4.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"postcss": "^7.0.11",
|
||||
"postcss-functions": "^3.0.0",
|
||||
"postcss-js": "^2.0.0",
|
||||
"postcss-nested": "^4.1.1",
|
||||
"postcss-selector-parser": "^5.0.0",
|
||||
"pretty-hrtime": "^1.0.3",
|
||||
"strip-comments": "^1.0.2"
|
||||
"postcss-selector-parser": "^6.0.0",
|
||||
"pretty-hrtime": "^1.0.3"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%"
|
||||
|
|
@ -63,25 +59,24 @@
|
|||
"babel": {
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "6.9.0"
|
||||
"node": "8.9.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-2",
|
||||
"stage-3",
|
||||
"react"
|
||||
]
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/jest/customMatchers.js",
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/jest/customMatchers.js"
|
||||
],
|
||||
"testPathIgnorePatterns": [
|
||||
"<rootDir>/__tests__/fixtures/"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/appearance').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/backgroundAttachment').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/backgroundColors').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/backgroundPosition').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/backgroundRepeat').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/backgroundSize').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/borderCollapse').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/borderColors').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/borderRadius').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/borderStyle').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/borderWidths').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/container')
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/cursor').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/display').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/flexbox').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/float').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/fontWeights').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/fonts').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/height').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/leading').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/lists').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/margin').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/maxHeight').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/maxWidth').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/minHeight').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/minWidth').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/negativeMargin').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/objectFit').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/objectPosition').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/opacity').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/outline').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/overflow').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/padding').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/pointerEvents').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/position').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/resize').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/shadows').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/svgFill').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/svgStroke').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/tableLayout').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/textAlign').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/textColors').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/textSizes').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/textStyle').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/tracking').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/userSelect').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/verticalAlign').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/visibility').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/whitespace').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/width').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../lib/plugins/zIndex').default
|
||||
|
|
@ -1 +0,0 @@
|
|||
@tailwind preflight;
|
||||
6
resolveConfig.js
Normal file
6
resolveConfig.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
const resolveConfigObjects = require('./lib/util/resolveConfig').default
|
||||
const defaultConfig = require('./stubs/defaultConfig.stub.js')
|
||||
|
||||
module.exports = function resolveConfig(config) {
|
||||
return resolveConfigObjects([config, defaultConfig])
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ function buildDistFile(filename) {
|
|||
console.info('Building Tailwind!')
|
||||
|
||||
Promise.all([
|
||||
buildDistFile('preflight'),
|
||||
buildDistFile('base'),
|
||||
buildDistFile('components'),
|
||||
buildDistFile('utilities'),
|
||||
buildDistFile('tailwind'),
|
||||
|
|
|
|||
46
src/cli/colors.js
Normal file
46
src/cli/colors.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import chalk from 'chalk'
|
||||
|
||||
/**
|
||||
* Applies colors to emphasize
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function bold(...msgs) {
|
||||
return chalk.bold(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to inform
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function info(...msgs) {
|
||||
return chalk.bold.cyan(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to signify error
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function error(...msgs) {
|
||||
return chalk.bold.red(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to represent a command
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function command(...msgs) {
|
||||
return chalk.bold.magenta(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to represent a file
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function file(...msgs) {
|
||||
return chalk.bold.magenta(...msgs)
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import autoprefixer from 'autoprefixer'
|
||||
import bytes from 'bytes'
|
||||
import chalk from 'chalk'
|
||||
import postcss from 'postcss'
|
||||
import prettyHrtime from 'pretty-hrtime'
|
||||
|
||||
import tailwind from '../..'
|
||||
|
||||
import commands from '.'
|
||||
import compile from '../compile'
|
||||
import * as colors from '../colors'
|
||||
import * as emoji from '../emoji'
|
||||
import * as utils from '../utils'
|
||||
|
||||
|
|
@ -57,68 +57,40 @@ function stopWithHelp(...msgs) {
|
|||
utils.die()
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles CSS file.
|
||||
*
|
||||
* @param {string} inputFile
|
||||
* @param {string} configFile
|
||||
* @param {string} outputFile
|
||||
* @param {boolean} autoprefix
|
||||
* @return {Promise}
|
||||
*/
|
||||
function build(inputFile, configFile, outputFile, autoprefix) {
|
||||
const css = utils.readFile(inputFile)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
postcss([tailwind(configFile)].concat(autoprefix ? [autoprefixer] : []))
|
||||
.process(css, {
|
||||
from: inputFile,
|
||||
to: outputFile,
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles CSS file and writes it to stdout.
|
||||
*
|
||||
* @param {string} inputFile
|
||||
* @param {string} configFile
|
||||
* @param {string} outputFile
|
||||
* @param {boolean} autoprefix
|
||||
* @param {CompileOptions} compileOptions
|
||||
* @return {Promise}
|
||||
*/
|
||||
function buildToStdout(inputFile, configFile, outputFile, autoprefix) {
|
||||
return build(inputFile, configFile, outputFile, autoprefix).then(result =>
|
||||
process.stdout.write(result.css)
|
||||
)
|
||||
function buildToStdout(compileOptions) {
|
||||
return compile(compileOptions).then(result => process.stdout.write(result.css))
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles CSS file and writes it to a file.
|
||||
*
|
||||
* @param {string} inputFile
|
||||
* @param {string} configFile
|
||||
* @param {string} outputFile
|
||||
* @param {boolean} autoprefix
|
||||
* @param {CompileOptions} compileOptions
|
||||
* @param {int[]} startTime
|
||||
* @return {Promise}
|
||||
*/
|
||||
function buildToFile(inputFile, configFile, outputFile, autoprefix, startTime) {
|
||||
function buildToFile(compileOptions, startTime) {
|
||||
const inputFileSimplePath = utils.getSimplePath(compileOptions.inputFile)
|
||||
const outputFileSimplePath = utils.getSimplePath(compileOptions.outputFile)
|
||||
|
||||
utils.header()
|
||||
utils.log()
|
||||
utils.log(emoji.go, 'Building...', chalk.bold.cyan(inputFile))
|
||||
utils.log(emoji.go, 'Building...', colors.file(inputFileSimplePath))
|
||||
|
||||
return build(inputFile, configFile, outputFile, autoprefix).then(result => {
|
||||
utils.writeFile(outputFile, result.css)
|
||||
return compile(compileOptions).then(result => {
|
||||
utils.writeFile(compileOptions.outputFile, result.css)
|
||||
|
||||
const prettyTime = prettyHrtime(process.hrtime(startTime))
|
||||
|
||||
utils.log()
|
||||
utils.log(emoji.yes, 'Finished in', chalk.bold.magenta(prettyTime))
|
||||
utils.log(emoji.pack, 'Size:', chalk.bold.magenta(bytes(result.css.length)))
|
||||
utils.log(emoji.disk, 'Saved to', chalk.bold.cyan(outputFile))
|
||||
utils.log(emoji.yes, 'Finished in', colors.info(prettyTime))
|
||||
utils.log(emoji.pack, 'Size:', colors.info(bytes(result.css.length)))
|
||||
utils.log(emoji.disk, 'Saved to', colors.file(outputFileSimplePath))
|
||||
utils.footer()
|
||||
})
|
||||
}
|
||||
|
|
@ -137,17 +109,25 @@ export function run(cliParams, cliOptions) {
|
|||
const configFile = cliOptions.config && cliOptions.config[0]
|
||||
const outputFile = cliOptions.output && cliOptions.output[0]
|
||||
const autoprefix = !cliOptions.noAutoprefixer
|
||||
const inputFileSimplePath = utils.getSimplePath(inputFile)
|
||||
const configFileSimplePath = utils.getSimplePath(configFile)
|
||||
|
||||
!inputFile && stopWithHelp('CSS file is required.')
|
||||
!utils.exists(inputFile) && stop(chalk.bold.magenta(inputFile), 'does not exist.')
|
||||
!utils.exists(inputFile) && stop(colors.file(inputFileSimplePath), 'does not exist.')
|
||||
|
||||
configFile &&
|
||||
!utils.exists(configFile) &&
|
||||
stop(chalk.bold.magenta(configFile), 'does not exist.')
|
||||
stop(colors.file(configFileSimplePath), 'does not exist.')
|
||||
|
||||
const compileOptions = {
|
||||
inputFile,
|
||||
outputFile,
|
||||
plugins: [tailwind(configFile)].concat(autoprefix ? [autoprefixer] : []),
|
||||
}
|
||||
|
||||
const buildPromise = outputFile
|
||||
? buildToFile(inputFile, configFile, outputFile, autoprefix, startTime)
|
||||
: buildToStdout(inputFile, configFile, outputFile, autoprefix)
|
||||
? buildToFile(compileOptions, startTime)
|
||||
: buildToStdout(compileOptions)
|
||||
|
||||
buildPromise.then(resolve).catch(reject)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import chalk from 'chalk'
|
||||
import { forEach, map, padEnd } from 'lodash'
|
||||
|
||||
import commands from '.'
|
||||
import * as constants from '../constants'
|
||||
import * as constants from '../../constants'
|
||||
import * as colors from '../colors'
|
||||
import * as utils from '../utils'
|
||||
|
||||
export const usage = 'help [command]'
|
||||
|
|
@ -18,11 +18,11 @@ export function forApp() {
|
|||
|
||||
utils.log()
|
||||
utils.log('Usage:')
|
||||
utils.log(' ', chalk.bold(constants.cli + ' <command> [options]'))
|
||||
utils.log(' ', colors.bold(constants.cli + ' <command> [options]'))
|
||||
utils.log()
|
||||
utils.log('Commands:')
|
||||
forEach(commands, command => {
|
||||
utils.log(' ', chalk.bold(padEnd(command.usage, pad)), command.description)
|
||||
utils.log(' ', colors.bold(padEnd(command.usage, pad)), command.description)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +34,10 @@ export function forApp() {
|
|||
export function forCommand(command) {
|
||||
utils.log()
|
||||
utils.log('Usage:')
|
||||
utils.log(' ', chalk.bold(constants.cli, command.usage))
|
||||
utils.log(' ', colors.bold(constants.cli, command.usage))
|
||||
utils.log()
|
||||
utils.log('Description:')
|
||||
utils.log(' ', chalk.bold(command.description))
|
||||
utils.log(' ', colors.bold(command.description))
|
||||
|
||||
if (command.options) {
|
||||
const pad = Math.max(...map(command.options, 'usage.length')) + PADDING_SIZE
|
||||
|
|
@ -45,7 +45,7 @@ export function forCommand(command) {
|
|||
utils.log()
|
||||
utils.log('Options:')
|
||||
forEach(command.options, option => {
|
||||
utils.log(' ', chalk.bold(padEnd(option.usage, pad)), option.description)
|
||||
utils.log(' ', colors.bold(padEnd(option.usage, pad)), option.description)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ export function forCommand(command) {
|
|||
* @param {string} commandName
|
||||
*/
|
||||
export function invalidCommand(commandName) {
|
||||
utils.error('Invalid command:', chalk.bold.magenta(commandName))
|
||||
utils.error('Invalid command:', colors.command(commandName))
|
||||
forApp()
|
||||
utils.die()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
import chalk from 'chalk'
|
||||
|
||||
import * as constants from '../constants'
|
||||
import * as constants from '../../constants'
|
||||
import * as colors from '../colors'
|
||||
import * as emoji from '../emoji'
|
||||
import * as utils from '../utils'
|
||||
|
||||
export const usage = 'init [file]'
|
||||
export const description =
|
||||
'Creates Tailwind config file. Default: ' + chalk.bold.magenta(constants.defaultConfigFile)
|
||||
'Creates Tailwind config file. Default: ' +
|
||||
colors.file(utils.getSimplePath(constants.defaultConfigFile))
|
||||
|
||||
export const options = [
|
||||
{
|
||||
usage: '--no-comments',
|
||||
description: 'Omit comments from the config file.',
|
||||
usage: '--full',
|
||||
description: 'Generate complete configuration file.',
|
||||
},
|
||||
]
|
||||
|
||||
export const optionMap = {
|
||||
noComments: ['no-comments'],
|
||||
full: ['full'],
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -30,21 +30,18 @@ export function run(cliParams, cliOptions) {
|
|||
return new Promise(resolve => {
|
||||
utils.header()
|
||||
|
||||
const noComments = cliOptions.noComments
|
||||
const full = cliOptions.full
|
||||
const file = cliParams[0] || constants.defaultConfigFile
|
||||
const simplePath = utils.getSimplePath(file)
|
||||
|
||||
utils.exists(file) && utils.die(chalk.bold.magenta(file), 'already exists.')
|
||||
utils.exists(file) && utils.die(colors.file(simplePath), 'already exists.')
|
||||
|
||||
let stub = utils
|
||||
.readFile(constants.configStubFile)
|
||||
.replace("require('./plugins/container')", "require('tailwindcss/plugins/container')")
|
||||
const stubFile = full ? constants.defaultConfigStubFile : constants.simpleConfigStubFile
|
||||
|
||||
noComments && (stub = utils.stripBlockComments(stub))
|
||||
|
||||
utils.writeFile(file, stub)
|
||||
utils.copyFile(stubFile, file)
|
||||
|
||||
utils.log()
|
||||
utils.log(emoji.yes, 'Created Tailwind config file:', chalk.bold.magenta(file))
|
||||
utils.log(emoji.yes, 'Created Tailwind config file:', colors.file(simplePath))
|
||||
|
||||
utils.footer()
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue