Skip to content

Commit 8179dc6

Browse files
authored
fix(tailwind): Declarations with multiple variables not being resolved (#2089)
1 parent 681d4ed commit 8179dc6

File tree

3 files changed

+44
-13
lines changed

3 files changed

+44
-13
lines changed

.changeset/wet-guests-share.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-email/tailwind": patch
3+
---
4+
5+
Fix multiple variables in the same declaration not being replaced properly

packages/tailwind/src/utils/css/resolve-all-css-variables.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@ describe('resolveAllCSSVariables', () => {
1616
}`);
1717
});
1818

19+
it('should work with multiple variables in the same declaration', () => {
20+
const root = parse(`:root {
21+
--top: 101px;
22+
--bottom: 102px;
23+
--right: 103px;
24+
--left: 104px;
25+
}
26+
27+
.box {
28+
margin: var(--top) var(--right) var(--bottom) var(--left);
29+
}`);
30+
31+
expect(resolveAllCSSVariables(root).toString()).toBe(`.box {
32+
margin: 101px 103px 102px 104px;
33+
}`);
34+
});
35+
1936
it('should keep variable usages if it cant find their declaration', () => {
2037
const root = parse(`.box {
2138
width: var(--width);

packages/tailwind/src/utils/css/resolve-all-css-variables.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,39 @@ export const resolveAllCSSVariables = (root: Root) => {
2626
const declarationsForAtRules = new Map<AtRule, Set<Declaration>>();
2727
const valueReplacingInformation = new Set<{
2828
declaration: Declaration;
29-
newValue: string;
29+
replacing: string;
30+
replacement: string;
3031
}>();
3132

32-
rule.walkDecls((decl) => {
33-
if (/var\(--[^\s)]+\)/.test(decl.value)) {
33+
rule.walkDecls((declaration) => {
34+
if (/var\(--[^\s)]+\)/.test(declaration.value)) {
3435
/**
3536
* @example ['var(--width)', 'var(--length)']
3637
*/
37-
const variablesUsed = /var\(--[^\s)]+\)/gm.exec(decl.value);
38+
const variablesUsed = [
39+
...declaration.value.matchAll(/var\(--[^\s)]+\)/gm),
40+
].map((match) => match.toString());
41+
3842
root.walkDecls((otherDecl) => {
3943
if (/--[^\s]+/.test(otherDecl.prop)) {
4044
const variable = `var(${otherDecl.prop})`;
4145
if (
4246
variablesUsed?.includes(variable) &&
43-
doNodesMatch(decl.parent, otherDecl.parent)
47+
doNodesMatch(declaration.parent, otherDecl.parent)
4448
) {
4549
if (
4650
otherDecl.parent?.parent instanceof AtRule &&
47-
otherDecl.parent !== decl.parent
51+
otherDecl.parent !== declaration.parent
4852
) {
4953
const atRule = otherDecl.parent.parent;
5054

5155
const clonedDeclaration = createDeclaration();
52-
clonedDeclaration.prop = decl.prop;
53-
clonedDeclaration.value = decl.value.replaceAll(
56+
clonedDeclaration.prop = declaration.prop;
57+
clonedDeclaration.value = declaration.value.replaceAll(
5458
variable,
5559
otherDecl.value,
5660
);
57-
clonedDeclaration.important = decl.important;
61+
clonedDeclaration.important = declaration.important;
5862

5963
const declarationForAtRule = declarationsForAtRules.get(atRule);
6064
if (declarationForAtRule) {
@@ -69,17 +73,22 @@ export const resolveAllCSSVariables = (root: Root) => {
6973
}
7074

7175
valueReplacingInformation.add({
72-
declaration: decl,
73-
newValue: decl.value.replaceAll(variable, otherDecl.value),
76+
declaration,
77+
replacing: variable,
78+
replacement: otherDecl.value,
7479
});
7580
}
7681
}
7782
});
7883
}
7984
});
8085

81-
for (const { declaration, newValue } of valueReplacingInformation) {
82-
declaration.value = newValue;
86+
for (const {
87+
declaration,
88+
replacing,
89+
replacement,
90+
} of valueReplacingInformation) {
91+
declaration.value = declaration.value.replaceAll(replacing, replacement);
8392
}
8493

8594
for (const [atRule, declarations] of declarationsForAtRules.entries()) {

0 commit comments

Comments
 (0)