Skip to content

Commit 9e436f7

Browse files
authored
Try to canonicalize any arbitrary utility to a bare value (#19379)
This PR adds an improvement to our canonicalization logic when dealing with arbitrary values. When trying to canonicalize utilities, we make use of the intellisense suggestions list where we typically use multiples of the spacing scale. This means that a value like `gap-[128px]` gets properly canonicalized to `gap-32`. However, when you try a value that we typically don't suggest such as `gap-[116px]` then it doesn't get canonicalized at all. This PR fixes that by trying to use the spacing scale and convert `116px / 4px` and try the `gap-29` utility instead. This is done by canonicalizing the incoming arbitrary value and the spacing multipliers such that `--spacing: 0.25rem` and `--spacing: 4px` both work as expected. ### Test plan 1. Added some tests with a spacing scale of `0.25rem` (which is the default) 2. Added some tests with the same spacing scale in a different unit `4px` 3. Added some tests with a different spacing scale `1px` Also had to update 1 test that now gets canonicalized properly, e.g.: `w-[124px]` → `w-31`.
1 parent 117433a commit 9e436f7

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- Preserve case of theme keys from JS configs and plugins ([#19337](https://github.com/tailwindlabs/tailwindcss/pull/19337))
1818
- Write source maps correctly on the CLI when using `--watch` ([#19373](https://github.com/tailwindlabs/tailwindcss/pull/19373))
1919
- Upgrade: Handle `future` and `experimental` config keys ([#19344](https://github.com/tailwindlabs/tailwindcss/pull/19344))
20+
- Try to canonicalize any arbitrary utility to a bare value ([#19379](https://github.com/tailwindlabs/tailwindcss/pull/19379))
2021

2122
### Added
2223

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,24 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
530530
// Default spacing scale
531531
['w-[64rem]', 'w-256', '0.25rem'],
532532

533+
// Non-suggested numbers
534+
['gap-[7.25rem]', 'gap-29', '0.25rem'],
535+
['gap-[calc(7rem+0.25rem)]', 'gap-29', '0.25rem'],
536+
['gap-[116px]', 'gap-29', '0.25rem'],
537+
538+
// Non-suggested numbers, with the same spacing scale with different
539+
// units
540+
['gap-[7.25rem]', 'gap-29', '4px'],
541+
['gap-[calc(7rem+0.25rem)]', 'gap-29', '4px'],
542+
['gap-[116px]', 'gap-29', '4px'],
543+
544+
// Non-suggested numbers, with a different spacing scale
545+
['gap-[7.25rem]', 'gap-116', '1px'],
546+
['gap-[calc(7rem+0.25rem)]', 'gap-116', '1px'],
547+
['gap-[116px]', 'gap-116', '1px'],
548+
533549
// Keep arbitrary value if units are different
534-
['w-[124px]', 'w-[124px]', '0.25rem'],
550+
['w-[124px]', 'w-31', '0.25rem'],
535551

536552
// Keep arbitrary value if bare value doesn't fit in steps of .25
537553
['w-[0.123rem]', 'w-[0.123rem]', '0.25rem'],

packages/tailwindcss/src/canonicalize-candidates.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,43 @@ function arbitraryUtilities(candidate: Candidate, options: InternalCanonicalizeO
990990
candidate.kind === 'arbitrary' ? candidate.value : (candidate.value?.value ?? null)
991991
if (value === null) return
992992

993+
// Try to canonicalize any incoming arbitrary value. Canonicalization of
994+
// `rem` and `px` values will be converted to `px`, so we have to
995+
// canonicalize the spacing multiplier as well.
996+
if (
997+
options.signatureOptions.rem !== null &&
998+
candidate.kind === 'functional' &&
999+
candidate.value?.kind === 'arbitrary'
1000+
) {
1001+
let spacingMultiplier = designSystem.resolveThemeValue('--spacing')
1002+
if (spacingMultiplier !== undefined) {
1003+
// Canonicalizing the spacing multiplier allows us to handle both
1004+
// `--spacing: 0.25rem` and `--spacing: 4px` values correctly.
1005+
let canonicalizedSpacingMultiplier = constantFoldDeclaration(
1006+
spacingMultiplier,
1007+
options.signatureOptions.rem,
1008+
)
1009+
if (canonicalizedSpacingMultiplier !== null) {
1010+
let canonicalizedValue = constantFoldDeclaration(value, options.signatureOptions.rem)
1011+
let valueDimension = dimensions.get(canonicalizedValue)
1012+
let spacingMultiplierDimension = dimensions.get(canonicalizedSpacingMultiplier)
1013+
if (
1014+
valueDimension &&
1015+
spacingMultiplierDimension &&
1016+
valueDimension[1] === spacingMultiplierDimension[1] && // Ensure the units match
1017+
spacingMultiplierDimension[0] !== 0
1018+
) {
1019+
let bareValue = `${valueDimension[0] / spacingMultiplierDimension[0]}`
1020+
if (isValidSpacingMultiplier(bareValue)) {
1021+
yield Object.assign({}, candidate, {
1022+
value: { kind: 'named', value: bareValue, fraction: null },
1023+
})
1024+
}
1025+
}
1026+
}
1027+
}
1028+
}
1029+
9931030
let spacingMultiplier = designSystem.storage[SPACING_KEY]?.get(value) ?? null
9941031
let rootPrefix = ''
9951032
if (spacingMultiplier !== null && spacingMultiplier < 0) {

0 commit comments

Comments
 (0)