Skip to content

Commit 7537e34

Browse files
authored
Ignore --tw- variables during internal signature computation (#19156)
This PR improves some of the signature computation logic. Right now, when you want to convert `[font-weight:400]` to `font-normal` it's not going to work because the signatures don't like up: ```css /* [font-weight:400] */ .x { font-weight: 400; } /* font-normal */ .x { --tw-font-weight: 400; font-weight: 400; } ``` So this PR essentially ignores `--tw-{property}` _if_ the `{property}` exists with the exact same value. The main reason we have this, is to make composition of utilities easier. As with any of these upgrades, they are the expected behavior in most cases, but there could always be a case where you don't want this, but that's why the upgrade tool requires you to review each change before applying it. Intellisense will recommend the simplified class, but it's up to you to decide if you want to apply it or not. There is a known edge case for `leading-{num}`, because the property is `line-height` and the CSS variable is `--tw-leading`. Right now we map `--tw-leading` to `line-height` but we can also update the leading classes to use `--tw-line-height` instead but that feels like a bigger breaking change _if_ people rely on these internal CSS variables...
1 parent 66c18ca commit 7537e34

File tree

3 files changed

+25
-15
lines changed

3 files changed

+25
-15
lines changed

integrations/upgrade/js-config.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ test(
167167
"
168168
--- src/index.html ---
169169
<div
170-
class="[letter-spacing:var(--tracking-super-wide)] [line-height:var(--leading-super-loose)]"
170+
class="tracking-super-wide leading-super-loose"
171171
></div>
172172
<div class="text-super-red/super-opaque leading-super-loose"></div>
173173

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
253253
'[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]/50',
254254
'[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]/50',
255255
],
256+
257+
// If a utility sets `property` and `--tw-{property}` with the same value,
258+
// we can ignore the `--tw-{property}`. This is just here for composition.
259+
// This means that we should be able to upgrade the one _without_ to the one
260+
// _with_ the variable
261+
['[font-weight:400]', 'font-normal'],
262+
['[line-height:0]', 'leading-0'],
263+
['[border-style:solid]', 'border-solid'],
256264
])(testName, async (candidate, expected) => {
257265
await expectCanonicalization(
258266
css`

packages/tailwindcss/src/signatures.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import { isValidSpacingMultiplier } from './utils/infer-data-type'
1111
import * as ValueParser from './value-parser'
1212
import { walk, WalkAction } from './walk'
1313

14-
const FLOATING_POINT_PERCENTAGE = /\d*\.\d+(?:[eE][+-]?\d+)?%/g
15-
1614
export enum SignatureFeatures {
1715
None = 0,
1816
ExpandProperties = 1 << 0,
@@ -101,29 +99,33 @@ function canonicalizeAst(ast: AstNode[], options: SignatureOptions) {
10199
let { rem, designSystem } = options
102100

103101
walk(ast, {
104-
enter(node) {
102+
enter(node, ctx) {
105103
// Optimize declarations
106104
if (node.kind === 'declaration') {
107105
if (node.value === undefined || node.property === '--tw-sort') {
108106
return WalkAction.Replace([])
109107
}
110108

109+
// Ignore `--tw-{property}` if `{property}` exists with the same value
110+
if (node.property.startsWith('--tw-')) {
111+
if (
112+
(ctx.parent?.nodes ?? []).some(
113+
(sibling) =>
114+
sibling.kind === 'declaration' &&
115+
node.value === sibling.value &&
116+
node.important === sibling.important &&
117+
!sibling.property.startsWith('--tw-'),
118+
)
119+
) {
120+
return WalkAction.Replace([])
121+
}
122+
}
123+
111124
if (options.features & SignatureFeatures.ExpandProperties) {
112125
let replacement = expandDeclaration(node, options.features)
113126
if (replacement) return WalkAction.Replace(replacement)
114127
}
115128

116-
// Normalize percentages by removing unnecessary dots and zeros.
117-
//
118-
// E.g.: `50.0%` → `50%`
119-
if (node.value.includes('%')) {
120-
FLOATING_POINT_PERCENTAGE.lastIndex = 0
121-
node.value = node.value.replaceAll(
122-
FLOATING_POINT_PERCENTAGE,
123-
(match) => `${Number(match.slice(0, -1))}%`,
124-
)
125-
}
126-
127129
// Resolve theme values to their inlined value.
128130
if (node.value.includes('var(')) {
129131
node.value = resolveVariablesInValue(node.value, designSystem)

0 commit comments

Comments
 (0)