Skip to content

Commit afd6906

Browse files
committed
Always return theme values when known
1 parent cb9f5b3 commit afd6906

File tree

2 files changed

+34
-19
lines changed

2 files changed

+34
-19
lines changed

packages/tailwindcss-language-service/src/util/css-vars.test.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { DesignSystem } from './v4'
55

66
test('replacing CSS variables with their fallbacks (when they have them)', () => {
77
let map = new Map<string, string>([
8-
['--foo', 'blue'],
8+
['--known', 'blue'],
99
])
1010

1111
let state: State = {
@@ -42,12 +42,15 @@ test('replacing CSS variables with their fallbacks (when they have them)', () =>
4242
),
4343
).toBe('color-mix(in srgb, oklch(0 0 0 / 2.5), oklch(0 0 0 / 2.5), 50%)')
4444

45-
// Fallbacks take precedence over theme values
46-
expect(replaceCssVarsWithFallbacks(state, 'var(--foo, red)')).toBe(' red')
45+
// Known theme keys are replaced with their values
46+
expect(replaceCssVarsWithFallbacks(state, 'var(--known)')).toBe('blue')
47+
48+
// Values from the theme take precedence over fallbacks
49+
expect(replaceCssVarsWithFallbacks(state, 'var(--known, red)')).toBe('blue')
4750

48-
// Values from the theme are used when no fallback is provided
49-
expect(replaceCssVarsWithFallbacks(state, 'var(--foo)')).toBe('blue')
51+
// Unknown theme keys use a fallback if provided
52+
expect(replaceCssVarsWithFallbacks(state, 'var(--unknown, red)')).toBe(' red')
5053

51-
// Values not in the theme don't get replaced if no fallback is provided
52-
expect(replaceCssVarsWithFallbacks(state, 'var(--bar)')).toBe('var(--bar)')
54+
// Unknown theme keys without fallbacks are not replaced
55+
expect(replaceCssVarsWithFallbacks(state, 'var(--unknown)')).toBe('var(--unknown)')
5356
})

packages/tailwindcss-language-service/src/util/css-vars.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import type { State } from "./state"
1+
import type { State } from './state'
22

33
export function replaceCssVarsWithFallbacks(state: State, str: string): string {
44
return replaceCssVars(str, (name, fallback) => {
5-
// If we have a fallback then we should use that value directly
6-
if (fallback) return fallback
7-
8-
// In a v4 project we should attempt to look up the value from the theme
9-
// this is because not all v4 projects will generate utilities where
10-
// variables have fallbacks
5+
// Replace with the value from the design system first. The design system
6+
// take precedences over other sources as that emulates the behavior of a
7+
// browser where the fallback is only used if the variable is defined.
118
if (state.designSystem && name.startsWith('--')) {
12-
return state.designSystem.resolveThemeValue?.(name) ?? null
9+
let value = state.designSystem.resolveThemeValue?.(name) ?? null
10+
if (value !== null) return value
11+
}
12+
13+
if (fallback) {
14+
return fallback
1315
}
1416

15-
// Don't replace the variable otherwise
17+
// Don't touch it since there's no suitable replacement
1618
return null
1719
})
1820
}
@@ -34,8 +36,17 @@ function replaceCssVars(str: string, replace: CssVarReplacer): string {
3436
} else if (str[j] === ',' && depth === 0 && fallbackStart === null) {
3537
fallbackStart = j + 1
3638
} else if (str[j] === ')' && depth === 0) {
37-
let varName = str.slice(i + 4, j)
38-
let fallback = fallbackStart === null ? null : str.slice(fallbackStart, j)
39+
let varName: string
40+
let fallback: string | null
41+
42+
if (fallbackStart === null) {
43+
varName = str.slice(i + 4, j)
44+
fallback = null
45+
} else {
46+
varName = str.slice(i + 4, fallbackStart - 1)
47+
fallback = str.slice(fallbackStart, j)
48+
}
49+
3950
let replacement = replace(varName, fallback)
4051

4152
if (replacement !== null) {
@@ -47,7 +58,8 @@ function replaceCssVars(str: string, replace: CssVarReplacer): string {
4758
break
4859
}
4960

50-
// Skip past the closing parenthesis and onto the next `var(`
61+
// It can't be replaced so we can avoid unncessary work by skipping over
62+
// the entire var(…) call.
5163
i = j + 1
5264
break
5365
}

0 commit comments

Comments
 (0)