Upgrade: Migrate spacing scale (#14905)

This PR adds migrations for the recent changes to the `--spacing` scale
done in #12263.

There are a few steps that we do to ensure we have the best upgrade
experience:

- If you are overwriting the `spacing` theme with custom values, we now
check if the new values are multiplies of the default spacing scale.
When they are, we can safely remove the overwrite.
- If you are extending the `spacing` theme, we will unset the default
`--spacing` scale and only use the values you provided.
- Any `theme()` function calls are replaced with `calc(var(--spacing) *
multiplier)` unless the values are extending the default scale.

One caveat here is for `theme()` key which can not be replaced with
`var()` (e.g. in `@media` attribute positions). These will not be able
to be replaced with `calc()` either so the following needs to stay
unmigrated:

```css
@media (max-width: theme(spacing.96)) {
  .foo {
    color: red;
  }
}
```

## Test plan

We are mainly testing two scenarios: The JS config _extends_ the
`spacing` namespace and the JS config _overwrites_ the `spacing`
namespace. For both cases we have added an integration test each to
ensure this works as expected. The test contains a mixture of keys (some
of it matching the default multiples, some don't, some have different
scales, and some use non-numeric identifiers). In addition to asserting
on the created CSS `@theme`, we also ensure that `theme()` calls are
properly replaced.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This commit is contained in:
Philipp Spiess 2024-11-07 20:25:21 +01:00 • committed by GitHub
parent 28e46badf7
commit 95c4877200
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 387 additions and 49 deletions

View file

@ -2,7 +2,7 @@ import { atRoot, atRule, decl, styleRule, type AstNode } from './ast'
import type { Candidate, CandidateModifier, NamedUtilityValue } from './candidate'
import type { Theme, ThemeKey } from './theme'
import { DefaultMap } from './utils/default-map'
import { inferDataType, isPositiveInteger } from './utils/infer-data-type'
import { inferDataType, isPositiveInteger, isValidSpacingMultiplier } from './utils/infer-data-type'
import { replaceShadowColors } from './utils/replace-shadow-colors'
import { segment } from './utils/segment'
@ -397,9 +397,7 @@ export function createUtilities(theme: Theme) {
handleBareValue: ({ value }) => {
let multiplier = theme.resolve(null, ['--spacing'])
if (!multiplier) return null
let num = Number(value)
if (num < 0 || num % 0.25 !== 0 || String(num) !== value) return null
if (!isValidSpacingMultiplier(value)) return null
return `calc(${multiplier} * ${value})`
},

View file

@ -328,3 +328,11 @@ export function isPositiveInteger(value: any) {
let num = Number(value)
return Number.isInteger(num) && num >= 0 && String(num) === String(value)
}
/**
* Returns true if the value is either a positive whole number or a multiple of 0.25.
*/
export function isValidSpacingMultiplier(value: any) {
let num = Number(value)
return num >= 0 && num % 0.25 === 0 && String(num) === String(value)
}