Skip to content

Commit 0282aa6

Browse files
philipp-spiessRobinMalfait
authored andcommitted
Make polyfill work when the theme variable resolves to another var
1 parent 811e97d commit 0282aa6

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

packages/tailwindcss/src/ast.ts

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ export function optimizeAst(
542542
let requiresPolyfill = false
543543
ValueParser.walk(ast, (node, { replaceWith }) => {
544544
if (node.kind !== 'function' || node.value !== 'color-mix') return
545+
545546
let containsUnresolvableVars = false
546547
let containsCurrentcolor = false
547548
ValueParser.walk(node.nodes, (node, { replaceWith }) => {
@@ -550,17 +551,47 @@ export function optimizeAst(
550551
requiresPolyfill = true
551552
return
552553
}
553-
if (node.kind !== 'function' || node.value !== 'var') return
554-
let firstChild = node.nodes[0]
555-
if (!firstChild || firstChild.kind !== 'word') return
556-
requiresPolyfill = true
557-
let inlinedColor = designSystem.theme.resolveValue(null, [firstChild.value as any])
558-
if (!inlinedColor) {
559-
containsUnresolvableVars = true
560-
return
561-
}
554+
555+
let varNode: ValueParser.ValueAstNode | null = node
556+
let inlinedColor: string | null = null
557+
let seenVariables = new Set<string>()
558+
do {
559+
if (varNode.kind !== 'function' || varNode.value !== 'var') return
560+
let firstChild = varNode.nodes[0]
561+
if (!firstChild || firstChild.kind !== 'word') return
562+
563+
let variableName = firstChild.value
564+
565+
if (seenVariables.has(variableName)) {
566+
containsUnresolvableVars = true
567+
return
568+
}
569+
570+
seenVariables.add(variableName)
571+
572+
requiresPolyfill = true
573+
574+
inlinedColor = designSystem.theme.resolveValue(null, [firstChild.value as any])
575+
if (!inlinedColor) {
576+
containsUnresolvableVars = true
577+
return
578+
}
579+
if (inlinedColor.toLowerCase() === 'currentcolor') {
580+
containsCurrentcolor = true
581+
return
582+
}
583+
584+
if (inlinedColor.startsWith('var(')) {
585+
let subAst = ValueParser.parse(inlinedColor)
586+
varNode = subAst[0]
587+
} else {
588+
varNode = null
589+
}
590+
} while (varNode)
591+
562592
replaceWith({ kind: 'word', value: inlinedColor })
563593
})
594+
564595
if (containsUnresolvableVars || containsCurrentcolor) {
565596
let separatorIndex = node.nodes.findIndex(
566597
(node) => node.kind === 'separator' && node.value.trim().includes(','),

packages/tailwindcss/src/index.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4764,6 +4764,36 @@ describe('`color-mix(…)` polyfill', () => {
47644764
`)
47654765
})
47664766

4767+
it('creates an inlined variable version of the color-mix(…) usages when it resolves to a var(…) containing another theme variable', async () => {
4768+
await expect(
4769+
compileCss(
4770+
css`
4771+
@theme {
4772+
--color-red: var(--color-red-500);
4773+
--color-red-500: oklch(63.7% 0.237 25.331);
4774+
}
4775+
@tailwind utilities;
4776+
`,
4777+
['text-red/50'],
4778+
),
4779+
).resolves.toMatchInlineSnapshot(`
4780+
":root, :host {
4781+
--color-red: var(--color-red-500);
4782+
--color-red-500: oklch(63.7% .237 25.331);
4783+
}
4784+
4785+
.text-red\\/50 {
4786+
color: #fb2c3680;
4787+
}
4788+
4789+
@supports (color: color-mix(in lab, red, red)) {
4790+
.text-red\\/50 {
4791+
color: color-mix(in oklab, var(--color-red) 50%, transparent);
4792+
}
4793+
}"
4794+
`)
4795+
})
4796+
47674797
it('works for color values in the first and second position', async () => {
47684798
await expect(
47694799
compileCss(
@@ -4971,6 +5001,34 @@ describe('`color-mix(…)` polyfill', () => {
49715001
`)
49725002
})
49735003

5004+
it('uses the first color value as the fallback when the `color-mix(…)` function contains theme variables that resolves to other variables', async () => {
5005+
await expect(
5006+
compileCss(
5007+
css`
5008+
@tailwind utilities;
5009+
@theme {
5010+
--color-red: var(--my-red);
5011+
}
5012+
`,
5013+
['text-red/50'],
5014+
),
5015+
).resolves.toMatchInlineSnapshot(`
5016+
".text-red\\/50 {
5017+
color: var(--color-red);
5018+
}
5019+
5020+
@supports (color: color-mix(in lab, red, red)) {
5021+
.text-red\\/50 {
5022+
color: color-mix(in oklab, var(--color-red) 50%, transparent);
5023+
}
5024+
}
5025+
5026+
:root, :host {
5027+
--color-red: var(--my-red);
5028+
}"
5029+
`)
5030+
})
5031+
49745032
it('uses the first color value of the inner most `color-mix(…)` function as the fallback when nested `color-mix(…)` function all contain non-theme variables', async () => {
49755033
await expect(
49765034
compileCss(

0 commit comments

Comments
 (0)