Skip to content

Commit 0c8d881

Browse files
authored
Improve percentage canonicalization (#19072)
This PR improves the canonicalization of percentage values such that `[.1]`, `[.10]`, `[10%]` and `[10.0%]` are all treated as the same value. Right now we're only focusing on percentages. We can likely do this for all numbers, but I'm a little afraid of places where you can have multiple numbers separated by multiple dots (think SVGs). ## Test plan 1. Added more tests to cover the new cases. 2. Tested it in a local test project, where you can see the normalization in action. <img width="1383" height="117" alt="image" src="https://github.com/user-attachments/assets/03d99e3a-4404-437b-b458-58f7e8ce60da" />
1 parent efe084b commit 0c8d881

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

packages/tailwindcss/src/canonicalize-candidates.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
254254
['[color:var(--color-red-500)]/[25%]', 'text-red-500/25'],
255255
['[color:var(--color-red-500)]/[100%]', 'text-red-500'],
256256
['[color:var(--color-red-500)]/100', 'text-red-500'],
257+
['[color:var(--color-red-500)]/[10%]', 'text-red-500/10'],
258+
['[color:var(--color-red-500)]/[10.0%]', 'text-red-500/10'],
259+
['[color:var(--color-red-500)]/[.1]', 'text-red-500/10'],
260+
['[color:var(--color-red-500)]/[.10]', 'text-red-500/10'],
257261
// No need for `/50` because that's already encoded in the `--color-primary`
258262
// value
259263
['[color:oklch(62.3%_0.214_259.815)]/50', 'text-primary'],

packages/tailwindcss/src/canonicalize-candidates.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1469,7 +1469,11 @@ function optimizeModifier(designSystem: DesignSystem, candidate: Candidate): Can
14691469
{
14701470
let newModifier: NamedUtilityValue = {
14711471
kind: 'named',
1472-
value: modifier.value.endsWith('%') ? modifier.value.slice(0, -1) : modifier.value,
1472+
value: modifier.value.endsWith('%')
1473+
? modifier.value.includes('.')
1474+
? `${Number(modifier.value.slice(0, -1))}`
1475+
: modifier.value.slice(0, -1)
1476+
: modifier.value,
14731477
fraction: null,
14741478
}
14751479

packages/tailwindcss/src/signatures.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { dimensions } from './utils/dimensions'
99
import { isValidSpacingMultiplier } from './utils/infer-data-type'
1010
import * as ValueParser from './value-parser'
1111

12+
const FLOATING_POINT_PERCENTAGE = /\d*\.\d+(?:[eE][+-]?\d+)?%/g
13+
1214
// Given a utility, compute a signature that represents the utility. The
1315
// signature will be a normalised form of the generated CSS for the utility, or
1416
// a unique symbol if the utility is not valid. The class in the selector will
@@ -59,6 +61,17 @@ export const computeUtilitySignature = new DefaultMap<
5961
if (node.value === undefined || node.property === '--tw-sort') {
6062
replaceWith([])
6163
}
64+
65+
// Normalize percentages by removing unnecessary dots and zeros.
66+
//
67+
// E.g.: `50.0%` → `50%`
68+
else if (node.value.includes('%')) {
69+
FLOATING_POINT_PERCENTAGE.lastIndex = 0
70+
node.value = node.value.replaceAll(
71+
FLOATING_POINT_PERCENTAGE,
72+
(match) => `${Number(match.slice(0, -1))}%`,
73+
)
74+
}
6275
}
6376

6477
// Replace special nodes with its children

0 commit comments

Comments
 (0)