mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Merge pull request #232 from tailwindcss/variants-rule
Add `@variants` at-rule for generating multiple variants
This commit is contained in:
commit
9c72969b7c
File diff suppressed because it is too large
Load Diff
96
__tests__/variantsAtRule.test.js
Normal file
96
__tests__/variantsAtRule.test.js
Normal file
@ -0,0 +1,96 @@
|
||||
import postcss from 'postcss'
|
||||
import plugin from '../src/lib/substituteVariantsAtRules'
|
||||
|
||||
function run(input, opts = () => {}) {
|
||||
return postcss([plugin(opts)]).process(input)
|
||||
}
|
||||
|
||||
test('it can generate hover variants', () => {
|
||||
const input = `
|
||||
@variants hover {
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
.hover\\:banana:hover { color: yellow; }
|
||||
.hover\\:chocolate:hover { color: brown; }
|
||||
`
|
||||
|
||||
return run(input).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('it can generate focus variants', () => {
|
||||
const input = `
|
||||
@variants focus {
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
.focus\\:banana:focus { color: yellow; }
|
||||
.focus\\:chocolate:focus { color: brown; }
|
||||
`
|
||||
|
||||
return run(input).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('it can generate hover and focus variants', () => {
|
||||
const input = `
|
||||
@variants hover, focus {
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
.focus\\:banana:focus { color: yellow; }
|
||||
.focus\\:chocolate:focus { color: brown; }
|
||||
.hover\\:banana:hover { color: yellow; }
|
||||
.hover\\:chocolate:hover { color: brown; }
|
||||
`
|
||||
|
||||
return run(input).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
test('it wraps the output in a responsive at-rule if responsive is included as a variant', () => {
|
||||
const input = `
|
||||
@variants responsive, hover, focus {
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
const output = `
|
||||
@responsive {
|
||||
.banana { color: yellow; }
|
||||
.chocolate { color: brown; }
|
||||
.focus\\:banana:focus { color: yellow; }
|
||||
.focus\\:chocolate:focus { color: brown; }
|
||||
.hover\\:banana:hover { color: yellow; }
|
||||
.hover\\:chocolate:hover { color: brown; }
|
||||
}
|
||||
`
|
||||
|
||||
return run(input).then(result => {
|
||||
expect(result.css).toMatchCss(output)
|
||||
expect(result.warnings().length).toBe(0)
|
||||
})
|
||||
})
|
||||
@ -6,17 +6,16 @@ expect.extend({
|
||||
return str.replace(/\s/g, '')
|
||||
}
|
||||
|
||||
if (stripped(received) == stripped(argument)) {
|
||||
if (stripped(received) === stripped(argument)) {
|
||||
return {
|
||||
message: () =>
|
||||
`expected ${received} not to match CSS ${argument}`,
|
||||
message: () => `expected ${received} not to match CSS ${argument}`,
|
||||
pass: true,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
message: () => `expected ${received} to match CSS ${argument}`,
|
||||
pass: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import cloneNodes from '../util/cloneNodes'
|
||||
|
||||
export default function() {
|
||||
return function(css) {
|
||||
css.walkAtRules('hoverable', atRule => {
|
||||
|
||||
47
src/lib/substituteVariantsAtRules.js
Normal file
47
src/lib/substituteVariantsAtRules.js
Normal file
@ -0,0 +1,47 @@
|
||||
import _ from 'lodash'
|
||||
import postcss from 'postcss'
|
||||
|
||||
const variantGenerators = {
|
||||
hover: container => {
|
||||
const cloned = container.clone()
|
||||
|
||||
cloned.walkRules(rule => {
|
||||
rule.selector = `.hover\\:${rule.selector.slice(1)}:hover`
|
||||
})
|
||||
|
||||
return cloned.nodes
|
||||
},
|
||||
focus: container => {
|
||||
const cloned = container.clone()
|
||||
|
||||
cloned.walkRules(rule => {
|
||||
rule.selector = `.focus\\:${rule.selector.slice(1)}:focus`
|
||||
})
|
||||
|
||||
return cloned.nodes
|
||||
},
|
||||
}
|
||||
|
||||
export default function() {
|
||||
return function(css) {
|
||||
css.walkAtRules('variants', atRule => {
|
||||
const variants = postcss.list.comma(atRule.params)
|
||||
|
||||
if (variants.includes('responsive')) {
|
||||
const responsiveParent = postcss.atRule({ name: 'responsive' })
|
||||
atRule.before(responsiveParent)
|
||||
responsiveParent.append(atRule)
|
||||
}
|
||||
|
||||
atRule.before(atRule.clone().nodes)
|
||||
|
||||
_.forEach(['focus', 'hover'], variant => {
|
||||
if (variants.includes(variant)) {
|
||||
atRule.before(variantGenerators[variant](atRule))
|
||||
}
|
||||
})
|
||||
|
||||
atRule.remove()
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user