mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Allows you to write a plugin that registers a new variant but only allows you to modify the selector (like what our built-in generators do.) Next steps are to support variants that wrap rules with at-rules (like @supports for example), variants that can modify properties (as opposed to just selectors), and to give variant plugin authors control over how responsive variants interact with their own variants.
200 lines
5.1 KiB
JavaScript
200 lines
5.1 KiB
JavaScript
import postcss from 'postcss'
|
|
import plugin from '../src/lib/substituteVariantsAtRules'
|
|
import config from '../defaultConfig.stub.js'
|
|
|
|
function run(input, opts = () => config) {
|
|
return postcss([plugin(opts)]).process(input, { from: undefined })
|
|
}
|
|
|
|
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 active variants', () => {
|
|
const input = `
|
|
@variants active {
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
}
|
|
`
|
|
|
|
const output = `
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
.active\\:banana:active { color: yellow; }
|
|
.active\\:chocolate:active { 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 group-hover variants', () => {
|
|
const input = `
|
|
@variants group-hover {
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
}
|
|
`
|
|
|
|
const output = `
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
.group:hover .group-hover\\:banana { color: yellow; }
|
|
.group:hover .group-hover\\:chocolate { color: brown; }
|
|
`
|
|
|
|
return run(input).then(result => {
|
|
expect(result.css).toMatchCss(output)
|
|
expect(result.warnings().length).toBe(0)
|
|
})
|
|
})
|
|
|
|
test('it can generate hover, active and focus variants', () => {
|
|
const input = `
|
|
@variants group-hover, hover, focus, active {
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
}
|
|
`
|
|
|
|
const output = `
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
.group:hover .group-hover\\:banana { color: yellow; }
|
|
.group:hover .group-hover\\:chocolate { color: brown; }
|
|
.hover\\:banana:hover { color: yellow; }
|
|
.hover\\:chocolate:hover { color: brown; }
|
|
.focus\\:banana:focus { color: yellow; }
|
|
.focus\\:chocolate:focus { color: brown; }
|
|
.active\\:banana:active { color: yellow; }
|
|
.active\\:chocolate:active { 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; }
|
|
.hover\\:banana:hover { color: yellow; }
|
|
.hover\\:chocolate:hover { 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('variants are generated in the order specified', () => {
|
|
const input = `
|
|
@variants focus, active, hover {
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
}
|
|
`
|
|
|
|
const output = `
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
.focus\\:banana:focus { color: yellow; }
|
|
.focus\\:chocolate:focus { color: brown; }
|
|
.active\\:banana:active { color: yellow; }
|
|
.active\\:chocolate:active { 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('plugin variants work', () => {
|
|
const input = `
|
|
@variants first-child {
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
}
|
|
`
|
|
|
|
const output = `
|
|
.banana { color: yellow; }
|
|
.chocolate { color: brown; }
|
|
.first-child\\:banana:first-child { color: yellow; }
|
|
.first-child\\:chocolate:first-child { color: brown; }
|
|
`
|
|
|
|
return run(input, () => ({
|
|
...config,
|
|
plugins: [
|
|
...config.plugins,
|
|
function({ addVariant }) {
|
|
addVariant('first-child', ({ className, separator }) => {
|
|
return `.first-child${separator}${className}:first-child`
|
|
})
|
|
},
|
|
],
|
|
})).then(result => {
|
|
expect(result.css).toMatchCss(output)
|
|
expect(result.warnings().length).toBe(0)
|
|
})
|
|
})
|