Don't associate custom CSS with a layer by default

This commit is contained in:
Adam Wathan 2020-09-02 13:50:42 -04:00
parent aae71c5249
commit 956133a7a4
2 changed files with 91 additions and 200 deletions

View file

@ -17,27 +17,19 @@ test('it can generate responsive variants', () => {
`
const output = `
@layer utilities {
.banana { color: yellow; }
.chocolate { color: brown; }
}
.banana { color: yellow; }
.chocolate { color: brown; }
@media (min-width: 500px) {
@layer utilities {
.sm\\:banana { color: yellow; }
.sm\\:chocolate { color: brown; }
}
.sm\\:banana { color: yellow; }
.sm\\:chocolate { color: brown; }
}
@media (min-width: 750px) {
@layer utilities {
.md\\:banana { color: yellow; }
.md\\:chocolate { color: brown; }
}
.md\\:banana { color: yellow; }
.md\\:chocolate { color: brown; }
}
@media (min-width: 1000px) {
@layer utilities {
.lg\\:banana { color: yellow; }
.lg\\:chocolate { color: brown; }
}
.lg\\:banana { color: yellow; }
.lg\\:chocolate { color: brown; }
}
`
@ -67,27 +59,19 @@ test('it can generate responsive variants with a custom separator', () => {
`
const output = `
@layer utilities {
.banana { color: yellow; }
.chocolate { color: brown; }
}
.banana { color: yellow; }
.chocolate { color: brown; }
@media (min-width: 500px) {
@layer utilities {
.sm__banana { color: yellow; }
.sm__chocolate { color: brown; }
}
.sm__banana { color: yellow; }
.sm__chocolate { color: brown; }
}
@media (min-width: 750px) {
@layer utilities {
.md__banana { color: yellow; }
.md__chocolate { color: brown; }
}
.md__banana { color: yellow; }
.md__chocolate { color: brown; }
}
@media (min-width: 1000px) {
@layer utilities {
.lg__banana { color: yellow; }
.lg__chocolate { color: brown; }
}
.lg__banana { color: yellow; }
.lg__chocolate { color: brown; }
}
`
@ -118,31 +102,23 @@ test('it can generate responsive variants when classes have non-standard charact
`
const output = `
@layer utilities {
.hover\\:banana { color: yellow; }
.chocolate-2\\.5 { color: brown; }
.group:hover .group-hover\\:toast { color: black; }
}
.hover\\:banana { color: yellow; }
.chocolate-2\\.5 { color: brown; }
.group:hover .group-hover\\:toast { color: black; }
@media (min-width: 500px) {
@layer utilities {
.sm\\:hover\\:banana { color: yellow; }
.sm\\:chocolate-2\\.5 { color: brown; }
.group:hover .sm\\:group-hover\\:toast { color: black; }
.sm\\:hover\\:banana { color: yellow; }
.sm\\:chocolate-2\\.5 { color: brown; }
.group:hover .sm\\:group-hover\\:toast { color: black; }
}
}
@media (min-width: 750px) {
@layer utilities {
.md\\:hover\\:banana { color: yellow; }
.md\\:chocolate-2\\.5 { color: brown; }
.group:hover .md\\:group-hover\\:toast { color: black; }
.md\\:hover\\:banana { color: yellow; }
.md\\:chocolate-2\\.5 { color: brown; }
.group:hover .md\\:group-hover\\:toast { color: black; }
}
}
@media (min-width: 1000px) {
@layer utilities {
.lg\\:hover\\:banana { color: yellow; }
.lg\\:chocolate-2\\.5 { color: brown; }
.group:hover .lg\\:group-hover\\:toast { color: black; }
}
.lg\\:hover\\:banana { color: yellow; }
.lg\\:chocolate-2\\.5 { color: brown; }
.group:hover .lg\\:group-hover\\:toast { color: black; }
}
`
@ -177,36 +153,20 @@ test('responsive variants are grouped', () => {
`
const output = `
@layer utilities {
.banana { color: yellow; }
}
.banana { color: yellow; }
.apple { color: red; }
@layer utilities {
.chocolate { color: brown; }
}
.chocolate { color: brown; }
@media (min-width: 500px) {
@layer utilities {
.sm\\:banana { color: yellow; }
}
@layer utilities {
.sm\\:chocolate { color: brown; }
}
.sm\\:banana { color: yellow; }
.sm\\:chocolate { color: brown; }
}
@media (min-width: 750px) {
@layer utilities {
.md\\:banana { color: yellow; }
}
@layer utilities {
.md\\:chocolate { color: brown; }
}
.md\\:banana { color: yellow; }
.md\\:chocolate { color: brown; }
}
@media (min-width: 1000px) {
@layer utilities {
.lg\\:banana { color: yellow; }
}
@layer utilities {
.lg\\:chocolate { color: brown; }
}
.lg\\:banana { color: yellow; }
.lg\\:chocolate { color: brown; }
}
`
@ -239,42 +199,36 @@ test('it can generate responsive variants for nested at-rules', () => {
`
const output = `
@layer utilities {
.banana {
.banana {
color: yellow;
}
@supports(display: grid) {
.grid\\:banana {
color: blue;
}
}
@media (min-width: 500px) {
.sm\\:banana {
color: yellow;
}
@supports(display: grid) {
.grid\\:banana {
.sm\\:grid\\:banana {
color: blue;
}
}
}
@media (min-width: 500px) {
@layer utilities {
.sm\\:banana {
color: yellow;
}
@supports(display: grid) {
.sm\\:grid\\:banana {
color: blue;
}
}
}
}
@media (min-width: 1000px) {
@layer utilities {
.lg\\:banana {
color: yellow;
}
.lg\\:banana {
color: yellow;
}
@supports(display: grid) {
.lg\\:grid\\:banana {
color: blue;
}
@supports(display: grid) {
.lg\\:grid\\:banana {
color: blue;
}
}
}
@ -310,47 +264,41 @@ test('it can generate responsive variants for deeply nested at-rules', () => {
`
const output = `
@layer utilities {
.banana {
.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) {
.flex-grid\\:banana {
.sm\\:flex-grid\\:banana {
color: blue;
}
}
}
}
@media (min-width: 500px) {
@layer utilities {
.sm\\:banana {
color: yellow;
}
@supports(display: grid) {
@supports(display: flex) {
.sm\\:flex-grid\\:banana {
color: blue;
}
}
}
}
}
@media (min-width: 1000px) {
@layer utilities {
.lg\\:banana {
color: yellow;
}
.lg\\:banana {
color: yellow;
}
@supports(display: grid) {
@supports(display: flex) {
.lg\\:flex-grid\\:banana {
color: blue;
}
@supports(display: grid) {
@supports(display: flex) {
.lg\\:flex-grid\\:banana {
color: blue;
}
}
}
@ -381,23 +329,15 @@ test('screen prefix is only applied to the last class in a selector', () => {
`
const output = `
@layer utilities {
.banana li * .sandwich #foo > div { color: yellow; }
}
.banana li * .sandwich #foo > div { color: yellow; }
@media (min-width: 500px) {
@layer utilities {
.banana li * .sm\\:sandwich #foo > div { color: yellow; }
}
.banana li * .sm\\:sandwich #foo > div { color: yellow; }
}
@media (min-width: 750px) {
@layer utilities {
.banana li * .md\\:sandwich #foo > div { color: yellow; }
}
.banana li * .md\\:sandwich #foo > div { color: yellow; }
}
@media (min-width: 1000px) {
@layer utilities {
.banana li * .lg\\:sandwich #foo > div { color: yellow; }
}
.banana li * .lg\\:sandwich #foo > div { color: yellow; }
}
`
@ -426,23 +366,15 @@ test('responsive variants are generated for all selectors in a rule', () => {
`
const output = `
@layer utilities {
.foo, .bar { color: yellow; }
}
.foo, .bar { color: yellow; }
@media (min-width: 500px) {
@layer utilities {
.sm\\:foo, .sm\\:bar { color: yellow; }
}
.sm\\:foo, .sm\\:bar { color: yellow; }
}
@media (min-width: 750px) {
@layer utilities {
.md\\:foo, .md\\:bar { color: yellow; }
}
.md\\:foo, .md\\:bar { color: yellow; }
}
@media (min-width: 1000px) {
@layer utilities {
.lg\\:foo, .lg\\:bar { color: yellow; }
}
.lg\\:foo, .lg\\:bar { color: yellow; }
}
`

View file

@ -4,51 +4,19 @@ import cloneNodes from '../util/cloneNodes'
import buildMediaQuery from '../util/buildMediaQuery'
import buildSelectorVariant from '../util/buildSelectorVariant'
function isLayer(node) {
if (Array.isArray(node)) {
return node.length === 1 && isLayer(node[0])
}
return node.type === 'atrule' && node.name === 'layer'
}
function layerNodes(nodes) {
return isLayer(nodes) ? nodes[0].nodes : nodes
}
export default function(config) {
return function(css) {
// Wrap any `responsive` rules with a copy of their parent `layer` to
// ensure the layer isn't lost when copying to the `screens` location.
// Store the `layer` for each responsive at-rule directly on the at-rule for later reference.
css.walkAtRules('layer', layerAtRule => {
const layer = layerAtRule.params
layerAtRule.walkAtRules('responsive', responsiveAtRule => {
const nestedlayerAtRule = postcss.atRule({
name: 'layer',
params: layer,
})
nestedlayerAtRule.prepend(responsiveAtRule.nodes)
responsiveAtRule.removeAll()
responsiveAtRule.prepend(nestedlayerAtRule)
responsiveAtRule.__tailwind = {
...responsiveAtRule.__tailwind,
layer,
}
})
})
// Find any `responsive` rules with no parent `layer` (these only come
// from the user's CSS, Tailwind never generates things this way itself)
// and wrap them with a default `layer` of `utilities`.
css.walkAtRules('responsive', responsiveAtRule => {
const [node] = responsiveAtRule.nodes
if (node.type === 'atrule' && node.name === 'layer') {
return
}
const nestedlayerAtRule = postcss.atRule({
name: 'layer',
params: 'utilities',
})
nestedlayerAtRule.prepend(responsiveAtRule.nodes)
responsiveAtRule.removeAll()
responsiveAtRule.prepend(nestedlayerAtRule)
})
const {
theme: { screens },
separator,
@ -59,16 +27,7 @@ export default function(config) {
css.walkAtRules('responsive', atRule => {
const nodes = atRule.nodes
responsiveRules.append(...cloneNodes(nodes))
// If the parent is already a `layer` (this is true for anything coming from
// a plugin, including core plugins) we don't want to create a double nested
// layer, so only insert the layer children. If there is no parent layer,
// preserve the layer information when inserting the nodes.
if (isLayer(atRule.parent)) {
atRule.before(layerNodes(nodes))
} else {
atRule.before(nodes)
}
atRule.before(nodes)
atRule.remove()
})