From ddb0beff6626367cc75e4248e47ab2a04017bde6 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 11 Jun 2025 22:18:14 +0200 Subject: [PATCH] Fix missing space around `-` when using `%` regression (#18289) This PR fixes a regression we shipped in v4.1.9, when using arbitrary values and injecting spaces around operator. When you use `w-[calc(100%-var(--foo))]`, you expect that this generates valid CSS: ```css width: calc(100% - var(--foo)); ``` But due to a regression, we generated: ```css width: calc(100%-var(--foo)); ``` Which is invalid CSS. This is because the algorithm we used to know when we had to inject a space around the `-` didn't take the `%` sign into account. We also didn't handle uppercase units like `123PX` properly. This PR fixes both issues. ## Test plan 1. Added a regression test for the `%` 2. Added a regression test for uppercase units like `123PX` Fixes: #18288 --- CHANGELOG.md | 4 +++- .../src/utils/decode-arbitrary-value.test.ts | 6 ++++++ packages/tailwindcss/src/utils/math-operators.ts | 10 +++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1346213ea..e30a1d06d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Fix missing space around `-` when using `%` ([#18289](https://github.com/tailwindlabs/tailwindcss/pull/18289)) ## [4.1.9] - 2025-06-11 diff --git a/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts b/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts index 19025d5b4..0bc4d425c 100644 --- a/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts +++ b/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts @@ -84,6 +84,12 @@ describe('adds spaces around math operators', () => { ['calc(theme(spacing.foo-2))', 'calc(theme(spacing.foo-2))'], ['calc(theme(spacing.foo-bar))', 'calc(theme(spacing.foo-bar))'], + // With percentages + ['calc(100%-var(--foo))', 'calc(100% - var(--foo))'], + + // With uppercase units + ['calc(100PX-theme(spacing.1))', 'calc(100PX - theme(spacing.1))'], + // Preserving CSS keyword tokens like fit-content without splitting around hyphens in complex expressions ['min(fit-content,calc(100dvh-4rem))', 'min(fit-content, calc(100dvh - 4rem))'], [ diff --git a/packages/tailwindcss/src/utils/math-operators.ts b/packages/tailwindcss/src/utils/math-operators.ts index 523fcce20..d31cc3c52 100644 --- a/packages/tailwindcss/src/utils/math-operators.ts +++ b/packages/tailwindcss/src/utils/math-operators.ts @@ -1,5 +1,7 @@ const LOWER_A = 0x61 const LOWER_Z = 0x7a +const UPPER_A = 0x41 +const UPPER_Z = 0x5a const LOWER_E = 0x65 const UPPER_E = 0x45 const ZERO = 0x30 @@ -12,6 +14,7 @@ const OPEN_PAREN = 0x28 const CLOSE_PAREN = 0x29 const COMMA = 0x2c const SPACE = 0x20 +const PERCENT = 0x25 const MATH_FUNCTIONS = [ 'calc', @@ -62,7 +65,12 @@ export function addWhitespaceAroundMathOperators(input: string) { // If we saw a number before, and we see normal a-z character, then we // assume this is a value such as `123px` - else if (valuePos !== null && char >= LOWER_A && char <= LOWER_Z) { + else if ( + valuePos !== null && + (char === PERCENT || + (char >= LOWER_A && char <= LOWER_Z) || + (char >= UPPER_A && char <= UPPER_Z)) + ) { valuePos = i }