diff --git a/CHANGELOG.md b/CHANGELOG.md index 7614097a3409..d293fd5c130a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgrade: migrate arbitrary modifiers with values without percentage sign to bare values `/[0.16]` -> `/16` ([#18184](https://github.com/tailwindlabs/tailwindcss/pull/18184)) - Upgrade: migrate CSS variable shorthand if fallback value contains function call ([#18184](https://github.com/tailwindlabs/tailwindcss/pull/18184)) +- Upgrade: Migrate negative arbitrary values to negative bare values, e.g.: `mb-[-32rem]` → `-mb-128` ([#18212](https://github.com/tailwindlabs/tailwindcss/pull/18212)) ## [4.1.8] - 2025-05-27 diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-arbitrary-utilities.ts b/packages/@tailwindcss-upgrade/src/codemods/template/migrate-arbitrary-utilities.ts index 63aa9396d875..3007e18deee3 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-arbitrary-utilities.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/template/migrate-arbitrary-utilities.ts @@ -159,7 +159,12 @@ export function migrateArbitraryUtilities( candidate.kind === 'arbitrary' ? candidate.value : (candidate.value?.value ?? null) if (value === null) return - let spacingMultiplier = spacing.get(designSystem)?.get(value) + let spacingMultiplier = spacing.get(designSystem)?.get(value) ?? null + let rootPrefix = '' + if (spacingMultiplier !== null && spacingMultiplier < 0) { + rootPrefix = '-' + spacingMultiplier = Math.abs(spacingMultiplier) + } for (let root of Array.from(designSystem.utilities.keys('functional')).sort( // Sort negative roots after positive roots so that we can try @@ -167,6 +172,8 @@ export function migrateArbitraryUtilities( // `-mt-[0px]` can be translated to `mt-[0px]`. (a, z) => Number(a[0] === '-') - Number(z[0] === '-'), )) { + if (rootPrefix) root = `${rootPrefix}${root}` + // Try as bare value for (let replacementCandidate of parseCandidate(designSystem, `${root}-${value}`)) { yield replacementCandidate diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate.test.ts b/packages/@tailwindcss-upgrade/src/codemods/template/migrate.test.ts index 49a40d016834..35de32a09bc2 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/template/migrate.test.ts @@ -69,6 +69,11 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s', // the fallback contains functions. The fallback should also be migrated to // the newest syntax. ['bg-[--my-color,theme(colors.red.500)]', 'bg-(--my-color,var(--color-red-500))'], + + // Both the positive and negative versions of arbitrary utilities should be + // converted to the bare value version. + ['mb-[32rem]', 'mb-128'], + ['mb-[-32rem]', '-mb-128'], ])(testName, async (candidate, result) => { if (strategy === 'with-variant') { candidate = `focus:${candidate}`