From 92ea5bb8b4bed16b9c94bfffa8fee3274615baa7 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 17 May 2024 16:29:53 -0700 Subject: [PATCH 1/5] Refactor --- .../tailwindcss-language-service/src/util/color.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/tailwindcss-language-service/src/util/color.ts b/packages/tailwindcss-language-service/src/util/color.ts index 420fbfbd..005e2256 100644 --- a/packages/tailwindcss-language-service/src/util/color.ts +++ b/packages/tailwindcss-language-service/src/util/color.ts @@ -58,10 +58,16 @@ function replaceColorVarsWithTheirDefaults(str: string): string { function getColorsInString(str: string): (culori.Color | KeywordColor)[] { if (/(?:box|drop)-shadow/.test(str)) return [] - return Array.from(replaceColorVarsWithTheirDefaults(str).matchAll(colorRegex), (match) => { + function toColor(match: RegExpMatchArray) { let color = match[1].replace(/var\([^)]+\)/, '1') return getKeywordColor(color) ?? culori.parse(color) - }).filter(Boolean) + } + + str = replaceColorVarsWithTheirDefaults(str) + + let possibleColors = str.matchAll(colorRegex) + + return Array.from(possibleColors, toColor).filter(Boolean) } function getColorFromDecls( From 0bb045b5e4a0b2f0dff2eb4dd5ee49c096224447 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 17 May 2024 16:34:28 -0700 Subject: [PATCH 2/5] Replace color vars with fallback value if hex --- packages/tailwindcss-language-service/src/util/color.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/tailwindcss-language-service/src/util/color.ts b/packages/tailwindcss-language-service/src/util/color.ts index 005e2256..ce15574a 100644 --- a/packages/tailwindcss-language-service/src/util/color.ts +++ b/packages/tailwindcss-language-service/src/util/color.ts @@ -55,6 +55,12 @@ function replaceColorVarsWithTheirDefaults(str: string): string { return str.replace(/((?:rgba?|hsla?|(?:ok)?(?:lab|lch))\(\s*)var\([^,]+,\s*([^)]+)\)/gi, '$1$2') } +function replaceHexColorVarsWithTheirDefaults(str: string): string { + // var(--color-red-500, #ef4444) + // -> #ef4444 + return str.replace(/var\([^,]+,\s*(#[^)]+)\)/gi, '$1') +} + function getColorsInString(str: string): (culori.Color | KeywordColor)[] { if (/(?:box|drop)-shadow/.test(str)) return [] @@ -63,6 +69,7 @@ function getColorsInString(str: string): (culori.Color | KeywordColor)[] { return getKeywordColor(color) ?? culori.parse(color) } + str = replaceHexColorVarsWithTheirDefaults(str) str = replaceColorVarsWithTheirDefaults(str) let possibleColors = str.matchAll(colorRegex) From 076fb4d1d7ff86092652f95cfa3990f8a105ba80 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 17 May 2024 16:34:57 -0700 Subject: [PATCH 3/5] Apply alpha-only `color-mix` to color when possible --- .../src/util/color.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/tailwindcss-language-service/src/util/color.ts b/packages/tailwindcss-language-service/src/util/color.ts index ce15574a..a7cf8223 100644 --- a/packages/tailwindcss-language-service/src/util/color.ts +++ b/packages/tailwindcss-language-service/src/util/color.ts @@ -71,6 +71,7 @@ function getColorsInString(str: string): (culori.Color | KeywordColor)[] { str = replaceHexColorVarsWithTheirDefaults(str) str = replaceColorVarsWithTheirDefaults(str) + str = removeColorMixWherePossible(str) let possibleColors = str.matchAll(colorRegex) @@ -251,3 +252,19 @@ export function formatColor(color: culori.Color): string { return culori.formatHex8(color) } + +const COLOR_MIX_REGEX = /color-mix\(in srgb, (.*?) (\d+|\.\d+|\d+\.\d+)%, transparent\)/g + +function removeColorMixWherePossible(str: string) { + return str.replace(COLOR_MIX_REGEX, (match, color, percentage) => { + if (color.startsWith('var(')) return match + + let parsed = culori.parse(color) + if (!parsed) return match + + let alpha = Number(percentage) / 100 + if (Number.isNaN(alpha)) return match + + return culori.formatRgb({ ...parsed, alpha }) + }) +} From eeb229e64ca2d2700040999fc4e91cee69ba44f5 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 17 May 2024 16:37:03 -0700 Subject: [PATCH 4/5] Re-enable tests --- .../tailwindcss-language-server/tests/colors/colors.test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/tailwindcss-language-server/tests/colors/colors.test.js b/packages/tailwindcss-language-server/tests/colors/colors.test.js index c7252de7..5a941719 100644 --- a/packages/tailwindcss-language-server/tests/colors/colors.test.js +++ b/packages/tailwindcss-language-server/tests/colors/colors.test.js @@ -116,7 +116,6 @@ withFixture('v4/basic', (c) => { ], }) - /* testColors('opacity modifier', { text: '
', expected: [ @@ -131,7 +130,6 @@ withFixture('v4/basic', (c) => { }, ], }) - */ testColors('arbitrary value', { text: '
', @@ -148,7 +146,6 @@ withFixture('v4/basic', (c) => { ], }) - /* testColors('arbitrary value and opacity modifier', { text: '
', expected: [ @@ -163,7 +160,6 @@ withFixture('v4/basic', (c) => { }, ], }) - */ testColors('oklch colors are parsed', { text: '
', From fe8f97dd3b496a4a4dc3a87d59b3fee35e5cee42 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 17 May 2024 17:01:30 -0700 Subject: [PATCH 5/5] Make sure gradient utilities show color decorators in v4 --- .../tests/colors/colors.test.js | 124 ++++++++++++++++++ .../src/util/color.ts | 15 +++ 2 files changed, 139 insertions(+) diff --git a/packages/tailwindcss-language-server/tests/colors/colors.test.js b/packages/tailwindcss-language-server/tests/colors/colors.test.js index 5a941719..76cb6f9a 100644 --- a/packages/tailwindcss-language-server/tests/colors/colors.test.js +++ b/packages/tailwindcss-language-server/tests/colors/colors.test.js @@ -87,6 +87,68 @@ withFixture('basic', (c) => { }, ], }) + + testColors('gradient utilities show colors', { + text: '
', + expected: [ + { + range: { start: { line: 0, character: 12 }, end: { line: 0, character: 22 } }, + color: { + alpha: 1, + red: 0, + green: 0, + blue: 0, + }, + }, + { + range: { start: { line: 0, character: 23 }, end: { line: 0, character: 36 } }, + color: { + alpha: 0.5, + red: 0, + green: 0, + blue: 0, + }, + }, + + { + range: { start: { line: 0, character: 37 }, end: { line: 0, character: 46 } }, + color: { + alpha: 1, + red: 0, + green: 0, + blue: 0, + }, + }, + { + range: { start: { line: 0, character: 47 }, end: { line: 0, character: 59 } }, + color: { + alpha: 0.5, + red: 0, + green: 0, + blue: 0, + }, + }, + + { + range: { start: { line: 0, character: 60 }, end: { line: 0, character: 68 } }, + color: { + alpha: 1, + red: 0, + green: 0, + blue: 0, + }, + }, + { + range: { start: { line: 0, character: 69 }, end: { line: 0, character: 80 } }, + color: { + alpha: 0.5, + red: 0, + green: 0, + blue: 0, + }, + }, + ], + }) }) withFixture('v4/basic', (c) => { @@ -175,4 +237,66 @@ withFixture('v4/basic', (c) => { }, ], }) + + testColors('gradient utilities show colors', { + text: '
', + expected: [ + { + range: { start: { line: 0, character: 12 }, end: { line: 0, character: 22 } }, + color: { + alpha: 1, + red: 0, + green: 0, + blue: 0, + }, + }, + { + range: { start: { line: 0, character: 23 }, end: { line: 0, character: 36 } }, + color: { + alpha: 0.5, + red: 0, + green: 0, + blue: 0, + }, + }, + + { + range: { start: { line: 0, character: 37 }, end: { line: 0, character: 46 } }, + color: { + alpha: 1, + red: 0, + green: 0, + blue: 0, + }, + }, + { + range: { start: { line: 0, character: 47 }, end: { line: 0, character: 59 } }, + color: { + alpha: 0.5, + red: 0, + green: 0, + blue: 0, + }, + }, + + { + range: { start: { line: 0, character: 60 }, end: { line: 0, character: 68 } }, + color: { + alpha: 1, + red: 0, + green: 0, + blue: 0, + }, + }, + { + range: { start: { line: 0, character: 69 }, end: { line: 0, character: 80 } }, + color: { + alpha: 0.5, + red: 0, + green: 0, + blue: 0, + }, + }, + ], + }) }) diff --git a/packages/tailwindcss-language-service/src/util/color.ts b/packages/tailwindcss-language-service/src/util/color.ts index a7cf8223..f9784f36 100644 --- a/packages/tailwindcss-language-service/src/util/color.ts +++ b/packages/tailwindcss-language-service/src/util/color.ts @@ -145,6 +145,21 @@ function getColorFromDecls( } function getColorFromRoot(state: State, css: postcss.Root): culori.Color | KeywordColor | null { + // Remove any `@property` rules + css = css.clone() + css.walkAtRules((rule) => { + // Ignore declarations inside `@property` rules + if (rule.name === 'property') { + rule.remove() + } + + // Ignore declarations @supports (-moz-orient: inline) + // this is a hack used for `@property` fallbacks in Firefox + if (rule.name === 'supports' && rule.params === '(-moz-orient: inline)') { + rule.remove() + } + }) + let decls: Record = {} let rule = postcss.rule({