Skip to content

Conversation

RobinMalfait
Copy link
Member

@RobinMalfait RobinMalfait commented Oct 9, 2025

The main goal of this PR was to support canonicalization of zero like values. We essentially want to canonicalize -mt-0 as mt-0, but also mt-[0px], mt-[0rem], and other length-like units to just mt-0.

To do this, we had to handle 2 things:

  1. We introduced some more constant folding, including making 0px and 0rem fold to 0. We only do this for length units. We also normalize -0, +0, -0.0 and so on to 0.
  2. While pre-computing utilities in our lookup table, we make sure that we prefer mt-0 over -mt-0 if both result in the same signature.

Moved some of the constant folding logic into its own function and added a bunch of separate tests for it.

Test plan

Added more unit tests where we normalize different zero-like values to 0.

Running the canonicalization logic:

designSystem.canonicalizeCandidates([
  '-m-0',
  '-m-[-0px]',
  '-m-[-0rem]',
  '-m-[0px]',
  '-m-[0rem]',
  'm-0',
  'm-[-0px]',
  'm-[-0rem]',
  'm-[0px]',
  'm-[0rem]',
  'm-[calc(var(--spacing)*0)]',
  'm-[--spacing(0)]',
  'm-[--spacing(0.0)]',
  'm-[+0]',
  'm-[-0]',
  '-m-[-0]',
  '-m-[+0]',
]) // → ['m-0']

Typically each math operator is parsed as a separate word and that's
because it's also typically surrounded by spaces. In case of `/`, this
was parsed as a separator instead of a word including the whitespace (if
any).

The use case we had was to parse `theme(colors.red.500/20%)` where we
don't want `colors.red.500/20%` to be a single word, but we want 3 parts
instead.

This normalizes this a little bit such that all math operators (+, -, *,
/) are just the `word` nodes and any surrounding whitespace will be a
separator node instead.
This is essentially the same as `walk`, but depth first so we handle
leaf nodes first. This helps in situations like constant folding where
we can work our way up.
We will use those in the constant folding logic. We could use
`ValueParser.parse` but we already know we want `word(…)` values so no
need to do the extra work.
This doesn't operate on a declaration, but a declaration value right
now. Could extend this in the future by also passing in the declaration
property if we want more smart fold logic.
This will rely on 2 things:

1. That we properly constant fold length units into `0`
2. That we prefer the "positive" version (`mt-0`) over its negative version (`-mt-0`)
Given they have the same signature.
@RobinMalfait RobinMalfait marked this pull request as ready for review October 9, 2025 11:12
@RobinMalfait RobinMalfait requested a review from a team as a code owner October 9, 2025 11:12
Comment on lines +60 to +61
//
// TODO: Ensure it's safe to do so based on the data types?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fairly safe, and feels like something we only have to add support for when running into actual issues 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me see if I can break this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probaaaably, but once you do, the questions is: how common / real is the actual issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think normalizing things with units to without could cause problems (like rem, em, etc… should probably normalize to 0px instead) but then how would you know margin-left: 0 normalizes to 0px without encoding data type info and that'd be annoying.

All that to say… I think this is fine for now. We can improve this later if need be.

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
@RobinMalfait RobinMalfait enabled auto-merge (squash) October 9, 2025 17:59
@RobinMalfait RobinMalfait merged commit 01d1e98 into main Oct 9, 2025
7 checks passed
@RobinMalfait RobinMalfait deleted the feat/canonicalization-constant-folding branch October 9, 2025 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants