Skip to content
This repository was archived by the owner on Apr 6, 2021. It is now read-only.

Commit e7c47d8

Browse files
committed
Flatten responsive/variants at-rules for better BC behavior
1 parent f84dcfd commit e7c47d8

5 files changed

+226
-28
lines changed

src/lib/removeLayerAtRules.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
function removeLayerAtRules(context) {
22
return (root) => {
3-
root.walkAtRules('layer', (rule) => {
4-
rule.remove()
3+
root.walkAtRules((rule) => {
4+
if (['layer', 'responsive', 'variants'].includes(rule.name)) {
5+
rule.remove()
6+
}
57
})
68
}
79
}

src/lib/setupContext.js

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,56 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
507507
}
508508
}
509509

510+
function extractVariantAtRules(node) {
511+
node.walkAtRules((atRule) => {
512+
if (['responsive', 'variants'].includes(atRule.name)) {
513+
extractVariantAtRules(atRule)
514+
atRule.before(atRule.nodes)
515+
atRule.remove()
516+
}
517+
})
518+
}
519+
520+
function collectLayerPlugins(root) {
521+
let layerPlugins = []
522+
523+
root.each((node) => {
524+
if (node.type === 'atrule' && ['responsive', 'variants'].includes(node.name)) {
525+
node.name = 'layer'
526+
node.params = 'utilities'
527+
}
528+
})
529+
530+
// Walk @layer rules and treat them like plugins
531+
root.walkAtRules('layer', (layerNode) => {
532+
extractVariantAtRules(layerNode)
533+
534+
if (layerNode.params === 'base') {
535+
for (let node of layerNode.nodes) {
536+
layerPlugins.push(function ({ addBase }) {
537+
addBase(node, { respectPrefix: false })
538+
})
539+
}
540+
}
541+
if (layerNode.params === 'components') {
542+
for (let node of layerNode.nodes) {
543+
layerPlugins.push(function ({ addComponents }) {
544+
addComponents(node, { respectPrefix: false })
545+
})
546+
}
547+
}
548+
if (layerNode.params === 'utilities') {
549+
for (let node of layerNode.nodes) {
550+
layerPlugins.push(function ({ addUtilities }) {
551+
addUtilities(node, { respectPrefix: false })
552+
})
553+
}
554+
}
555+
})
556+
557+
return layerPlugins
558+
}
559+
510560
function registerPlugins(tailwindConfig, plugins, context) {
511561
let variantList = []
512562
let variantMap = new Map()
@@ -703,32 +753,7 @@ function setupContext(configOrPath) {
703753
return typeof plugin === 'function' ? plugin : plugin.handler
704754
})
705755

706-
let layerPlugins = []
707-
708-
// Walk @layer rules and treat them like plugins
709-
root.walkAtRules('layer', (layerNode) => {
710-
if (layerNode.params === 'base') {
711-
for (let node of layerNode.nodes) {
712-
layerPlugins.push(function ({ addBase }) {
713-
addBase(node, { respectPrefix: false })
714-
})
715-
}
716-
}
717-
if (layerNode.params === 'components') {
718-
for (let node of layerNode.nodes) {
719-
layerPlugins.push(function ({ addComponents }) {
720-
addComponents(node, { respectPrefix: false })
721-
})
722-
}
723-
}
724-
if (layerNode.params === 'utilities') {
725-
for (let node of layerNode.nodes) {
726-
layerPlugins.push(function ({ addUtilities }) {
727-
addUtilities(node, { respectPrefix: false })
728-
})
729-
}
730-
}
731-
})
756+
let layerPlugins = collectLayerPlugins(root)
732757

