From 53092ea1e97f5b5ed0da9b7cb811ce2a45f91f88 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 23 Mar 2021 21:00:27 -0400 Subject: [PATCH 1/2] Fix multiple @apply of responsive rules We achieve this by: 1. handling applies on a per-parent basis 2. Splitting @apply a b c into @apply a; @apply b; @apply c; (in that order) and then sorting all applies in a given node --- src/lib/expandApplyAtRules.js | 33 +++++++++++++++++++++++++++------ tests/10-apply.test.css | 32 ++++++++++++++++++++++++++++++++ tests/10-apply.test.js | 9 +++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/lib/expandApplyAtRules.js b/src/lib/expandApplyAtRules.js index d6b2eee..7704c23 100644 --- a/src/lib/expandApplyAtRules.js +++ b/src/lib/expandApplyAtRules.js @@ -102,8 +102,15 @@ function expandApplyAtRules(context) { .join(', ') } + /** @type {Map} */ + let perParentApplies = new Map() + + // Collect all apply candidates and their rules for (let apply of applies) { - let siblings = [] + let candidates = perParentApplies.get(apply.parent) || [] + + perParentApplies.set(apply.parent, candidates) + let [applyCandidates, important] = extractApplyCandidates(apply.params) for (let applyCandidate of applyCandidates) { @@ -115,13 +122,25 @@ function expandApplyAtRules(context) { let rules = applyClassCache.get(applyCandidate) + candidates.push([applyCandidate, important, rules]) + } + } + + for (const [parent, candidates] of perParentApplies) { + let siblings = [] + + for (let candidate of candidates) { + let applyCandidate = candidate[0] + let important = candidate[1] + let rules = candidate[2] for (let [meta, node] of rules) { let root = postcss.root({ nodes: [node.clone()] }) - let canRewriteSelector = node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes'); + let canRewriteSelector = + node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes') if (canRewriteSelector) { root.walkRules((rule) => { - rule.selector = replaceSelector(apply.parent.selector, rule.selector, applyCandidate) + rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate) rule.walkDecls((d) => { d.important = important @@ -134,11 +153,13 @@ function expandApplyAtRules(context) { } // Inject the rules, sorted, correctly - const nodes = siblings.sort(([a], [z]) => bigSign(a.sort - z.sort)).map(s => s[1]) + const nodes = siblings.sort(([a], [z]) => bigSign(a.sort - z.sort)).map((s) => s[1]) - // `apply.parent` is referring to the node at `.abc` in: .abc { @apply mt-2 } - apply.parent.after(nodes) + // `parent` refers to the node at `.abc` in: .abc { @apply mt-2 } + parent.after(nodes) + } + for (let apply of applies) { // If there are left-over declarations, just remove the @apply if (apply.parent.nodes.length > 1) { apply.remove() diff --git a/tests/10-apply.test.css b/tests/10-apply.test.css index cccd8b4..dd7ee96 100644 --- a/tests/10-apply.test.css +++ b/tests/10-apply.test.css @@ -265,6 +265,38 @@ color: green; font-weight: 700; } +h1 { + font-size: 1.5rem; + line-height: 2rem; +} +@media (min-width: 640px) { + h1 { + font-size: 1.875rem; + line-height: 2.25rem; + } +} +@media (min-width: 1024px) { + h1 { + font-size: 1.5rem; + line-height: 2rem; + } +} +h2 { + font-size: 1.5rem; + line-height: 2rem; +} +@media (min-width: 640px) { + h2 { + font-size: 1.5rem; + line-height: 2rem; + } +} +@media (min-width: 1024px) { + h2 { + font-size: 1.5rem; + line-height: 2rem; + } +} @keyframes spin { to { transform: rotate(360deg); diff --git a/tests/10-apply.test.js b/tests/10-apply.test.js index 8e0c3e0..a9fa533 100644 --- a/tests/10-apply.test.js +++ b/tests/10-apply.test.js @@ -99,6 +99,15 @@ test('@apply', () => { .use-with-other-properties-component { @apply use-with-other-properties-base; } + + h1 { + @apply text-2xl lg:text-2xl sm:text-3xl; + } + h2 { + @apply text-2xl; + @apply lg:text-2xl; + @apply sm:text-2xl; + } } @layer utilities { From 52e997696de182725e7d7e3fe44904f51db5eef9 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 24 Mar 2021 08:40:14 -0400 Subject: [PATCH 2/2] Use destructing when looping over candidates Co-authored-by: Robin Malfait --- src/lib/expandApplyAtRules.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib/expandApplyAtRules.js b/src/lib/expandApplyAtRules.js index 7704c23..b969074 100644 --- a/src/lib/expandApplyAtRules.js +++ b/src/lib/expandApplyAtRules.js @@ -129,10 +129,7 @@ function expandApplyAtRules(context) { for (const [parent, candidates] of perParentApplies) { let siblings = [] - for (let candidate of candidates) { - let applyCandidate = candidate[0] - let important = candidate[1] - let rules = candidate[2] + for (let [applyCandidate, important, rules] of candidates) { for (let [meta, node] of rules) { let root = postcss.root({ nodes: [node.clone()] }) let canRewriteSelector =