84 Commits

Author SHA1 Message Date
Robin Malfait
71fb9cdf59
Improve @tailwindcss/upgrade and pnpm workspaces support (#18065)
This PR fixes an issue where an error such as:

<img width="1702" alt="image"
src="https://github.com/user-attachments/assets/4e6f75c7-3182-4497-939e-96cff08c55ae"
/>

Will be thrown during the upgrade process. This can happen when you are
using `pnpm` and your CSS file includes a `@import "tailwindcss";`. In
this scenario, `tailwindcss` will be loaded from a shared `.pnpm` folder
outside of the current working directory.

In this case, we are also not interested in migrating _that_ file, but
we also don't want the upgrade process to just crash.

I didn't see an option to ignore errors like this, so wrapped it in a
try/catch instead.

It also fixes another issue where if you are using a pnpm workspace and
run the upgrade tool from the root, then it throws you an error that you
cannot add dependencies to the workspace root unless `-w` or
`--workspace-root` flags are passed.

For this, we disable the check entirely using the
`--ignore-workspace-root-check` flag. If we always used the
`--workspace-root` flag, then the dependencies would always be added to
the root, regardless of where you are running the script from which is
not what we want.

## Test plan

Before:

<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/78246876-3eb6-4539-a557-d3d366f1b3a3"
/>

After:

<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/a65e4421-d7c5-4d83-b35d-934708543e25"
/>

Before:
 
<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/53772661-2c4a-4212-84d9-a556a0ad320f"
/>

After:

<img width="1816" alt="image"
src="https://github.com/user-attachments/assets/5bfaf20e-34b8-44fd-9b59-e72d36738879"
/>
2025-05-19 12:47:08 +02:00
Robin Malfait
c7d368b3c4
Do not migrate declarations in <style> blocks (#18057)
This PR improves the upgrade tool by making sure that we don't migrate
CSS declarations in `<style>…</style>` blocks.

We do this by making sure that:

1. We detect a declaration, the current heuristic is that the candidate
is:
   - Preceded by whitespace
   - Followed by a colon and whitespace

   ```html
   <style>
   .foo {
       flex-shrink: 0;
      ^           ^^
   }
   </style>
   ```

2. We are in a `<style>…</style>` block

   ```html
   <style>
   ^^^^^^
   .foo {
       flex-shrink: 0;
   }
   </style>
   ^^^^^^^^
   ```

The reason we have these 2 checks is because just relying on the first
heuristic alone, also means that we will not be migrating keys in JS
objects, because they typically follow the same structure:

```js
let classes = {
 flex: 0,
^    ^^
}
```

Another important thing to note is that we can't just ignore anything in
between `<style>…</style>` blocks, because you could still be using
`@apply` that we _do_ want to migrate.

Last but not least, the first heuristics is not perfect either. If you
are writing minified CSS then this will likely fail if there is no
whitespace around the candidate.

But my current assumption is that nobody should be writing minified CSS,
and minified CSS will very likely be generated and gitignored. In either
situation, replacements in minified CSS will not be any worse than it is
today.

I'm open to suggestions for better heuristics.

## Test plan

1. Added an integration test that verifies that we do migrate `@apply`
and don't migrate the `flex-shrink: 0;` declaration.


Fixes: #17975
2025-05-16 12:53:34 +02:00
Robin Malfait
1ada8e0f22
Make candidate template migrations faster (#18025)
This PR makes the migrations for templates much faster. To make this
work, I also had to move things around a bit (so you might want to check
this PR commit by commit). I also solved an issue by restructuring the
code.

### Performance

For starters, we barely applied any caching when migrating candidates
from α to β. The problem with this is that in big projects the same
candidates will appear _everywhere_, so caching is going to be useful
here.

One of the reasons why we didn't do any caching is that some migrations
were checking if a migration is actually safe to do. To do this, we were
checking the `location` (the location of the candidate in the template).
Since this location is unique for each template, caching was not
possible.

So the first order of business was to hoist the `isSafeMigration` check
up as the very first thing we do in the migration.

If we do this first, then the only remaining code relies on the
`DesignSystem`, `UserConfig` and `rawCandidate`.

In a project, the `DesignSystem` and `UserConfig` will be the same
during the migration, only the `rawCandidate` will be different which
means that we can move all this logic in a good old `DefaultMap` and
cache the heck out of it.

Running the numbers on our Tailwind Plus repo, this results in:
```
    Total seen candidates: 2 211 844
Total migrated candidates: 7 775 
               Cache hits: 1 575 700
```

That's a lot of work we _don't_ have to do. Looking at the timings, the
template migration step goes from ~45s to ~10s because of this.

Another big benefit of this is that this makes migrations _actually_
safe. Before we were checking if a migration was safe to do in specific
migrations. But other migrations were still printing the candidate which
could still result in an unsafe migration.

For example when migrating the `blur` and the `shadow` classes, the
`isSafeMigration` was used. But if the input was `!flex` then the safety
check wasn't even checked in this specific migration.

### Safe migrations

Also made some changes to the `isSafeMigration` logic itself. We used to
start by checking the location, but thinking about the problem again,
the actual big problem we were running into is classes that are short
like `blur`, and `shadow` because they could be used in other contexts
than a Tailwind CSS class.

Inverting this logic means that more specific Tailwind CSS classes will
very likely _not_ cause any issues at all.

For example:
- If you have variants: `hover:focus:flex`
- If you have arbitrary properties: `[color:red]`
- If you have arbitrary values: `bg-[red]`
- If you have a modifier: `bg-red-500/50`
- If you have a `-` in the name: `bg-red-500`

Even better if we can't parse a candidate at all, we can skip the
migrations all together.

This brings us to the issue in #17974, one of the issues was already
solved by just hoisting the `isSafeMigration`. But to make the issue was
completely solved I also made sure that in Vue attributes like
`:active="…"` are also considered unsafe (note: `:class` is allowed).

Last but not least, in case of the `!duration` that got replaced with
`duration!` was solved by verifying that the candidate actually produces
valid CSS. We can compute the signature for this class.

The reason this wasn't thrown away earlier is because we can correctly
parse `duration` but `duration` on its own doesn't exist,
`duration-<number>` does exist as a functional utility which is why it
parsed in the first place.

Fixes: #17974

## Test plan

1. Ran the tool on our Tailwind UI Templates repo to compare the new
output with the "old" behavior and there were no differences in output.
2. Ran the tool on our Tailwind Plus repo, and the template migration
step went from ~45s to ~10s.
3. Added additional tests to verify the issues in #17974 are fixed.


[ci-all] let's run this on all CI platforms...
2025-05-15 11:17:39 +00:00
Philipp Spiess
e57a2f5a3a
Change casing of utilities with named values to kebab-case to match u… (#18017)
Fixes #16156

## Summary

This PR adds a new 3 -> 4 template migration that changes the casing of
in both utility values and modifier values from camelCase to kebab-case
to match the updated CSS variable names.

## Test plan

- Added integration test, see the diff in the PR.
2025-05-14 14:51:51 +02:00
Philipp Spiess
ef2e6c71fe
Upgrade: Migrate outline class (#17996)
This PR adds a migration from `outline` to `outline-solid` for the v3 ->
v4 upgrade tool.

## Test plan

- Added integration test
2025-05-13 14:20:40 +02:00
Robin Malfait
4e4275638f
Design system driven upgrade migrations (#17831)
This PR introduces a vastly improved upgrade migrations system, to
migrate your codebase and modernize your utilities to make use of the
latest variants and utilities.

It all started when I saw this PR the other day:
https://github.com/tailwindlabs/tailwindcss/pull/17790

I was about to comment "Don't forget to add a migration". But I've been
thinking about a system where we can automate this process away. This PR
introduces this system.

This PR introduces upgrade migrations based on the internal Design
System, and it mainly updates arbitrary variants, arbitrary properties
and arbitrary values.

## The problem

Whenever we ship new utilities, or you make changes to your CSS file by
introducing new `@theme` values, or adding new `@utility` rules. It
could be that the rest of your codebase isn't aware of that, but you
could be using these values.

For example, it could be that you have a lot of arbitrary properties in
your codebase, they look something like this:

```html
<div class="[color-scheme:dark] [text-wrap:balance]"></div>
```

Whenever we introduce new features in Tailwind CSS, you probably don't
keep an eye on the release notes and update all of these arbitrary
properties to the newly introduced utilities.

But with this PR, we can run the upgrade tool:

```console
npx -y @tailwindcss/upgrade@latest
```

...and it will upgrade your project to use the new utilities:

```html
<div class="scheme-dark text-balance"></div>
```

It also works for arbitrary values, for example imagine you have classes
like this:

```html
<!-- Arbitrary property -->
<div class="[max-height:1lh]"></div>

<!-- Arbitrary value -->
<div class="max-h-[1lh]"></div>
```

Running the upgrade tool again:

```console
npx -y @tailwindcss/upgrade@latest
```

... gives you the following output:

```html
<!-- Arbitrary property -->
<div class="max-h-lh"></div>

<!-- Arbitrary value -->
<div class="max-h-lh"></div>
```

This is because of the original PR I mentioned, which introduced the
`max-h-lh` utilities.

A nice benefit is that this output only has 1 unique class instead of 2,
which also potentially reduces the size of your CSS file.

It could also be that you are using arbitrary values where you (or a
team member) didn't even know an alternative solution existed.

E.g.:

```html
<div class="w-[48rem]"></div>
```

After running the upgrade tool you will get this:

```html
<div class="w-3xl"></div>
```

We can go further though. Since the release of Tailwind CSS v4, we
introduced the concept of "bare values". Essentially allowing you to
type a number on utilities where it makes sense, and we produce a value
based on that number.

So an input like this:

```html
<div class="border-[123px]"></div>
```

Will be optimized to just:

```html
<div class="border-123"></div>
```

This can be very useful for complex utilities, for example, how many
times have you written something like this:

```html
<div class="grid-cols-[repeat(16,minmax(0,1fr))]"></div>
```

Because up until Tailwind CSS v4, we only generated 12 columns by
default. But since v4, we can generate any number of columns
automatically.

Running the migration tool will give you this:

```html
<div class="grid-cols-16"></div>
```

### User CSS

But, what if I told you that we can keep going...

In [Catalyst](https://tailwindcss.com/plus/ui-kit) we often use classes
that look like this for accessibility reasons:

```html
<div class="text-[CanvasText] bg-[Highlight]"></div>
```

What if you want to move the `CanvasText` and `Highlight` colors to your
CSS:

```css
@import "tailwincdss";

@theme {
  --color-canvas: CanvasText;
  --color-highlight: Highlight;
}
```

If you now run the upgrade tool again, this will be the result:

```html
<div class="text-canvas bg-highlight"></div>
```

We never shipped a `text-canvas` or `bg-highlight` utility, but the
upgrade tool uses your own CSS configuration to migrate your codebase.

This will keep your codebase clean, consistent and modern and you are in
control.

Let's look at one more example, what if you have this in a lot of
places:

```html
<div class="[scrollbar-gutter:stable]"></div>
```

And you don't want to wait for the Tailwind CSS team to ship a
`scrollbar-stable` (or similar) feature. You can add your own utility:

```css
@import "tailwincdss";

@utility scrollbar-stable {
  scrollbar-gutter: stable;
}
```

```html
<div class="scrollbar-stable"></div>
```

## The solution — how it works

There are 2 big things happening here:

1. Instead of us (the Tailwind CSS team) hardcoding certain migrations,
we will make use of the internal `DesignSystem` which is the source of
truth for all this information. This is also what Tailwind CSS itself
uses to generate the CSS file.

   The internal `DesignSystem` is essentially a list of all:

   1. The internal utilities
   2. The internal variants
   3. The default theme we ship
   4. The user CSS
      1. With custom `@theme` values
      2. With custom `@custom-variant` implementations
      3. With custom `@utility` implementations
2. The upgrade tool now has a concept of `signatures`

The signatures part is the most interesting one, and it allows us to be
100% sure that we can migrate your codebase without breaking anything.

A signature is some unique identifier that represents a utility. But 2
utilities that do the exact same thing will have the same signature.

To make this work, we have to make sure that we normalize values. One
such value is the selector. I think a little visualization will help
here:

| UTILITY          | GENERATED SIGNATURE     |
| ---------------- | ----------------------- |
| `[display:flex]` | `.x { display: flex; }` |
| `flex`           | `.x { display: flex; }` |

They have the exact same signature and therefore the upgrade tool can
safely migrate them to the same utility.

For this we will prefer the following order:

1. Static utilities — essentially no brackets. E.g.: `flex`,
`grid-cols-2`
2. Arbitrary values — e.g.: `max-h-[1lh]`, `border-[2px]`
3. Arbitrary properties — e.g.: `[color-scheme:dark]`, `[display:flex]`

We also have to canonicalize utilities to there minimal form.
Essentially making sure we increase the chance of finding a match.

```
[display:_flex_] → [display:flex] → flex
[display:_flex]  → [display:flex] → flex
[display:flex_]  → [display:flex] → flex
[display:flex]   → [display:flex] → flex
```

If we don't do this, then the signatures will be slightly different, due
to the whitespace:

| UTILITY            | GENERATED SIGNATURE       |
| ------------------ | ------------------------- |
| `[display:_flex_]` | `.x { display:  flex ; }` |
| `[display:_flex]`  | `.x { display:  flex; }`  |
| `[display:flex_]`  | `.x { display: flex ; }`  |
| `[display:flex]`   | `.x { display: flex; }`   |

### Other small improvements

A few other improvements are for optimizing existing utilities:

1. Remove unnecessary data types. E.g.:

   - `bg-[color:red]` -> `bg-[red]`
- `shadow-[shadow:inset_0_1px_--theme(--color-white/15%)]` ->
`shadow-[inset_0_1px_--theme(--color-white/15%)]`

This also makes use of these signatures and if dropping the data type
results in the same signature then we can safely drop it.

Additionally, if a more specific utility exists, we will prefer that
one. This reduced ambiguity and the need for data types.

   - `bg-[position:123px]` → `bg-position-[123px]`
   - `bg-[123px]` → `bg-position-[123px]`
   - `bg-[size:123px]` → `bg-size-[123px]`


2. Optimizing modifiers. E.g.:
   - `bg-red-500/[25%]` → `bg-red-500/25`
   - `bg-red-500/[100%]` → `bg-red-500`
   - `bg-red-500/100` → `bg-red-500`

3. Hoist `not` in arbitrary variants

- `[@media_not_(prefers-color-scheme:dark)]:flex` →
`not-[@media_(prefers-color-scheme:dark)]:flex` → `not-dark:flex` (in
case you are using the default `dark` mode implementation

4. Optimize raw values that could be converted to bare values. This uses
the `--spacing` variable to ensure it is safe.

   - `w-[64rem]` → `w-256`

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-05-02 23:18:06 +02:00
Robin Malfait
dbc8023a08
Do not sort and format stylesheets that didn't change (#17824)
This PR improves the upgrade tooling at tiny bit to make sure that as
long as we didn't change any of the stylesheets, that we also don't sort
internal nodes and/or format the stylesheet at all.

This is important in case the Prettier rules are different or if a
totally different formatter is used.

Essentially, if we didn't have to change the stylesheets because of a
migration, we don't want to change it due to a formatter either.
2025-04-29 17:07:35 +00:00
Robin Malfait
8e826b18f3
Ensure @tailwindcss/upgrade runs on Tailwind CSS v4 projects and is idempotent (#17717)
This PR ensures that the `@tailwindcss/upgrade` tool works on existing
Tailwind CSS v4 projects. This PR also ensures that the upgrade tool is
idempotent, meaning that it can be run multiple times and it should
result in the same output.

One awesome feature this unlocks is that you can run the upgrade tool on
your codebase at any time and upgrade classes if you still have some
legacy syntaxes, such as `bg-[var(--my-color)]`, in your muscle memory.

One small note: If something changed in the first run, re-running will
not work immediately because your git repository will not be clean and
the upgrade tool requires your git repo to be clean. But once you
verified and committed your changes, the upgrade tool will be
idempotent.

Idempotency is guaranteed by ensuring that some migrations are skipped
by checking what version of Tailwind CSS you are on _before_ the version
is upgraded.

For the Tailwind CSS version: We will resolve `tailwindcss` itself to
know the _actual_ version that is installed (the one resolved from
`node_modules`). Not the one available in your package.json. Your
`package.json` could be out of sync if you reverted changes but didn't
run `npm install` yet.

Back to Idempotency:

For example, we have migrations where we change the variant order of
stacked variants. If we would run these migrations every time you run
the upgrade tool then we would be flip-flopping the order every run.

See: https://tailwindcss.com/docs/upgrade-guide#variant-stacking-order

Another example is where we rename some utilities. For example, we
rename:

| Before      | After       |
| ----------- | ----------- |
| `shadow`    | `shadow-sm` |
| `shadow-sm` | `shadow-xs` |

Notice how we have `shadow-sm` in both the `before` and `after` column.

If we would run the upgrade tool again, then we would eventually migrate
your original `shadow` to `shadow-sm` (first run) and then to
`shadow-xs` (second run). Which would result in the wrong shadow.

See: https://tailwindcss.com/docs/upgrade-guide#renamed-utilities

---

The order of upgrade steps changed a bit as well to make the internals
are easier to work with and reason about.

1. Find CSS files
2. Link JS config files (if you are in a Tailwind CSS v3 project)
3. Migrate the JS config files (if you are in a Tailwind CSS v3 project)
4. Upgrade Tailwind CSS to v4 (or the latest version at that point)
5. Migrate the stylesheets (we used to migrate the source files first)
6. Migrate the source files

This is done so that step 5 and 6 will always operate on a Tailwind CSS
v4 project and we don't need to check the version number again. This is
also necessary because your CSS file will now very likely contain
`@import "tailwindcss";` which doesn't exist in Tailwind CSS v3.

This also means that we can rely on the same internals that Tailwind CSS
actually uses for locating the source files. We will use
`@tailwindcss/oxide`'s scanner to find the source files (and it also
keeps your custom `@source` directives into account).

This PR also introduces a few actual migrations related to recent
features and changes we shipped.

1. We migrate deprecated classes to their new names:

   | Before                | After                 |
   | --------------------- | --------------------- |
   | `bg-left-top`         | `bg-top-left`         |
   | `bg-left-bottom`      | `bg-bottom-left`      |
   | `bg-right-top`        | `bg-top-right`        |
   | `bg-right-bottom`     | `bg-bottom-right`     |
   | `object-left-top`     | `object-top-left`     |
   | `object-left-bottom`  | `object-bottom-left`  |
   | `object-right-top`    | `object-top-right`    |
   | `object-right-bottom` | `object-bottom-right` |

   Introduced in:

   - https://github.com/tailwindlabs/tailwindcss/pull/17378
   - https://github.com/tailwindlabs/tailwindcss/pull/17437

2. We migrate simple arbitrary variants to their dedicated variant:

   | Before                  | After               |
   | ----------------------- | ------------------- |
   | `[&:user-valid]:flex`   | `user-valid:flex`   |
   | `[&:user-invalid]:flex` | `user-invalid:flex` |

   Introduced in:

   - https://github.com/tailwindlabs/tailwindcss/pull/12370

3. We migrate `@media` variants to their dedicated variant:

| Before | After |
| ----------------------------------------------------- |
------------------------- |
| `[@media_print]:flex` | `print:flex` |
| `[@media(prefers-reduced-motion:no-preference)]:flex` |
`motion-safe:flex` |
| `[@media(prefers-reduced-motion:reduce)]:flex` | `motion-reduce:flex`
|
| `[@media(prefers-contrast:more)]:flex` | `contrast-more:flex` |
| `[@media(prefers-contrast:less)]:flex` | `contrast-less:flex` |
| `[@media(orientation:portrait)]:flex` | `portrait:flex` |
| `[@media(orientation:landscape)]:flex` | `landscape:flex` |
| `[@media(forced-colors:active)]:flex` | `forced-colors:flex` |
| `[@media(inverted-colors:inverted)]:flex` | `inverted-colors:flex` |
| `[@media(pointer:none)]:flex` | `pointer-none:flex` |
| `[@media(pointer:coarse)]:flex` | `pointer-coarse:flex` |
| `[@media(pointer:fine)]:flex` | `pointer-fine:flex` |
| `[@media(any-pointer:none)]:flex` | `any-pointer-none:flex` |
| `[@media(any-pointer:coarse)]:flex` | `any-pointer-coarse:flex` |
| `[@media(any-pointer:fine)]:flex` | `any-pointer-fine:flex` |
| `[@media(scripting:none)]:flex` | `noscript:flex` |

The new variants related to `inverted-colors`, `pointer`, `any-pointer`
and `scripting` were introduced in:

   - https://github.com/tailwindlabs/tailwindcss/pull/11693
   - https://github.com/tailwindlabs/tailwindcss/pull/16946
   - https://github.com/tailwindlabs/tailwindcss/pull/11929
   - https://github.com/tailwindlabs/tailwindcss/pull/17431

   This also applies to the `not` case, e.g.:

| Before | After |
| --------------------------------------------------------- |
----------------------------- |
| `[@media_not_print]:flex` | `not-print:flex` |
| `[@media_not(prefers-reduced-motion:no-preference)]:flex` |
`not-motion-safe:flex` |
| `[@media_not(prefers-reduced-motion:reduce)]:flex` |
`not-motion-reduce:flex` |
| `[@media_not(prefers-contrast:more)]:flex` | `not-contrast-more:flex`
|
| `[@media_not(prefers-contrast:less)]:flex` | `not-contrast-less:flex`
|
| `[@media_not(orientation:portrait)]:flex` | `not-portrait:flex` |
| `[@media_not(orientation:landscape)]:flex` | `not-landscape:flex` |
| `[@media_not(forced-colors:active)]:flex` | `not-forced-colors:flex` |
| `[@media_not(inverted-colors:inverted)]:flex` |
`not-inverted-colors:flex` |
| `[@media_not(pointer:none)]:flex` | `not-pointer-none:flex` |
| `[@media_not(pointer:coarse)]:flex` | `not-pointer-coarse:flex` |
| `[@media_not(pointer:fine)]:flex` | `not-pointer-fine:flex` |
| `[@media_not(any-pointer:none)]:flex` | `not-any-pointer-none:flex` |
| `[@media_not(any-pointer:coarse)]:flex` |
`not-any-pointer-coarse:flex` |
| `[@media_not(any-pointer:fine)]:flex` | `not-any-pointer-fine:flex` |
| `[@media_not(scripting:none)]:flex` | `not-noscript:flex` |

For each candidate, we run a set of upgrade migrations. If at the end of
the migrations the original candidate is still the same as the new
candidate, then we will parse & print the candidate one more time to
pretty print into consistent classes. Luckily parsing is cached so there
is no real downside overhead.

Consistency (especially with arbitrary variants and values) will reduce
your CSS file because there will be fewer "versions" of your class.

Concretely, the pretty printing will apply changes such as:

| Before                 | After             |
| ---------------------- | ----------------- |
| `bg-[var(--my-color)]` | `bg-(--my-color)` |
| `bg-[rgb(0,_0,_0)]`    | `bg-[rgb(0,0,0)]` |

Another big important reason for this change is that these classes on
their own
would have been migrated _if_ another migration was relevant for this
candidate.
This means that there are were some inconsistencies. E.g.:

| Before | After | Reason |
| ----------------------- | ---------------------- |
------------------------------------ |
| `!bg-[var(--my-color)]` | `bg-(--my-color)!` | Because the `!` is in
the wrong spot |
| `bg-[var(--my-color)]` | `bg-[var(--my-color)]` | Because no
migrations rand |

As you can see, the way the `--my-color` variable is used, is different.
This
changes will make sure it will now always be consistent:
| Before | After |
| ----------------------- | ---------------------- |
| `!bg-[var(--my-color)]` | `bg-(--my-color)!` |
| `bg-[var(--my-color)]` | `bg-(--my-color)` |

Yay!

Of course, if you don't want these more cosmetic changes, you can always
ignore the upgrade and revert these changes and only commit the changes
you want.

# Test plan

- All existing tests still pass.
- But I had to delete 1 test (we tested that Tailwind CSS v3 was
required).
- And had to mock the `version.isMajor` call to ensure we run the
individual migration tests correctly.
- Added new tests to test:
  1. Migrating Tailwind CSS v4 projects works
  1. Idempotency of the upgrade tool

[ci-all]
2025-04-22 11:10:46 -04:00
Justin Wong
c0af1e2129
Fix fontSize array upgrade (#17630)
Fixes #17622.

Adds a specific handling case in `themeableValues()` in
`packages/tailwindcss/src/compat/apply-config-to-theme.ts`. It seems
like this has unique handling in v3 for an array value, whereby the
second value is treated as a `line-height`.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-04-11 13:23:54 +02:00
Teddy Bradford
3e41e9ffe6
Replace currentColor with currentcolor (lowercase) (#17510)
Replaces `currentColor` with `currentcolor` (lowercase) to match what's
defined in [CSS Color Module Level
4](https://www.w3.org/TR/css-color-4/#currentcolor-color) and
[MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#currentcolor_keyword)
(see: https://github.com/mdn/content/pull/16592).

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-04-03 16:09:12 +02:00
Philipp Spiess
156afc6d67
Improve compatibility with Safari 15 (#17435)
This PR improves the compatibility with Tailwind CSS v4 with unsupported
browsers with the goal to greatly improve compatibility with Safari 15.

To make this work, this PR makes the following changes to all code

- Change `oklab(…)` default theme values to use a percentage in the
first place (so instead of `--color-red-500: oklch(0.637 0.237 25.331);`
we now define it as `--color-red-500: oklch(63.7% 0.237 25.331);` since
this syntax has much broader support on Safari).
- Polyfill `@property` with a `@supports` query targeting older versions
of Safari and Firefox *
- Create fallbacks for the `color-mix(…)` function that use _inlined
color values from your theme_ so that they can be computed a compile
time by `lightningcss`. These fallbacks will convert to srgb to increase
compatibility.
- Create fallbacks for the _relative color_ feature used in the new
shadow utilities and using `color-mix(…)` in case _relative color_ is
applied on `currentcolor` (due to limited browser support)
- Create fallbacks for gradient interpolation methods (e.g. to support
`bg-linear-to-r/oklab`)
- Polyfill `@media` queries range syntax.

## A simplified example

Given this example CSS input:

```css
@import 'tailwindcss';
@source inline('from-cyan-500/50 bg-linear-45');
```

Here's the updated output CSS including the newly added polyfills and
updated `oklab` values:

```css
.bg-linear-45 {
  --tw-gradient-position: 45deg;
  background-image: linear-gradient(var(--tw-gradient-stops));
}

@supports (background-image: linear-gradient(in lab, red, red)) {
  .bg-linear-45 {
    --tw-gradient-position: 45deg in oklab;
  }
}

.from-cyan-500\\/50 {
  --tw-gradient-from: oklab(71.5% -.11682 -.08247 / .5);
  --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
}

@supports (color: color-mix(in lab, red, red)) {
  .from-cyan-500\\/50 {
    --tw-gradient-from: color-mix(in oklab, var(--color-cyan-500) 50%, transparent);
  }
}

:root, :host {
  --color-cyan-500: oklch(71.5% .143 215.221);
}

@supports (((-webkit-hyphens: none)) and (not (margin-trim: 1lh))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
  @layer base {
    *, :before, :after, ::backdrop {
      --tw-gradient-position: initial;
      --tw-gradient-from: #0000;
      --tw-gradient-via: #0000;
      --tw-gradient-to: #0000;
      --tw-gradient-stops: initial;
      --tw-gradient-via-stops: initial;
      --tw-gradient-from-position: 0%;
      --tw-gradient-via-position: 50%;
      --tw-gradient-to-position: 100%;
    }
  }
}

@property --tw-gradient-position {
  syntax: "*";
  inherits: false
}

@property --tw-gradient-from {
  syntax: "<color>";
  inherits: false;
  initial-value: #0000;
}

@property --tw-gradient-via {
  syntax: "<color>";
  inherits: false;
  initial-value: #0000;
}

@property --tw-gradient-to {
  syntax: "<color>";
  inherits: false;
  initial-value: #0000;
}

@property --tw-gradient-stops {
  syntax: "*";
  inherits: false
}

@property --tw-gradient-via-stops {
  syntax: "*";
  inherits: false
}

@property --tw-gradient-from-position {
  syntax: "<length-percentage>";
  inherits: false;
  initial-value: 0%;
}

@property --tw-gradient-via-position {
  syntax: "<length-percentage>";
  inherits: false;
  initial-value: 50%;
}

@property --tw-gradient-to-position {
  syntax: "<length-percentage>";
  inherits: false;
  initial-value: 100%;
}
```

## \* A note on `@property` polyfills and CSS modules

On Next.js, CSS module files are required to be _pure_, meaning that all
selectors must either be scoped to a class or an ID. Fortunatnyl for us,
this does not apply to `@property` rules which we've been using before
to initialize CSS variables.

However, since we're now bringing back the `@property` polyfills, that
would cause unexpected rules to be exported from the CSS file as this:

```css
@reference "tailwindcss";

.skew {
  @apply skew-7;
}
```

Would turn to the following file:

```css
.skew {
  /* … */
}
@supports (/*…*/) {
  @layer base {
    *, :before, :after, ::backdrop {
      --tw-gradient-position: initial;
    }
  }
}
@property /* … */ 
```

Notice that this adds a `*` selector which is not considered pure.

Unfortunately there is no way for us to silence this warning or work
around it, as the dependency causing this errors
([`postcss-modules-local-by-default`](https://github.com/css-modules/postcss-modules-local-by-default))
is bundled into Next.js. To work around crashes, these polyfills will
not apply to CSS modules processed by the PostCSS extension for now.

## Testing on tailwindcss.com

To see the changes in effect, take a look at this screencast that
compares tailwindcss.com on iOS 15.5 with a version that has the patches
of this PR applied:

https://github.com/user-attachments/assets/1279d6f5-3c63-4f30-839c-198a789f4292

## Test plan

- Tested on tailwindcss.com via a preview build:
https://tailwindcss-com-git-legacy-browsers-tailwindlabs.vercel.app/
- Updated tests
- Ensure we also test on Chrome 111, Safari 16.4, Firefox 128 to
make sure we have no regressions. Also tested on Safari 16.4, 15.5, 18.0
2025-04-01 13:33:22 +02:00
Philipp Spiess
294952f170
Handle BOM (#16800)
Resolves #15662 
Resolves #15467

## Test plan

Added integration tests for upgrade tooling (which already worked
surprisingly?) and CLI.
2025-02-25 16:07:16 +01:00
Philipp Spiess
ec1d7d4b85
Upgrade: Use latest tag for packages (#16620) 2025-02-18 11:57:51 +01:00
Philipp Spiess
a1e083afc5
Upgrade: Handle darkMode value with block syntax (#16507)
Closes #16171

This PR handles `darkMode` variant configs containing braces (so
creating sub-rules) the same way we handle it in the interop layer.
Since the interop layer runs inside the `addVariant` API that we do not
run here, I instead oped to copy the one liner.

## Test plan

Updated one of the migration tests to include a rule that wasn't working
before. Ensured the new output works via
https://play.tailwindcss.com/nR99uhKtv3
2025-02-14 16:48:52 +01:00
Robin Malfait
a659159bf1
Bump and pin prettier (#16382)
This PR bumps the Prettier dependencies, and also pins the version.

Noticed that a PR with a single empty commit started failing at the time
of writing this
(https://github.com/tailwindlabs/tailwindcss/pull/16306). This is
because prettier released a new minor version which results in slightly
different output.

Let's bump prettier and handle the differences, but also pin the version
to avoid this in the future.
2025-02-10 10:54:45 +01:00
Robin Malfait
4035ab0b76
Implement @variant (#15663)
This PR replaces `@variant` with `@custom-variant` for registering
custom variants via your CSS.

In addition, this PR introduces `@variant` that can be used in your CSS
to use a variant while writing custom CSS.

E.g.:

```css
.btn {
  background: white;

  @variant dark {
    background: black;
  }
}
```

Compiles to:

```css
.btn {
  background: white;
}

@media (prefers-color-scheme: dark) {
  .btn {
    background: black;
  }
}
```

For backwards compatibility, the `@variant` rules that don't have a body
and are
defined inline:

```css
@variant hocus (&:hover, &:focus);
```

And `@variant` rules that are defined with a body and a `@slot`:

```css
@variant hocus {
  &:hover, &:focus {
    @slot;
  }
}
```

Will automatically be upgraded to `@custom-variant` internally, so no
breaking changes are introduced with this PR.

---

TODO:
- [x] ~~Decide whether we want to allow multiple variants and if so,
what syntax should be used. If not, nesting `@variant <variant> {}` will
be the way to go.~~ Only a single `@variant <variant>` can be used, if
you want to use multiple, nesting should be used:

```css
.foo {
  @variant hover {
    @variant focus {
      color: red;
    }
  }
}
```
2025-01-21 10:20:35 -05:00
Robin Malfait
82589eb2c1
Migrate theme(…) to --theme(…), migrate calc(var(--spacing)*x) to --spacing(x) (#15579)
This PR improves the codemod tool to simplify 2 things:

1. Whenever you have a `theme(…)` call, we try to change it to a
`var(…)`, but if that doesn't work for some reason, we will make sure to
at least convert it to the more modern `--theme(…)`.
2. When converting `theme(spacing.2)`, we used to convert it to
`calc(var(--spacing)*2)`, but now we will convert it to `--spacing(2)`
instead.
2025-01-09 17:17:07 +01:00
Philipp Spiess
d4f693f7f3
Upgrade: Do not extract class names from functions (#15566)
This PR prevents the migration of utilities detected in function names,
e.g.: the use of `shadow` inside `filter: 'drop-shadow(…)'`.

## Test plan

Have content like this in a project you're migrating using the upgrade
tool:

```js
{
  filter: 'drop-shadow(0 0 0.5rem #000)'
}
```

This was verified by adding unit tests to the specific codemods and
adding an integration test.
2025-01-07 15:31:48 +01:00
Robin Malfait
2a29c29441
Improve integration tests (stability + performance) (#15125)
This PR improves the integration tests in two ways:
1. Make the integration tests more reliable and thus less flakey
2. Make the integration tests faster (by introducing concurrency)

Tried a lot of different things to make sure that these tests are fast
and stable.

---

The biggest issue we noticed is that some tests are flakey, these are
tests with long running dev-mode processes where watchers are being used
and/or dev servers are created.
To solve this, all the tests that spawn a process look at stdout/stderr
and wait for a message from the process to know whether we can start
making changes.

For example, in case of an Astro project, you get a `watching for file
changes` message. In case of Nuxt project you can wait for an `server
warmed up in` and in case of Next.js there is a `Ready in` message.

These depend on the tools being used, so this is hardcoded per test
instead of a magically automatic solution.

These messages allow us to wait until all the initial necessary work,
internal watchers and/or dev servers are setup before we start making
changes to the files and/or request CSS stylesheets before the server(s)
are ready.

---

Another improvement is how we setup the dev servers. Before, we used to
try and get a free port on the system and use a `--port` flag or a
`PORT` environment variable. Instead of doing this (which is slow), we
rely on the process itself to show a URL with a port. Basically all
tools will try to find a free port if the default port is in use. We can
then use the stdout/stderr messages to get the URL and the port to use.

To reduce the amount of potential conflicts in ports, we used to run
every test and every file sequentially to basically guarantee that ports
are free. With this new approach where we rely on the process, I noticed
that we don't really run into this issue again (I reran the tests
multiple times and they were always stable)

<img width="316" alt="image"
src="https://github.com/user-attachments/assets/b75ddab4-f919-4995-85d0-f212b603e5c2"
/>
Note: these tests run Linux, Windows and macOS in this branch just for
testing purposes. Once this is done, we will only run Linux tests on PRs
and run all 3 of them on the `next` branch.

We do make the tests concurrent by default now, which in theory means
that there could be conflicts (which in practice means that the process
has to do a few more tries to find a free port). To reduce these
conflicts, we split up the integration tests such that Vite, PostCSS,
CLI, … tests all run in a separate job in the GitHub actions workflow.

<img width="312" alt="image"
src="https://github.com/user-attachments/assets/fe9a58a1-98eb-4d9b-8845-a7c8a7af5766"
/>

Comparing this branch against the `next` branch, this is what CI looks
like right now:

| `next` | `feat/improve-integration-tests` |
| --- | --- |
| <img width="594" alt="image"
src="https://github.com/user-attachments/assets/540d21eb-ab03-42e8-9f6f-b3a071fc7635"
/> | <img width="672" alt="image"
src="https://github.com/user-attachments/assets/8ef2e891-08a1-464b-9954-4153174ebce7"
/> |

There also was a point in time where I introduced sequential tests such
that all spawned processes still run after each other, but so far I
didn't run into issues if we keep them concurrent so I dropped that
code.

Some small changes I made to make things more reliable:
1. When relying on stdout/stderr messages, we split lines on `\n` and we
strip all the ANSI escapes which allows us to not worry about special
ANSI characters when finding the URL or a specific message to wait for.
2. Once a test is done, we `child.kill()` the spawned process. If that
doesn't work, for whatever reason, we run a `child.kill('SIGKILL')` to
force kill the process. This could technically lead to some memory or
files not being cleaned up properly, but once CI is done, everything is
thrown away anyway.
3. As you can see in the screenshots, I used some nicer names for the
workflows.

| `next` | `feat/improve-integration-tests` |
| --- | --- |
| <img width="276" alt="image"
src="https://github.com/user-attachments/assets/e574bb53-e21b-4619-9cdb-515431b255b9"
/> | <img width="179" alt="image"
src="https://github.com/user-attachments/assets/8bc75119-fb91-4500-a1d0-bd09f74c93ad"
/> |

They also look a bit nicer in the PR overview as well:
<img width="929" alt="image"
src="https://github.com/user-attachments/assets/04fc71fc-74b0-4e7c-9047-2aada664efef"
/>

The very last commit just filters out Windows and macOS tests again for
PRs (but they are executed on the `next` branch.

---

### Nest steps

I think for now we are in a pretty good state, but there are some things
we can do to further improve everything (mainly make things faster) but
aren't necessary. I also ran into issue while trying it so there is more
work to do.

1. More splits — instead of having a Vite folder and PostCSS folder, we
can go a step further and have folders for Next.js, Astro, Nuxt, Remix,
…
2. Caching — right now we have to run the build step for every OS on
every "job". We can re-use the work here by introducing a setup job that
the other jobs rely on. @thecrypticace and I tried it already, but were
running into some Bun specific Standalone CLI issues when doing that.
3. Remote caching — we could re-enable remote caching such that the
`build` step can be full turbo (e.g.: after a PR is merged in `next` and
we run everything again)
2024-12-12 13:48:56 +01:00
Robin Malfait
a18ae8e734
Migrate backdrop-blur-* utilities (#15242)
This PR adds missing migrations for the `backdrop-blur-*` utilities. It
uses the same values from your theme as `blur` does.
2024-11-29 11:11:47 -05:00
Philipp Spiess
317cf089b9
Upgrade: Migrate prefixed group and peer classes (#15208)
Resolves #15193

This PR fixes an issue where `group` and `peer` would not have their
prefixes migrated as part of the upgrade script. We do this by
registering `group` and `peer` as utilities during the codemods. This
way, `parseCandidate` will find these classes to be valid Tailwind
candidates and the prefix can be migrated just like any other utility.

## Test Plan

Tried it with the v3 upgrade playground in the repo and it worked fine: 

<img width="1257" alt="Screenshot 2024-11-27 at 12 17 25"
src="https://github.com/user-attachments/assets/1ee101e1-1d6a-4ce0-b0d4-8d51e5f6b0d2">

I've also added tests to our prefix upgrade integration test and the
prefix migration unit tests.
2024-11-27 11:34:27 -05:00
Jonathan Reinink
dad9ac6209
Revert new default form styles (#15100)
Closes #15071

This PR reverts the changes in #15036 which add consistent base styles
for buttons and form controls to Preflight.

While this felt like a good idea (for the reasons explained in that PR),
practically this is just too disruptive of a change for people upgrading
from v3 to v4.

While updating some of our projects to v4 we found ourselves adding
classes to undo styles more often than we expected, and it also felt
inconsistent to have to use a different set of classes to style a link
or a button when we wanted them to look the same.

We also decided it feels a little strange that you could change the
border color of an element without ever specifying that it should have a
border, for example this just feels a little wrong:

```html
<button class="border-blue-500">
```

We also needed to set a default `color-scheme` value for any of this
stuff to work which breaks the ability to use the `color-scheme` meta
tag.

Since this change was a fairly major breaking change and we aren't
feeling much benefit from it, it doesn't feel worth making this change
for v4.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-11-22 08:55:05 -05:00
Philipp Spiess
6c85327908
Convert opacity keys to percentage values (#15067)
This PR improves compatibility for named `opacity` theme values. One of
the changes in v4 is that we use the CSS `color-mix()` function to apply
opacity to colors. This, however, is limited to percentage values only:

```css
color: color-mix(in oklch, var(--color-red-500) 50%, transparent);
/*                                              ^^^             */
/*                          This needs to be a percentage value */
```

In v3, however, it was common to specify custom opacity values as
decimal numbers. That's also what we did in our default config:


6069a81187/stubs/config.full.js (L703-L725)

This PR improves interop with these values by:

1. Converting decimal numbers in the range of `[0, 1]` to their
percentage value equivalent when using the interop layer.
2. Adjusts the codemod that migrates `opacity` theme keys to Tailwind v4
theme variables to include the same conversion.
3. Furthermore, due to the added support of named opacity modifers, we
can also drop theme keys that would now be the default. For example the
following config would not be necessary in v4 as the opacity modifier
would accept the value `50` by default:
    ```js
    module.exports = {
      theme: {
        opacity: {
          50: 0.5
        }
      }
    }
    ```

## Test Plan

Added a new integration test for the codemod and a unit test for the
interop layer. I also re-ran the codemod on the Commit template and it's
now working as expected (left is v3, right is v4):

<img width="2560" alt="Screenshot 2024-11-21 at 17 25 32"
src="https://github.com/user-attachments/assets/f0c87243-ca80-4c39-ae5e-c1ab48fbe614">
2024-11-21 19:06:58 +01:00
Philipp Spiess
61c3718017
Add color to form reset snippet (#15064)
While testing the latest alpha release across Tailwind v3 projects, we
noticed one regression in relation to the default color of `<button>`
elements. In v3, the reset would change the default to `inherit` but in
v4 we would _not include it in the reset snippet inserted by the upgrade
too_.

This PR changes the upgrade snippet to include it:

```diff
 /*
   In Tailwind CSS v4, basic styles are applied to form elements by default. To
   maintain compatibility with v3, the following resets have been added:
 */
 @layer base {
   input,
   textarea,
   select,
   button {
     border: 0px solid;
     border-radius: 0;
     padding: 0;
+    color: inherit;
     background-color: transparent;
   }
 }
```

This PR also ensures that there's a newline between the two code
snippets.

## Test Plan

### Before


![image](https://github.com/user-attachments/assets/00b5ea23-a6f2-4f7c-93c9-62aac841ce97)

### After

<img width="1354" alt="Screenshot 2024-11-21 at 15 42 58"
src="https://github.com/user-attachments/assets/9a4503fe-683f-4d08-abf2-7dd111ed5428">
2024-11-21 16:14:52 +01:00
Robin Malfait
c53a5258f8
Upgrade: Migrate ring to ring-3 (#15063)
This PR adds a codemod for migrating `ring` to `ring-3` if it is safe to
do so.


# Test plan

Added a `ring` to the Catalyst project and then migrated it:
<img width="864" alt="image"
src="https://github.com/user-attachments/assets/163d9faa-c712-494e-b9d7-106508157915">
2024-11-21 14:20:56 +01:00
Robin Malfait
3cf5c2df79
Disallow empty arbitrary values (#15055)
This PR makes the candidate parser more strict by not allowing empty
arbitrary values.

Examples that are not allowed anymore:

- `bg-[]` — arbitrary value
- `bg-()` — arbitrary value, var shorthand
- `bg-[length:]` — arbitrary value, with typehint
- `bg-(length:)` — arbitrary value, with typehint, var shorthand
- `bg-red-500/[]` — arbitrary modifier
- `bg-red-500/()` — arbitrary modifier, var shorthand
- `data-[]:flex` — arbitrary value for variant
- `data-():flex` — arbitrary value for variant, var shorthand
- `group-visible/[]:flex` — arbitrary modifier for variant
- `group-visible/():flex` — arbitrary modifier for variant, var
shorthand

If you are trying to trick the parser by injecting some spaces like
this:

- `bg-[_]`

Then that is also not allowed.
2024-11-21 13:47:13 +01:00
Philipp Spiess
fcf948f8c8
Add consistent base styles for buttons and form controls (#15036)
This PR introduces consistent base styles for buttons and form controls
in Tailwind CSS v4.

## Motivation

In v3, form elements lack default styles, which can be
confusing—especially when certain elements, like a text input without a
placeholder or value, are rendered completely invisible on the page.

The goal of this change is to provide reasonable default styles for
buttons, inputs, selects, and textareas that are (mostly) consistent
across all browsers while remaining easy to customize with your own
styles.

This improvement should make Tailwind more accessible for developers new
to the framework and more convenient in scenarios where you need to
quickly create demos (e.g., using Tailwind Play).

## Light and dark mode support

These styles support both light and dark mode, achieved using the
`light-dark()` CSS function. While browser support for this function is
still somewhat limited, Lightning CSS transpiles it to a CSS
variable-based approach that works in older browsers.

For this approach to function correctly, a default `color-scheme` must
be set in your CSS (as explained in [the Lightning CSS
documentation](https://lightningcss.dev/transpilation.html#light-dark()-color-function)).
This PR addresses this requirement by setting the `color-scheme` to
`light` on the `html` element in Preflight.

<img width="1712" alt="image"
src="https://github.com/user-attachments/assets/dba56368-1427-47b3-9419-7c2f6313a944">

<img width="1709" alt="image"
src="https://github.com/user-attachments/assets/3d84fcd2-9606-4626-8e03-164a1dce9018">

## Breaking changes

While we don’t expect these changes to significantly impact v3 users
upgrading to v4, there may be minor differences for those relying on the
simpler v3 styles.

For example, Preflight now applies a `border-radius` to buttons and form
controls. If you weren’t explicitly setting the border radius to `0` in
your project, you’ll need to do so to restore the previous look.

Thankfully, reverting to the v3 styles is straightforward—just add the
following reset to your CSS:

```css
@layer base {
  input,
  textarea,
  select,
  button {
    border: 0px solid;
    border-radius: 0;
    padding: 0;
    background-color: transparent;
  }
}
```

It’s worth noting that this reset doesn't touch the
`::file-selector-button` styles that were added in this PR. This is
because it's not possible to reliably "undo" these styles and restore
the original user-agent styles (which is what was used in v3), as these
are different in each browser. However, these new styles actually match
the defaults in most browsers pretty closely, so hopefully this just
won't be an issue.

## Codemod

This PR includes a codemod that automatically inserts the above
mentioned v3 reset to help avoid breaking changes during the upgrade.
The codemod will insert the following CSS:

```css
/*
  In Tailwind CSS v4, basic styles are applied to form elements by default. To
  maintain compatibility with v3, the following resets have been added:
*/
@layer base {
  input,
  textarea,
  select,
  button {
    border: 0px solid;
    border-radius: 0;
    padding: 0;
    background-color: transparent;
  }
}
```

## Testing

These changes have been tested across a wide range of browsers,
including Chrome, Safari, Firefox, Edge, and Opera on macOS and Windows,
as well as Safari, Chrome, Firefox, and several lesser-known browsers on
iOS and Android.

However, some quirks still exist in certain mobile browsers, such as iOS
Safari, which adds too much bottom padding below date and time inputs:

<img width="1548" alt="Screenshot 2024-11-20 at 3 57 20 PM"
src="https://github.com/user-attachments/assets/507c7724-ac41-4634-a2b3-61ac4917ebce">

The only reliable way to address these issues is by applying
`appearance: none` to these form controls. However, this felt too
opinionated for Preflight, so we’ve opted to leave such adjustments to
user-land implementations.

---------

Co-authored-by: Jonathan Reinink <jonathan@reinink.ca>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-11-21 11:21:31 +01:00
Robin Malfait
f19afd91e5
Improve root file detection (#15048)
This PR fixes an issue where the Tailwind root file detection was wrong.

Whenever a CSS file contains any of the `@tailwind` directives or an
`@import` to any of the Tailwind files, the file is considered a
Tailwind root file.

If multiple CSS files are part of the same tree, then we make the
nearest common parent the root file.

This root file will be the file where we add `@config` and/or inject
other changes during the migration process.

However, if your folder structure looked like this:

```css
/* index.css */
@import "./base.css";
@import "./typography.css";
@import "tailwindcss/components"; /* This makes index.css a root file */
@import "./utilities.css";

/* base.css */
@tailwind base; /* This makes base.css a root file */

/* utilities.css */
@tailwind utilities; /* This makes utilities.css a root file */
```

Then we computed that `index.css` nad `base.css` were considered root
files even though they belong to the same tree (because `base.css` is
imported by `index.css`).

This PR fixes that behaviour by essentially being less smart, and just
checking again if any sheets are part of the same tree.

# Test plan:

Added an integration test that covers this scenario and fails before the
fix.

Also ran it on our tailwindcss.com codebase.

| Before | After |
| --- | --- |
| <img width="1072" alt="image"
src="https://github.com/user-attachments/assets/8ee99a59-335e-4221-b368-a8cd81e85191">
| <img width="1072" alt="image"
src="https://github.com/user-attachments/assets/fe5acae4-d3fc-43a4-bd31-eee768a3a6a5">
|

(Yes, I know the migration still fails, but that's a different issue.)
2024-11-20 00:20:40 +01:00
Jordan Pittman
b73c746e6e
Implement compat for <alpha-value> from v3 (#15033)
This implements backwards compatibility for colors that use the old
`<alpha-value>` feature from v3. We can do this by replacing
`<alpha-value>` with `1` because we use `color-mix` to actually apply
opacity modifiers in v4.
2024-11-19 10:01:45 -05:00
Philipp Spiess
b3d1cbb72f
Upgrade: Error when project is already using Tailwind CSS v4 (#15015)
In some local testing we ran the `@tailwindcss/upgrade` command twice in
a row. It would be great to get some feedback that this is not working,
so this PR now checks if it can resolve the installed version of
`tailwindcss` and if it can, it requires it to be < 4 (you can bypass
this check with `--force`).

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-11-19 15:53:02 +01:00
Robin Malfait
08c6c96f02
Improve multi-root @config linking (#15001)
This PR improves the discoverability of Tailwind config files when we
are trying to link them to your CSS files.

When you have multiple "root" CSS files in your project, and if they
don't include an `@config` directive, then we tried to find the Tailwind
config file in your current working directory.

This means that if you run the upgrade command from the root of your
project, and you have a nested folder with a separate Tailwind setup,
then the nested CSS file would link to the root Tailwind config file.

Visually, you can think of it like this:

```
.
├── admin
│   ├── src
│   │   └── styles
│   │       └── index.css       <-- This will be linked to (1)
│   └── tailwind.config.js      (2)
├── src
│   └── styles
│       └── index.css           <-- This will be linked to (1)
└── tailwind.config.js          (1)
```

If you run the upgrade command from the root of your project, then the
`/src/styles/index.css` will be linked to `/tailwind.config.js` which is
what we expect.

But `/admin/src/styles/index.css` will _also_ be linked to
`/tailwind.config.js`

With this PR we improve this behavior by looking at the CSS file, and
crawling up the parent tree. This mens that the new behavior looks like
this:

```
.
├── admin
│   ├── src
│   │   └── styles
│   │       └── index.css       <-- This will be linked to (2)
│   └── tailwind.config.js      (2)
├── src
│   └── styles
│       └── index.css           <-- This will be linked to (1)
└── tailwind.config.js          (1)
```

Now `/src/styles/index.css` will be linked to `/tailwind.config.js`, and
`/admin/src/styles/index.css` will be linked to
`/admin/tailwind.config.js`.

When we discover the Tailwind config file, we will also print a message
to the user to let them know which CSS file is linked to which Tailwind
config file.

This should be a safe improvement because if your Tailwind config file
had a different name, or if it lived in a sibling folder then Tailwind
wouldn't find it either and you already required a `@config "…";`
directive in your CSS file to point to the correct file.

In the unlikely event that it turns out that 2 (or more) CSS files
resolve to the same to the same Tailwind config file, then an upgrade
might not be safe and some manual intervention might be needed. In this
case, we will show a warning about this.

<img width="1552" alt="image"
src="https://github.com/user-attachments/assets/7a1ad11d-18c5-4b7d-9a02-14f0116ae955">


Test plan:
---

- Added an integration test that properly links the nearest Tailwind
config file by looking up the tree
- Added an integration test that resolves 2 or more CSS files to the
same config file, resulting in an error where manual intervention is
needed
- Ran it on the Tailwind UI codebase

Running this on Tailwind UI's codebase it looks like this:

<img width="1552" alt="image"
src="https://github.com/user-attachments/assets/21785428-5e0d-47f7-80ec-dab497f58784">

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-11-18 16:43:44 +00:00
Robin Malfait
3dc3bad781
Re-introduce automatic var injection shorthand (#15020)
This PR re-introduces the automatic var injection feature.

For some backstory, we used to support classes such as `bg-[--my-color]`
that resolved as-if you wrote `bg-[var(--my-color)]`.

The is issue is that some newer CSS properties accepts dashed-idents
(without the `var(…)`). This means that some properties accept
`view-timeline-name: --my-name;` (see:
https://developer.mozilla.org/en-US/docs/Web/CSS/view-timeline-name).

To make this a tiny bit worse, these properties _also_ accept
`var(--my-name-reference)` where the variable `--my-name-reference`
could reference a dashed-ident such as `--my-name`.

This makes the `bg-[--my-color]` ambiguous because we don't know if you
want `var(--my-color)` or `--my-color`.

With this PR, we bring back the automatic var injection feature as
syntactic sugar, but we use a different syntax to avoid the ambiguity.
Instead of `bg-[--my-color]`, you can now write `bg-(--my-color)` to get
the same effect as `bg-[var(--my-color)]`.

This also applies to modifiers, so `bg-red-500/[var(--my-opacity)]` can
be written as `bg-red-500/(--my-opacity)`. To go full circle, you can
rewrite `bg-[var(--my-color)]/[var(--my-opacity)]` as
`bg-(--my-color)/(--my-opacity)`.

---

This is implemented as syntactical sugar at the parsing stage and
handled when re-printing. Internally the system (and every plugin) still
see the proper `var(--my-color)` value.

Since this is also handled during printing of the candidate, codemods
don't need to be changed but they will provide the newly updated syntax.

E.g.: running this on the Catalyst codebase, you'll now see changes like
this:
<img width="542" alt="image"
src="https://github.com/user-attachments/assets/8f0e26f8-f4c9-4cdc-9f28-52307c38610e">

Whereas before we converted this to the much longer
`min-w-[var(--button-width)]`.

---

Additionally, this required some changes to the Oxide scanner to make
sure that `(` and `)` are valid characters for arbitrary-like values.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-11-18 15:47:48 +01:00
Robin Malfait
57f87be440
Resolve imports from CSS file (#15010)
This PR adds an improvement to the upgrade tool to make sure that if you
pass a single CSS file, that the upgrade tool resolves all the imports
in that file and processes them as well.


Test plan:
---

Created a project where `index.css` imports `other.css`. Another
`leave-me-alone.css` is created to proof that this file is _not_
changed. Running the upgrade guide using `index.css` also migrates
`other.css` but not `leave-me-alone.css`.

Here is a video so you don't have to manually create it:



https://github.com/user-attachments/assets/20decf77-77d2-4a7c-8ff1-accb1c77f8c1
2024-11-15 22:06:52 +01:00
Philipp Spiess
5edf6c7dc0
Ensure clients pin the tailwindcss version (#15011)
We noticed that in the current alpha 34 release, the `package.json` file
of the `@tailwindcss/node` package only defines `tailwindcss` as a dev
dependency. This makes it very easy for version mismatches to happen
when a v3 version (or an earlier v4 alpha for that matter) was installed
in the same project:

```json
{
  "name": "@tailwindcss/node",
  "version": "4.0.0-alpha.34",
  "description": "A utility-first CSS framework for rapidly building custom user interfaces.",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/tailwindlabs/tailwindcss.git",
    "directory": "packages/@tailwindcss-node"
  },
  "bugs": "https://github.com/tailwindlabs/tailwindcss/issues",
  "homepage": "https://tailwindcss.com",
  "files": [
    "dist/"
  ],
  "publishConfig": {
    "provenance": true,
    "access": "public"
  },
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.js"
    },
    "./require-cache": {
      "types": "./dist/require-cache.d.ts",
      "default": "./dist/require-cache.js"
    },
    "./esm-cache-loader": {
      "types": "./dist/esm-cache.loader.d.mts",
      "default": "./dist/esm-cache.loader.mjs"
    }
  },
  "devDependencies": {
    "tailwindcss": "4.0.0-alpha.34"
  },
  "dependencies": {
    "enhanced-resolve": "^5.17.1",
    "jiti": "^2.0.0-beta.3"
  },
  "scripts": {
    "build": "tsup-node",
    "dev": "pnpm run build -- --watch"
  }
}
```

Furthermore, we were trying to fix issues where our integration test
setup could not install `tailwindcss@3` because of how we did pnpm
overrides.

This PR fixes this by:

- Ensuring every client that calls into `tailwindcss` core marks it as a
version-pinned dependency. You are still required to install
`tailwindcss` in your project along side a client (e.g.
`@tailwindcss/vite`) but we now only use your installed version for
importing the respective `.css` files. For the core logic, we are now
requiring each package to use `tailwindcss` at the same version. This
should help resolve issues like
https://github.com/tailwindlabs/tailwindcss/discussions/14652
- We tried to eliminate the dependency on `tailwindcss` from the
`@tailwindcss/upgrade` package. Unfortunately this is not possible to do
right now because we need to load the CSS files from v4 to create the
right environment. In a future version we could bundle the required CSS
files with `@tailwidncss/upgrade` but it doesn't seem necessary for now.
- We then changed our integration test overrides to only override the
`tailwindcss` package that are dependencies of the known list of
packages that we have `tailwindcss` dependencies on: `@tailwindcss/node`
and `@tailwindcss/upgrade`. This ensures that we can install v3 of
`tailwindcss` in the integration tests and it will work. Something we
want to do for some upgrade tests.

# Test plan

Integration work again. Furthermore we added a quick setup with the CLI
using the local tarballs and ensured it works:

```bash
pnpm init
pnpm install ../../tailwindcss/dist/tailwindcss-cli.tgz 
pnpm install ../../tailwindcss/dist/tailwindcss.tgz 
echo '@import "tailwindcss";' > index.css
echo '<div class="underline"></div>' > index.html
pnpm tailwindcss -i index.css -o out.css
cat out.css
```
2024-11-15 17:18:48 +01:00
Philipp Spiess
890f18de93
Add codemod and interop for legacy container component configu (#14999)
This PR adds support for handling v3 [`container` customizations
](https://tailwindcss.com/docs/container#customizing). This is done by
adding a custom utility to extend the core `container` utility. A
concrete example can be taken from the added integration test.

### Input

```ts
/** @type {import('tailwindcss').Config} */
export default {
  content: ['./src/**/*.html'],
  theme: {
    container: {
      center: true,
      padding: {
        DEFAULT: '2rem',
        '2xl': '4rem',
      },
      screens: {
        md: '48rem', // Matches a default --breakpoint
        xl: '1280px',
        '2xl': '1536px',
      },
    },
  },
}
```

### Output

```css
@import "tailwindcss";

@utility container {
  margin-inline: auto;
  padding-inline: 2rem;

  @media (width >= theme(--breakpoint-sm)) {
    max-width: none;
  }

  @media (width >= 48rem) {
    max-width: 48rem;
  }

  @media (width >= 1280px) {
    max-width: 1280px;
  }

  @media (width >= 1536px) {
    max-width: 1536px;
    padding-inline: 4rem;
  }
}
````


## Test Plan

This PR adds extensive tests to the compat layer as part of unit tests.
Additionally it does at a test to the codemod setup that shows that the
right `@utility` code is generated. Furthermore I compared the
implementation against v3 on both the compat layer and the custom
`@utility`:


https://github.com/user-attachments/assets/44d6cbfb-4861-4225-9593-602b719f628f
2024-11-14 12:19:21 -05:00
Robin Malfait
4079059420
Add missing layer(…) to imports above Tailwind directives (#14982)
This PR fixes an issue where imports above Tailwind directives didn't
get a `layer(…)` argument.

Given this CSS:
```css
@import "./typography.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
```

It was migrated to:
```css
@import "./typography.css";
@import "tailwindcss";
```

But to ensure that the typography styles end up in the correct location,
it requires the `layer(…)` argument.

This PR now migrates the input to:
```css
@import "./typography.css" layer(base);
@import "tailwindcss";
```

Test plan:
---

Added an integration test where an import receives the `layer(…)`, but
an import that eventually contains `@utility` does not receive the
`layer(…)` argument. This is necessary otherwise the `@utility` will be
nested when we are processing the inlined CSS.

Running this on the Commit template, we do have a proper `layer(…)`
<img width="585" alt="image"
src="https://github.com/user-attachments/assets/538055e6-a9ac-490d-981f-41065a6b59f9">
2024-11-14 18:05:14 +01:00
Robin Malfait
8538ad859c
Ensure @config is injected in common ancestor sheet (#14989)
This PR fixes an issue where an `@config` was injected in a strange
location if you have multiple CSS files with Tailwind directives.

Let's say you have this setup:
```css
/* ./src/index.css */
@import "./tailwind-setup.css";

/* ./src/tailwind-setup.css */
@import "./base.css";
@import "./components.css";
@import "./utilities.css";

/* ./src/base.css */
@tailwind base;

/* ./src/components.css */
@tailwind components;

/* ./src/utilities.css */
@tailwind utilities;
```

In this case, `base.css`, `components.css`, and `utilities.css` are all
considered Tailwind roots because they contain Tailwind directives or
imports.

Since there are multiple roots, the nearest common ancestor should
become the tailwind root (where `@config` is injected). In this case,
the nearest common ancestor is `tailwind-setup.css` (not `index.css`
because that's further away).

Before this change, we find the common ancestor between `base.css` and
`components.css` which would be `index.css` instead of
`tailwind-setup.css`.

In a next iteration, we compare `index.css` with `utilities.css` and
find that there is no common ancestor (because the `index.css` file has
no parents). This resulted in the `@config` being injected in
`index.css` and in `utilities.css`.

Continuing with the rest of the migrations, we migrate the `index.css`'s
`@config` away, but we didn't migrate the `@config` from
`utilities.css`.

With this PR, we don't even have the `@config` in the `utilities.css`
file anymore.

Test plan
---

1. Added an integration test with a non-migrateable config file to
ensure that the `@config` is injected in the correct file.
2. Added an integration test with a migrateable config file to ensure
that the CSS config is injected in the correct file. h/t @philipp-spiess
3. Ran the upgrade on the https://commit.tailwindui.com project and
ensured that
1. The `@config` does not exist in the `utilities.css` file (this was
the first bug we solved)
  2. The `@config` is replaced in the `tailwind.css` file correctly.

<img width="592" alt="image"
src="https://github.com/user-attachments/assets/02e3f6ea-a85d-46c2-ac93-09f34ac4a4b8">

<img width="573" alt="image"
src="https://github.com/user-attachments/assets/e372eb5f-5732-4052-ab39-096ba7970ff6">
2024-11-14 11:48:31 +01:00
Robin Malfait
49484f0491
Do not migrate legacy classes with custom values (#14976)
This PR fixes an issue where we migrated classes such as `rounded` to
`rounded-sm` (see:
https://github.com/tailwindlabs/tailwindcss/pull/14875)

However, if you override the values in your `tailwind.config.js` file,
then the migration might not be correct.

This PR makes sure to only migrate the classes if you haven't overridden
the values in your `tailwind.config.js` file.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-11-14 11:31:05 +01:00
Adam Wathan
56288a318a
Remove input borders by default (#14929)
This PR reverts a change we made for v4 that added borders to inputs by
default. It feels like we have to go further than this for this to
actually be useful to anyone, and since there were no borders in v3 it's
also a breaking change.

If we wanted to make form elements look more "normal" out of the box I
think we need to do something more like this:

https://play.tailwindcss.com/icCwFLVp4z?file=css

But it's a huge rabbit hole and there are so many stupid details to get
right that it feels like an insurmountable task, and if we can't go all
the way with it it's better to just maximize compatibility with v3.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-08 15:29:41 -05:00
Philipp Spiess
350add7490
Rename --line-height-* variables to --leading-* (#14925)
Part of the current changes, we also want to make the `--line-height-*`
namespace closer to the utility name so we're renaming it to
`--leading-*`:

```diff
  @theme {
-  --line-height-none: 1;
-  --line-height-tight: 1.25;
-  --line-height-snug: 1.375;
-  --line-height-normal: 1.5;
-  --line-height-relaxed: 1.625;
-  --line-height-loose: 2;

    /* ... */
  
+  --leading-none: 1;
+  --leading-tight: 1.25;
+  --leading-snug: 1.375;
+  --leading-normal: 1.5;
+  --leading-relaxed: 1.625;
+  --leading-loose: 2;

    /* ... */
  }
```

Notice that we did not change the nested values used in the `--text`
type scale, e.g.:

```css
@theme {
  /* Type scale */
  --text-xs: 0.75rem;
  --text-xs--line-height: 1rem;
}
```

These do not refer to the `leading` utility and instead refer to nested
properties so we're keeping those as-is.

## Test Plan

Added cases to the CSS `theme()` variable/JS plugin tests (interop
layer) and the integration tests (codemod layer).
2024-11-08 20:00:30 +01:00
Philipp Spiess
586723fd6a
Rename --letter-spacing-* variables to --tracking-* (#14921)
Part of the current changes, we also want to make the
`--letter-spacing-*` namespace closer to the utility name so we're
renaming it to `--tracking-*`:

```diff
  @theme {
-  --letter-spacing-tighter: -0.05em;
-  --letter-spacing-tight: -0.025em;
-  --letter-spacing-normal: 0em;
-  --letter-spacing-wide: 0.025em;
-  --letter-spacing-wider: 0.05em;
-  --letter-spacing-widest: 0.1em;

    /* ... */
  
+  --tracking-tighter: -0.05em;
+  --tracking-tight: -0.025em;
+  --tracking-normal: 0em;
+  --tracking-wide: 0.025em;
+  --tracking-wider: 0.05em;
+  --tracking-widest: 0.1em;

    /* ... */
  }
```

## Test Plan

Added cases to the CSS `theme()` variable/JS plugin tests (interop
layer) and the integration tests (codemod layer).
2024-11-08 17:02:47 +01:00
Philipp Spiess
95c4877200
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>
2024-11-07 14:25:21 -05:00
Adam Wathan
28e46badf7
Rename --font-size-* variables to --text-* (#14909)
This PR updates all of the `--font-size-*` variables to `--text-*`
instead to closer match the utility names.

```diff
  @theme {
-   --font-size-xs: 0.75rem;
-   --font-size-xs--line-height: 1rem;
-   --font-size-sm: 0.875rem;
-   --font-size-sm--line-height: 1.25rem;
-   --font-size-base: 1rem;
-   --font-size-base--line-height: 1.5rem;
-   --font-size-lg: 1.125rem;
-   --font-size-lg--line-height: 1.75rem;
-   --font-size-xl: 1.25rem;
-   --font-size-xl--line-height: 1.75rem;

    /* ... */
  
+   --text-xs: 0.75rem;
+   --text-xs--line-height: 1rem;
+   --text-sm: 0.875rem;
+   --text-sm--line-height: 1.25rem;
+   --text-base: 1rem;
+   --text-base--line-height: 1.5rem;
+   --text-lg: 1.125rem;
+   --text-lg--line-height: 1.75rem;
+   --text-xl: 1.25rem;
+   --text-xl--line-height: 1.75rem;

    /* ... */
  }
```

This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-11-07 14:08:06 -05:00
Robin Malfait
75eeed85b6
Fix crash during upgrade when content globs escape root of project (#14896)
This PR fixes an issue where globs in you `content` configuration escape
the current "root" of the project.

This can happen if you have a folder, and you need to look up in the
tree (e.g.: when looking at another package in a monorepo, or in case of
a Laravel project where you want to look at mail templates).

This applies a similar strategy we already implement on the Rust side.

1. Expand braces in the globs
2. Move static parts of the `pattern` to the `base` of the glob entry
object

---

Given a project setup like this:
```
.
├── admin
│   ├── my-tailwind.config.ts
│   └── src
│       ├── abc.jpg
│       ├── index.html
│       ├── index.js
│       └── styles
│           └── input.css
├── dashboard
│   ├── src
│   │   ├── index.html
│   │   ├── index.js
│   │   ├── input.css
│   │   └── pickaday.css
│   └── tailwind.config.ts
├── package-lock.json
├── package.json
├── postcss.config.js
└── unrelated
    └── index.html

7 directories, 14 files
```


If you then have this config:
```ts
// admin/my-tailwind.config.ts
export default {
  content: {
    relative: true,
    files: ['./src/**/*.html', '../dashboard/src/**/*.html'],
                            //  ^^  this is the important part, which escapes
                            //      the current root of the project.
  },
  theme: {
    extend: {
      colors: {
        primary: 'red',
      },
    },
  },
}
```


Then before this change, running the command looks like this:
<img width="1760" alt="image"
src="https://github.com/user-attachments/assets/60e2dfc7-3751-4432-80e3-8b4b8f1083d4">


After this change, running the command looks like this:
<img width="1452" alt="image"
src="https://github.com/user-attachments/assets/5c47182c-119c-4732-a253-2dace7086049">

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-11-07 12:22:25 +00:00
Robin Malfait
462308d8d7
Sort upgraded CSS (#14866)
During the migration process, a lot of changes to the CSS file happen.
Some parts are converted, some parts are deleted and some new CSS is
added.

To make sure we are generating a sensible and good looking CSS file, we
will sort the final CSS and pretty print it.

The order we came up with looks like this:

```css
/* Imports */
@import "tailwindcss";
@import "../other.css";

/* Configuration */
@config "../path/to/tailwindcss.config.js";

@plugin "my-plugin-1";
@plugin "my-plugin-2";

@source "./foo/**/*.ts";
@source "./bar/**/*.ts";

@variant foo {}
@variant bar {}

@theme {}

/* Border compatibility CSS */
@layer base {}

/* Utilities */
@utility foo {}
@utility bar {}

/* Rest of your own CSS if any */
```

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-11-07 12:04:52 +00:00
Adam Wathan
2aea6e9d37
Rename --font-family-* variables to --font-* (#14885)
This PR renames the `--font-family-*` theme variables to `--font-*` to
more closely match the utility names and be a bit more terse in general.

```diff
  @theme {
-   --font-family-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
-   --font-family-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
-   --font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
    
+   --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+   --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
+   --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
  }
```

This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-06 10:33:44 -05:00
Robin Malfait
d099f8bda6
Migrate default utilities to have a value suffix (#14875)
This PR adds a migration for migrating the changes we implemented in
https://github.com/tailwindlabs/tailwindcss/pull/14849

This is the migration we perform:

| Old               | New                |
| ----------------- | ------------------ |
| `shadow`          | `shadow-sm`        |
| `shadow-sm`       | `shadow-xs`        |
| `shadow-xs`       | `shadow-2xs`       |
| `inset-shadow`    | `inset-shadow-sm`  |
| `inset-shadow-sm` | `inset-shadow-xs`  |
| `inset-shadow-xs` | `inset-shadow-2xs` |
| `drop-shadow`     | `drop-shadow-sm`   |
| `drop-shadow-sm`  | `drop-shadow-xs`   |
| `rounded`         | `rounded-sm`       |
| `rounded-sm`      | `rounded-xs`       |
| `blur`            | `blur-sm`          |
| `blur-sm`         | `blur-xs`          |

Also added an integration test to ensure that `shadow` is properly
migrated to `shadow-sm`, and doesn't get migrated to `shadow-xs`
(because `shadow-sm` is migrated to `shadow-xs`).
2024-11-06 12:28:38 +01:00
Adam Wathan
c50de9384a
Replace default explicit spacing scale with multiplier system (#14857)
This PR replaces the default spacing scale (`--spacing-*`) with a
generative system based on a default spacing _unit_.

Instead of the default theme containing values like `--spacing-4`,
`--spacing-6`, `--spacing-8`, etc., instead we just define a single
`--spacing` value:

```css
@theme {
  --spacing: 0.25rem;
}
```

Utilities like `px-4` are derived from this unit by multiplying it by
the value in the utility (4 in this case):

```css
.px-4 {
  padding-inline: calc(var(--spacing) * 4);
}
```

The biggest consequence of this change is that every value is available
now, rather than just the explicitly configured values.

This means utilities like `px-42` will work now, whereas prior to this
PR only `px-40` and `px-44` were valid utilities. I personally found it
very difficult to know which values actually existed at the higher end
of the scale without IntelliSense, and in practice even when working
with a skilled designer like [Steve](https://x.com/steveschoger) who
helped design Tailwind's default spacing scale, I'd very often need to
break out of it to implement a design, and trying to round to a value
that was in the scale made the design worse, not better.

This PR allows you to use any whole number, as well as decimal numbers
that are multiples of `0.25` to ensure classes like `px-1.5` continue to
work. While this means you can now technically do things like
`pt-97.25`, I think the presence of the fractional value will be enough
of a signal to developers that they are doing something a little
unusual, and they can use their judgment as to whether they are making
the right decision or not.

I'll update this PR with a lot more detail when I have a chance, as
there are a few other things to explain like:

- Unifying all of the values for
width/min-width/max-width/height/min-height/max-height utilities
- Deriving numeric line-height values from the spacing multiplier
instead of a separate line-height scale
- Using `--spacing: initial` to disable the multiplier
- How you can still use an explicit spacing scale and ignore this change
- How we plan to use IntelliSense to surface a more curated set of
spacing values even if smaller increments work when you type them
explicitly

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-05 15:22:50 -05:00
Robin Malfait
894bf9f5ef
Support migrating projects with multiple config files (#14863)
When migrating a project from Tailwind CSS v3 to Tailwind CSS v4, then
we started the migration process in the following order:

1. Migrate the JS/TS config file
2. Migrate the source files (found via the `content` option)
3. Migrate the CSS files

However, if you have a setup where you have multiple CSS root files
(e.g.: `frontend` and `admin` are separated), then that typically means
that you have an `@config` directive in your CSS files. These point to
the Tailwind CSS config file.

This PR changes the migration order to do the following:

1. Build a tree of all the CSS files
2. For each `@config` directive, migrate the JS/TS config file
3. For each JS/TS config file, migrate the source files

If a CSS file does not contain any `@config` directives, then we start
by filling in the `@config` directive with the default Tailwind CSS
config file (if found, or the one passed in). If no default config file
or passed in config file can be found, then we will error out (just like
we do now)

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-11-04 16:52:11 +00:00
Robin Malfait
eb54dcdbfc
Install @tailwindcss/postcss next to tailwindcss (#14830)
This PR improves the PostCSS migrations to make sure that we install
`@tailwindcss/postcss` in the same bucket as `tailwindcss`.

If `tailwindcss` exists in the `dependencies` bucket, we install
`@tailwindcss/postcss` in the same bucket. If `tailwindcss` exists in
the `devDependencies` bucket, we install `@tailwindcss/postcss` in the
same bucket.

This also contains an internal refactor that normalizes the package
manager to make sure we can install a package to the correct bucket
depending on the package manager.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-30 15:32:24 -04:00