733758
// TODO: This is a workaround for backwards compatibility, since custom variants
734759
// were historically sorted before screen/stackable variants.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
* {
2+
--tw-shadow: 0 0 #0000;
3+
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
4+
--tw-ring-offset-width: 0px;
5+
--tw-ring-offset-color: #fff;
6+
--tw-ring-color: rgba(59, 130, 246, 0.5);
7+
--tw-ring-offset-shadow: 0 0 #0000;
8+
--tw-ring-shadow: 0 0 #0000;
9+
}
10+
.responsive-in-components {
11+
color: blue;
12+
}
13+
.variants-in-components {
14+
color: red;
15+
}
16+
.both-in-components {
17+
color: green;
18+
}
19+
.responsive-in-utilities {
20+
color: blue;
21+
}
22+
.variants-in-utilities {
23+
color: red;
24+
}
25+
.both-in-utilities {
26+
color: green;
27+
}
28+
.responsive-at-root {
29+
color: white;
30+
}
31+
.variants-at-root {
32+
color: orange;
33+
}
34+
.both-at-root {
35+
color: pink;
36+
}
37+
@media (min-width: 768px) {
38+
.md\:focus\:responsive-in-components:focus {
39+
color: blue;
40+
}
41+
.md\:focus\:variants-in-components:focus {
42+
color: red;
43+
}
44+
.md\:focus\:both-in-components:focus {
45+
color: green;
46+
}
47+
.md\:focus\:responsive-in-utilities:focus {
48+
color: blue;
49+
}
50+
.md\:focus\:variants-in-utilities:focus {
51+
color: red;
52+
}
53+
.md\:focus\:both-in-utilities:focus {
54+
color: green;
55+
}
56+
.md\:focus\:responsive-at-root:focus {
57+
color: white;
58+
}
59+
.md\:focus\:variants-at-root:focus {
60+
color: orange;
61+
}
62+
.md\:focus\:both-at-root:focus {
63+
color: pink;
64+
}
65+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<div class="responsive-in-utilities"></div>
2+
<div class="variants-in-utilities"></div>
3+
<div class="both-in-utilities"></div>
4+
<div class="responsive-at-root"></div>
5+
<div class="variants-at-root"></div>
6+
<div class="both-at-root"></div>
7+
<div class="responsive-in-components"></div>
8+
<div class="variants-in-components"></div>
9+
<div class="both-in-components"></div>
10+
<div class="md:focus:responsive-in-utilities"></div>
11+
<div class="md:focus:variants-in-utilities"></div>
12+
<div class="md:focus:both-in-utilities"></div>
13+
<div class="md:focus:responsive-at-root"></div>
14+
<div class="md:focus:variants-at-root"></div>
15+
<div class="md:focus:both-at-root"></div>
16+
<div class="md:focus:responsive-in-components"></div>
17+
<div class="md:focus:variants-in-components"></div>
18+
<div class="md:focus:both-in-components"></div>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const postcss = require('postcss')
2+
const tailwind = require('../src/index.js')
3+
const fs = require('fs')
4+
const path = require('path')
5+
6+
function run(input, config = {}) {
7+
return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) })
8+
}
9+
10+
test('responsive and variants atrules', () => {
11+
let config = {
12+
purge: [path.resolve(__dirname, './07-responsive-and-variants-atrules.test.html')],
13+
corePlugins: { preflight: false },
14+
theme: {},
15+
plugins: [],
16+
}
17+
18+
let css = `
19+
@tailwind base;
20+
@tailwind components;
21+
@tailwind utilities;
22+
23+
@layer utilities {
24+
@responsive {
25+
.responsive-in-utilities {
26+
color: blue;
27+
}
28+
}
29+
@variants {
30+
.variants-in-utilities {
31+
color: red;
32+
}
33+
}
34+
@responsive {
35+
@variants {
36+
.both-in-utilities {
37+
color: green;
38+
}
39+
}
40+
}
41+
}
42+
43+
@responsive {
44+
.responsive-at-root {
45+
color: white;
46+
}
47+
}
48+
@variants {
49+
.variants-at-root {
50+
color: orange;
51+
}
52+
}
53+
@responsive {
54+
@variants {
55+
.both-at-root {
56+
color: pink;
57+
}
58+
}
59+
}
60+
61+
@layer components {
62+
@responsive {
63+
.responsive-in-components {
64+
color: blue;
65+
}
66+
}
67+
@variants {
68+
.variants-in-components {
69+
color: red;
70+
}
71+
}
72+
@responsive {
73+
@variants {
74+
.both-in-components {
75+
color: green;
76+
}
77+
}
78+
}
79+
}
80+
`
81+
82+
return run(css, config).then((result) => {
83+
let expectedPath = path.resolve(__dirname, './07-responsive-and-variants-atrules.test.css')
84+
let expected = fs.readFileSync(expectedPath, 'utf8')
85+
86+
expect(result.css).toMatchCss(expected)
87+
})
88+
})

0 commit comments

Comments
 (0)