98 Commits

Author SHA1 Message Date
Adam Wathan
437579d3f0
Prepare v4.0.0-alpha.33 release (#14967)
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-11 20:28:41 -05:00
Adam Wathan
7da9272d0f
Prepare v4.0.0-alpha.32 (#14954)
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-11 11:05:22 -05:00
Robin Malfait
292efa5daa
Remove the negative flag from the Candidate AST (#14938)
This PR removes the `negative` flag from the `Candidate` AST. The system
itself doesn't this information at all, but it's up to each plugin to
handle the `negative` flag themselves.

This also means that if you _don't_ handle it, that `foo` and `-foo`
results in the same CSS output.

To make sure that the negative version of utilities that supported it
still work, this PR also adds the negative versions as separate
utilities. E.g.: `-scale` is registered in addition to `scale`.

This is an internal refactor only, and doesn't change any behavior.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-11 10:46:53 -05:00
Robin Malfait
d325e70496
Convert , to in grid-cols-[…], grid-rows-[…], and object-[…] (#14927)
This PR converts legacy commas in arbitrary values to spaces.

In Tailwind CSS v3, we allowed commas in arbitrary values for
`grid-cols-[…]`, `grid-rows-[…]`, and `object-[…]` for backwards
compatibility. The underlying CSS value did use spaces instead of
commas.

This PR adds a code mod where convert the commas to spaces when we see
them.


Test plan:
---

Running this on Catalyst it goes from this:

<img width="393" alt="image"
src="https://github.com/user-attachments/assets/03cbda73-41f9-4601-b77a-5b511226b876">

To the expected value of:

<img width="376" alt="image"
src="https://github.com/user-attachments/assets/dd9bbe01-5eb1-4340-937b-70c435e7e4f0">

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-11-11 10:26:37 -05:00
Robin Malfait
0d3e13ec60
Migrate arbitrary values to built-in values (#14841)
This PR adds a migration where we detect arbitrary variants and try to
upgrade them to built-in variants.

For example, if you are using `[[data-visible]]:flex`, we can convert it
to `data-visible:flex`. We can also upgrade more advanced examples such
as `has-[[data-visible]]:flex` to a compound variant which becomes
`has-data-visible:flex`.

A table of example migrations:

| Before | After |
| ------------------------------------------ |
---------------------------------- |
| `[[data-visible]]:flex` | `data-visible:flex` |
| `[&[data-visible]]:flex` | `data-visible:flex` |
| `[[data-visible]&]:flex` | `data-visible:flex` |
| `[[data-url*="example"]]:flex` | `data-[url*="example"]:flex` |
| `[[data-url$=".com"_i]]:flex` | `data-[url$=".com"_i]:flex` |
| `[[data-url$=.com_i]]:flex` | `data-[url$=.com_i]:flex` |
| `[&:is([data-visible])]:flex` | `data-visible:flex` |
| `has-[[data-visible]]:flex` | `has-data-visible:flex` |
| `has-[&:is([data-visible])]:flex` | `has-data-visible:flex` |
| `has-[[data-slot=description]]:flex` |
`has-data-[slot=description]:flex` |
| `has-[&:is([data-slot=description])]:flex` |
`has-data-[slot=description]:flex` |
| `has-[[aria-visible="true"]]:flex` | `has-aria-visible:flex` |
| `has-[[aria-visible]]:flex` | `has-aria-[visible]:flex` |

We can also convert combinators from `[&>[data-visible]]:flex` to just
`*:data-visible:flex` and `[&_[data-visible]]:flex` to
`**:data-visible:flex`.

| Before | After |
| --- | --- |
| `[&>[data-visible]]:flex` | `*:data-visible:flex` |
| `[&_>_[data-visible]]:flex` | `*:data-visible:flex` |
| `[&_[data-visible]]:flex` | `**:data-visible:flex` |

Additionally, if you have complex selectors with `:not()`, we can
convert this to a compound `not-*` variant in some cases as well:

| Before | After |
| --- | --- |
| `[&:nth-child(2)]:flex` | `nth-2:flex` |
| `[&:not(:nth-child(2))]:flex` | `not-nth-2:flex` |

If some of the values in `nth-child(…)` are a bit too complex, then we
still try to convert them but to arbitrary values instead.

| Before | After |  
| --- | --- |
| `[&:nth-child(-n+3)]:flex` | `nth-[-n+3]:flex` |
| `[&:not(:nth-child(-n+3))]:flex` | `not-nth-[-n+3]:flex` |

This also implements some optimizations around `even` and `odd`:

| Before | After |
| --- | --- |
| `[&:nth-child(odd)]:flex` | `odd:flex` |
| `[&:not(:nth-child(odd))]:flex` | `even:flex` |
| `[&:nth-child(even)]:flex` | `even:flex` |
| `[&:not(:nth-child(even))]:flex` | `odd:flex` |


Some examples that stay as-is:

- `has-[&>[data-visible]]:flex` we can't upgrade this one because
`has-*` is not a valid variant.
- `has-[[data-visible][data-dark]]:flex` we can't upgrade this one
because `[data-visible][data-dark]` has to be on the same element. If we
convert this to `has-data-visible:has-data-dark:flex` then this
condition will be true if an element exists with `data-visible` and
another element exists with `data-dark` but we don't guarantee that they
are the same element.

---

Running this on the Catalyst codebase results in some updates that look
like this:

<img width="676" alt="image"
src="https://github.com/user-attachments/assets/6f0ff21d-5037-440b-9b80-0997ab0c11dd">
<img width="397" alt="image"
src="https://github.com/user-attachments/assets/8f0856fa-1709-404a-ac34-7d8c661fa799">

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-11 12:44:13 +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
Adam Wathan
bcddc81f66
Replace outline-none with outline-hidden, add new outline-none (#14926)
This PR renames the existing `outline-none` utility to `outline-hidden`,
and adds a new simpler `outline-none` utility that just sets
`outline-style: none`.

The existing `outline-none` utility doesn't actually set `outline:
none`, and instead creates a 2px invisible outline:

```css
.outline-none {
  outline: 2px solid transparent;
  outline-offset: 2px;
}
```

We implemented it this way because people often use `outline: none` to
hide focus rings and replace them with custom shadow-based focus rings,
without realizing that that approach leads to no visible focus ring in
forced colors mode because box shadows aren't rendered in forced colors
mode.

While this is sort of helpful and clever, it can be a pain when you
really do need `outline: none`, and I think it feels surprising in
hindsight to hijack the name of an existing CSS property value and make
it mean something else.

The name `outline-hidden` feels better because it's a new keyword that
CSS doesn't use for outlines, and implies that perhaps there's a bit
more going on than just setting `outline-style: none`.

This PR includes a codemod to convert any existing use of `outline-none`
to `outline-hidden`, and we will be sure to explain what
`outline-hidden` does for you in the v4 documentation.

Manually tested this in the Vite playground to make sure it behaves as
expected 👍

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-08 20:03:12 +01:00
Robin Malfait
3fb49bb0ee
Fix theme(…/15%) to only apply when used on its own (#14922)
This PR fixes an issue where our codemod migrations can convert
`bg-[theme(colors.white/15%)]` to `bg-[var(--color-white)]/15` where the
`15%` from within the `theme(…)` is converted to a candidate modifier
(at the end).

The idea was that if the `theme(…)` is used with a modifier, then it can
only be used with colors. If a candidate uses it, it also means that a
color was used and we can use `/15` instead.

However this is not true if it is used as part of a bigger value. E.g.:
`shadow-[shadow:inset_0_0_0_1px_theme(colors.white/15%)]` would be
converted to `shadow-[inset_0_0_0_1px_var(--color-white)]/15` which is
not correct because the value isn't a color, the color is _part_ of the
value.

In this case, we make sure that the `theme(…)` is the only AST node in
the value, and if it is we can safely do the conversion. If there are
other AST nodes we keep the `theme(…)` call.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-11-08 16:05:30 +00:00
Philipp Spiess
aaa32e23e2
Allow newlines and tabs in the argument list of the theme() function (#14917)
We noticed an issue that the `theme()` function wourld not properly
parse in CSS if you split the argument list over multiple lines. This is
fixed by treating `\n` and `\t` the same as space:

```css
.custom-font {
  font-family: theme(
    fontFamily.unknown,
    Helvetica Neue,
    Helvetica,
    sans-serif
  );
}
```

## Test plan

Added tests, but also tried it in the Vite example:

<img width="1995" alt="Screenshot 2024-11-08 at 13 46 09"
src="https://github.com/user-attachments/assets/f9bf94b0-3f9b-4334-8911-9190987e2df5">
2024-11-08 10:14:11 -05:00
Robin Malfait
99c4c04c54
Fix glob pattern hoisting on Windows (#14904)
This ensures our glob hoisting mechanism (see #14896) works on Windows
when performing an upgrade.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-11-07 15:31:06 -05: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
26638af3ef
Rename --width-* namespace to --container-* (#14898)
This PR renames all of the `--width-*` variables to `--container-*` to
better communicate the purpose of these tokens as layout container
sizes. These are the values that were historically stored under
`maxWidth` in the v3 and earlier eras, and were also re-used by the
container queries plugin.

The name `--container-*` feels like a better match alongside the
`--breakpoint-*` namespace and since these both serve that same sort of
purpose it makes sense to me that the name should be optimized for
feeling "right" in that context.

I like that this also sort of advertises Tailwind's support for
container queries directly in the CSS variables themselves, and helps
people understand what these are really intended to be used for.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-06 20:50:30 -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
8bd3c85420
Derive all font-weight values from theme (#14883)
This PR removes all of the static `font-weight` utilities that were
previously hard-coded into the framework in favor of deriving those
utilities from the `--font-weight-*` theme values instead.

Biggest motivation for this is giving people a way to explicitly disable
font-weight utilities they don't want to use in their project, which
previously wasn't possible.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-05 16:06:47 -05: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
depfu[bot]
df6dfb012c
Update tree-sitter 0.21.1 → 0.22.0 (major) (#14858) 2024-11-04 15:14:46 +01:00
Robin Malfait
baed3aabe2
Migrate grid-cols-[subgrid] and grid-rows-[subgrid] to grid-cols-subgrid and grid-rows-subgrid (#14840)
This PR adds a migration to convert `grid-cols-[subgrid]` to
`grid-cols-subgrid` and `grid-rows-[subgrid]` to `grid-rows-subgrid`.
2024-11-01 20:25:53 +00:00
Robin Malfait
0b5736f1b2
Remove whitespace around , separator (#14838)
This PR is an improvement/fix by making sure that whitespace around the
`,` separator is removed when printing arbitrary values.

Before:
```diff
- <div class="grid-cols-[min(50%,theme(spacing.80))_auto]"></div>
+ <div class="grid-cols-[min(50%,_var(--spacing-80))_auto]"></div>
```

After:
```diff
- <div class="grid-cols-[min(50%,theme(spacing.80))_auto]"></div>
+ <div class="grid-cols-[min(50%,var(--spacing-80))_auto]"></div>
```

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-10-31 10:15:52 +01:00
Robin Malfait
92007a5b23
Fix crash when using @source containing .. (#14831)
This PR fixes an issue where a `@source` crashes when the path
eventually resolves to a path ending in `..`.

We have to make sure that we canonicalize the path to make sure that we
are working with the real directory.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-10-30 16:24:48 -04: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
depfu[bot]
840c9e65b9
Update postcss-selector-parser 6.1.2 → 7.0.0 (major) (#14834)
Here is everything you need to know about this upgrade. Please take a
good look at what changed and the test results before merging this pull
request.

### What changed?




#### ✳️ postcss-selector-parser (6.1.2 → 7.0.0) ·
[Repo](https://github.com/postcss/postcss-selector-parser) ·
[Changelog](https://github.com/postcss/postcss-selector-parser/blob/master/CHANGELOG.md)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/postcss/postcss-selector-parser/releases/tag/v7.0.0">7.0.0</a></h4>

<blockquote><h1 dir="auto">7.0.0</h1>
<ul dir="auto">
<li>Feat: make insertions during iteration safe (major)</li>
</ul></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/postcss-selector-parser/feedback">Please
let us know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="1b1e9c3bc1...6158750aab">See
the full diff on Github</a>. The new version differs by 2 commits:</p>
<ul>
<li><a
href="6158750aab"><code>chore(release):
7.0.0</code></a></li>
<li><a
href="4fa6e860a1"><code>feat!:
make insertions during iteration safe (#295)</code></a></li>
</ul>
</details>












---
![Depfu
Status](https://depfu.com/badges/edd6acd35d74c8d41cbb540c30442adf/stats.svg)

[Depfu](https://depfu.com) will automatically keep this PR
conflict-free, as long as you don't add any commits to this branch
yourself. You can also trigger a rebase manually by commenting with
`@depfu rebase`.

<details><summary>All Depfu comment commands</summary>
<blockquote><dl>
<dt>@​depfu rebase</dt><dd>Rebases against your default branch and
redoes this update</dd>
<dt>@​depfu recreate</dt><dd>Recreates this PR, overwriting any edits
that you've made to it</dd>
<dt>@​depfu merge</dt><dd>Merges this PR once your tests are passing and
conflicts are resolved</dd>
<dt>@​depfu cancel merge</dt><dd>Cancels automatic merging of this
PR</dd>
<dt>@​depfu close</dt><dd>Closes this PR and deletes the branch</dd>
<dt>@​depfu reopen</dt><dd>Restores the branch and reopens this PR (if
it's closed)</dd>
<dt>@​depfu pause</dt><dd>Ignores all future updates for this dependency
and closes this PR</dd>
<dt>@​depfu pause [minor|major]</dt><dd>Ignores all future minor/major
updates for this dependency and closes this PR</dd>
<dt>@​depfu resume</dt><dd>Future versions of this dependency will
create PRs again (leaves this PR as is)</dd>
</dl></blockquote>
</details>

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
2024-10-30 15:27:53 -04:00
Robin Malfait
94ea5e225b
Prepare v4.0.0-alpha.31 release (#14823)
Prepare v4.0.0-alpha.31 release
2024-10-30 07:53:51 -04:00
Robin Malfait
d68a780f98
Auto source detection improvements (#14820)
This PR introduces a new `source(…)` argument and improves on the
existing `@source`. The goal of this PR is to make the automatic source
detection configurable, let's dig in.

By default, we will perform automatic source detection starting at the
current working directory. Auto source detection will find plain text
files (no binaries, images, ...) and will ignore git-ignored files.

If you want to start from a different directory, you can use the new
`source(…)` next to the `@import "tailwindcss/utilities"
layer(utilities) source(…)`.

E.g.:

```css
/* ./src/styles/index.css */
@import 'tailwindcss/utilities' layer(utilities) source('../../');
```

Most people won't split their source files, and will just use the simple
`@import "tailwindcss";`, because of this reason, you can use
`source(…)` on the import as well:

E.g.:

```css
/* ./src/styles/index.css */
@import 'tailwindcss' source('../../');
```

Sometimes, you want to rely on auto source detection, but also want to
look in another directory for source files. In this case, yuo can use
the `@source` directive:

```css
/* ./src/index.css */
@import 'tailwindcss';

/* Look for `blade.php` files in `../resources/views` */
@source '../resources/views/**/*.blade.php';
```

However, you don't need to specify the extension, instead you can just
point the directory and all the same automatic source detection rules
will apply.

```css
/* ./src/index.css */
@import 'tailwindcss';

@source '../resources/views';
```

If, for whatever reason, you want to disable the default source
detection feature entirely, and only want to rely on very specific glob
patterns you define, then you can disable it via `source(none)`.

```css
/* Completely disable the default auto source detection */
@import 'tailwindcss' source(none);

/* Only look at .blade.php files, nothing else  */
@source "../resources/views/**/*.blade.php";
```

Note: even with `source(none)`, if your `@source` points to a directory,
then auto source detection will still be performed in that directory. If
you don't want that, then you can simply add explicit files in the globs
as seen in the previous example.

```css
/* Completely disable the default auto source detection */
@import 'tailwindcss' source(none);

/* Run auto source detection in `../resources/views` */
@source "../resources/views";
```

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-29 20:33:34 +00:00
Robin Malfait
c439cdf43c
Internal refactor, introduce AtRule (#14802)
This PR introduces an internal refactor where we introduce the `AtRule`
CSS Node in our AST.

The motivation for this is that in a lot of places we need to
differentiate between a `Rule` and an `AtRule`. We often do this with
code that looks like this:

```ts
rule.selector[0] === '@' && rule.selector.startsWith('@media')
```

Another issue we have is that we often need to check for `'@media '`
including the space, because we don't want to match `@mediafoobar` if
somebody has this in their CSS. Alternatively, if you CSS is minified
then it could be that you have a rule that looks like
`@media(width>=100px)`, in this case we _also_ have to check for
`@media(`.

Here is a snippet of code that we have in our codebase:

```ts
// Find at-rules rules
if (node.kind === 'rule') {
  if (
    node.selector[0] === '@' &&
    (node.selector.startsWith('@media ') ||
      node.selector.startsWith('@media(') ||
      node.selector.startsWith('@custom-media ') ||
      node.selector.startsWith('@custom-media(') ||
      node.selector.startsWith('@container ') ||
      node.selector.startsWith('@container(') ||
      node.selector.startsWith('@supports ') ||
      node.selector.startsWith('@supports(')) &&
    node.selector.includes(THEME_FUNCTION_INVOCATION)
  ) {
    node.selector = substituteFunctionsInValue(node.selector, resolveThemeValue)
  }
}
```

Which will now be replaced with a much simpler version:
```ts
// Find at-rules rules
if (node.kind === 'at-rule') {
  if (
    (node.name === '@media' ||
      node.name === '@custom-media' ||
      node.name === '@container' ||
      node.name === '@supports') &&
    node.params.includes(THEME_FUNCTION_INVOCATION)
  ) {
    node.params = substituteFunctionsInValue(node.params, resolveThemeValue)
  }
}
```

Checking for all the cases from the first snippet is not the end of the
world, but it is error prone. It's easy to miss a case.

A direct comparison is also faster than comparing via the
`startsWith(…)` function.

---

Note: this is only a refactor without changing other code _unless_ it
was required to make the tests pass. The tests themselves are all
passing and none of them changed (because the behavior should be the
same).
The one exception is the tests where we check the parsed AST, which now
includes `at-rule` nodes instead of `rule` nodes when we have an
at-rule.
2024-10-29 01:17:25 +01:00
Robin Malfait
4e5e0a3e1b
Bump prettier-plugin-tailwindcss to latest version during upgrade (#14808)
This PR adds a migration to bump the `prettier-plugin-tailwindcss`
version to the latest version when upgrading your project. This is to
ensure that the plugin is compatible with the latest version of Tailwind
CSS.

Note: we will only do this _if_ you already used the
`prettier-plugin-tailwindcss` plugin in your project.
2024-10-28 23:46:24 +00:00
Jordan Pittman
10a8f1a725
Prepare v4.0.0-alpha.30 release (#14789) 2024-10-24 16:22:08 -04:00
Robin Malfait
f83041852d
Handle feedback from #14783 (#14788)
This PR is a continuation of #14783 to handle the feedback on that PR.

1. Update the test to be more realistic
2. Updated the comment

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-24 16:11:59 -04:00
Robin Malfait
430836f651
Ensure layer(…) on @import is only removed when @utility is present (#14783)
This PR fixes an issue where `layer(…)` next to imports were removed
where they shouldn't have been removed.

The issue exists if _any_ of the `@import` nodes in a file contains
`@utility`, if that's the case then we removed the `layer(…)` next to
_all_ `@import` nodes.

Before we were checking if the current sheet contained `@utility` or in
any of its children (sub-`@import` nodes).

This fixes that by looping over the `@import` nodes in the current
sheet, and looking for the `@utility` in the associated/imported file.
This way we update each node individually.

Test plan:
---

Added a dedicated integration test to make sure all codemods together
result in the correct result. Input:

96e8908378/integrations/upgrade/index.test.ts (L2076-L2108)

Output:

96e8908378/integrations/upgrade/index.test.ts (L2116-L2126)
2024-10-24 14:33:10 -04:00
Robin Malfait
5a1c2e7480
Only generate Preflight compatibility styles when Preflight is used (#14773)
This PR improves where we inject the border compatibility CSS. Before
this change we injected it if it was necessary in one of these spots:

- Above the first `@layer base` to group it together with existing
`@layer base` at-rules.
- If not present, after the last `@import`, to make sure that we emit
valid CSS because `@import` should be at the top (with a few
exceptions).

However, if you are working with multiple CSS files, then it could be
that we injected the border compatibility CSS multiple times if those
files met one of the above conditions.

To solve this, we now inject the border compatibility CSS with the same
rules as above, but we also have another condition:

The border compatibility CSS is only injected if the file also has a
`@import "tailwindcss";` _or_ `@import "tailwindcss/preflight";` in the
current file.

---

Added integration tests to make sure that we are generating what we
expect in a real environment. Some of the integration tests also use the
old `@tailwind` directives to make sure that the order of migrations is
correct (first migrate to `@import` syntax, then inject the border
compatibility CSS).

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-24 13:19:56 -04:00
Philipp Spiess
b722ebca37
Upgrade: Ensure underscores in url() and var() are not escaped (#14778)
This PR fixes an issue where currently a `theme()` function call inside
an arbitrary value that used a dot in the key path:

```jsx
let className = "ml-[theme(spacing[1.5])]"
```

Was causing issues when going though the codemod. The issue is that for
candidates, we require `_` to be _escaped_, since otherwise they will be
replaced with underscore. When going through the codemods, the above
candidate would be translated to the following CSS variable access:

```js
let className = "ml-[var(--spacing-1\_5))"
```

Because the underscore was escaped, we now have an invalid string inside
a JavaScript file (as the `\` would escape inside the quoted string.

To resolve this, we decided that this common case (as its used by the
Tailwind CSS default theme) should work without escaping. In
https://github.com/tailwindlabs/tailwindcss/pull/14776, we made the
changes that CSS variables used via `var()` no longer unescape
underscores. This PR extends that so that the Variant printer (that
creates the serialized candidate representation after the codemods make
changes) take this new encoding into account.

This will result in the above example being translated into:

```js
let className = "ml-[var(--spacing-1_5))"
```

With no more escaping. Nice!

## Test Plan

I have added test for this to the kitchen-sink upgrade tests.
Furthermore, to ensure this really works full-stack, I have updated the
kitchen-sink test to _actually build the migrated project with Tailwind
CSS v4_. After doing so, we can assert that we indeed have the right
class name in the generated CSS.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-24 12:49:22 -04:00
Philipp Spiess
3f2afaf3d0
Upgrade: Improve heuristics around important codemod (#14774)
This PR improves the heuristics around the important codemod (e.g.
`!border` => `border!`) as we noticed a few more cases where we the
current heuristics was not enough.

Specifically, we made it not migrate the candidate in the following
conditions:

- When there's an immediate property access: `{ "foo": !border.something
+ ""}`
- When it's used as condition in the template language: `<div
v-if="something && !border"></div>` or `<div x-if="!border"></div>`

## Test plan

I added test cases to the unit tests and updated the integration test to
contain a more sophisticated example.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-24 11:31:12 -04:00
Adam Wathan
39cfcfa427
Register migrateImport to ensure it actually runs (#14769)
This PR makes sure the `migrateImport` codemod is properly registered so
that it runs as part of the upgrade process.

## Test plan

This PR adds a new `v3` playground with an `upgrade` script that you can
use to run the upgrade from the local package. When you add a
non-prefixed `@import` to the v3 example, the paths are now properly
updated with no errors logged:


https://github.com/user-attachments/assets/85949bbb-756b-4ee2-8ac0-234fe1b2ca39

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-10-24 11:00:25 -04:00
depfu[bot]
2e0446c503
Update picocolors 1.0.1 → 1.1.1 (minor) (#14771) 2024-10-24 11:25:50 +02:00
Philipp Spiess
2327e68bc7
Prepare v4.0.0-alpha.29 release (#14761) 2024-10-23 15:30:26 +02:00
Philipp Spiess
41decce8de Upgrade: Migrate JS theme configuration keys with dot and slash in the property name (#14736)
This PR fixes an issue where JS configuration theme properties with dots
or slashes in them would not migrate correctly. E.g.:

```ts
import { type Config } from 'tailwindcss'

module.exports = {
  theme: {   
    width: {
      1.5: '0.375rem',
      '1/2': '50%',
    }
  }
}
```

This should convert to:

```css
@theme {
  --width-1_5: 0.375rem;
  --width-1\/2: 50%;
}
```

_Note: We will likely change the `--width-1_5` key to `--width-1\.5` in
a follow-up PR._

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-23 11:05:24 +02:00
Philipp Spiess
a06245b3fe
Upgrade: Rewrite imports of relative files to use relative file paths (#14755)
When we implemented the CSS import resolution system, we found out a
detail about CSS imports in that files without a relative path prefix
would still be relative to the source file. E.g.:

```css
@import 'foo.css';
```

Should first look for the file `foo.css` in the same directory. To make
this cost as cheap as possible, we limited this by a heuristics to only
apply the auto-relative imports for files with a file extension.

Naturally, while testing v4 on more templates, we found that it's common
for people to omit the file extension when loading css file. The above
could also be written as such:

```css
@import 'foo';
```

To improve this, we have two options:

- We either remove the heuristics, making every `@import` more expensive
because we have to check for relative files.
- We upgrade our codemods to rewrite `@import` statements to be
explicitly relative.

Because we really care about performance, we opted to go with the latter
option. This PR adds the codemod and removes the heuristics so we
resolve CSS files similar to how you would resolve JS files.

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-22 16:30:41 -04:00
RobinMalfait
c6572ab929 Add codemod for border style compatibility (#14746)
This PR adds a codemod that ensures that the border styles from Tailwind CSS v3 work as expected once your project is migrated to Tailwind CSS v4.

In Tailwind CSS v3, the default border color is `colors.gray.200` and in Tailwind CSS v4 the default border color is `currentColor`.

Similarly in Tailwind CSS v3, DOM elements such as `input`, `select`, and `textarea` have a border width of `0px`, in Tailwind CSS v4, we don't change the border width of these elements and keep them as `1px`.

If your project happens to already use the same value for the default border color (`currentColor`) as we use in Tailwind CSS v4, then nothing happens. But this is very unlikely, so we will make sure that we honor your `borderColor.DEFAULT` value.

If you didn't change the default values in your `tailwind.config.js`, then we will inject compatibility CSS using the default Tailwind CSS v3 values to ensure the default color and width are applied correctly.
2024-10-22 17:41:50 +00:00
philipp-spiess
fc261bdcf7 Upgrade: Migrate max-w-screen-* candidates (#14754)
This PR migrates `max-w-screen-*` candidates to the v4 equivalent relying on the breakpoint var: `max-w-[var(--breakpoint-*)]`
2024-10-22 16:40:42 +00:00
philipp-spiess
338a78050a Upgrade: Reduce number of false-positive migrations of the important modifier (#14737)
The important candidate migration is one of the most broad we have since it matches for any utility that are prefixed with an exclamation mark.

When running the codemodes on our example projects, we noticed that this was instead creating false-positives with candidates used in code positions, e.g:

```ts
export default {
  shouldNotUse: !border.shouldUse,
}
```

To prevent false-positives, this PR adds a heuristics to detect wether or not a candidate is used in a non-code position. We do this by checking the character before and after the modifier and only allow quotes or spaces.

This can cause candidates to not migrate that are valid Tailwind CSS classes, e.g.:

```ts
let classNames = `!underline${isHovered ? ' font-bold' : ''}`
```

This, however, is not a big issue since v4 can parse the v3 important prefix too.
2024-10-22 16:24:30 +00:00
RobinMalfait
02cb52ad38 Add codemod for migrating the @screen directive (#14749)
This PR adds a codemod for migrating the old `@screen` directive from Tailwind
CSS v2 that also worked in Tailwind CSS v3 but wasn't documented anymore.

Internally, this first migrates `@screen md` to `@media screen(md)`, then we rely on the existing migration that migrates the `screen(…)` function.

Input:
```css
@screen md {
  .foo {
    color: red;
  }
}
```

Output (IR):
```css
@media screen(md) {
  .foo {
    color: red;
  }
}
```

Output:
```css
@media theme(--breakpoint-md) {
  .foo {
    color: red;
  }
}
```
2024-10-22 16:09:56 +00:00
RobinMalfait
5bf2efb521 Add codemod for migrating @variants and @responsive directives (#14748)
This PR migrates the `@variants` and `@responsive` directives.

In Tailwind CSS v2, these were used to generate certain variants of responsive variants for the give classes. In Tailwind CSS v3, these still worked but were implemented as a no-op such that these directives don't end up in your final CSS.

In Tailwind CSS v4, these don't exist at all anymore, so we can safely get rid of them by replacing them with their contents.

Input:
```css
@variants hover, focus {
  .foo {
    color: red;
  }
}

@responsive {
  .bar {
    color: blue;
  }
}
```

Output:
```css
.foo {
  color: red;
}

.bar {
  color: blue;
}
```
2024-10-22 16:09:54 +00:00
Robin Malfait
d2865c3e58
Remove layer(utilities) if imports contain @utility (#14738)
We have a migration that adds the `layer(…)` next to the `@import`
depending on the order of original values. For example:
```css
@import "tailwindcss/utilities":
@import "./foo.css":
@import "tailwindcss/components":
```

Will be turned into:
```css
@import "tailwindcss":
@import "./foo.css" layer(utilities):
```

Because it used to exist between `utilities` and `components`. Without
this it would be _after_ `components`.

This results in an issue if an import has (deeply) nested `@utility`
at-rules after migrations. This is because if this is generated:
```css
/* ./src/index.css */
@import "tailwindcss";
@import "./foo.css" layer(utilities);

/* ./src/foo.css */
@utility foo {
  color: red;
}
```

Once we interpret this (and thus flatten it), the final CSS would look
like:
```css
@layer utilities {
  @utility foo {
    color: red;
  }
}
```

This means that `@utility` is not top-level and an error would occur.

This fixes that by removing the `layer(…)` from the import if the
imported file (or any of its children) contains an `@utility`. This is
to ensure that once everything is imported and flattened, that all
`@utility` at-rules are top-level.
2024-10-21 23:46:24 +02:00
Philipp Spiess
18cb3c60e6
Upgrade: Allow corePlugins in JS config files (#14742)
This PR enables JS configuration files with `corePlugins` themes to be
migrated. If such option is found in your config, we will warn the user
and omit the option from the resulting CSS file as there is no v4
alternative.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-21 16:21:55 -04:00
Robin Malfait
5ce37c45c2
Ensure we migrate theme(spacing.1) to var(--spacing-1) correctly (#14724)
This PR fixes an issue where `theme(…)` calls that contain a `.1`
weren't correctly converted to `var(--spacing-1)`. The reason for this
is that `.1` has some special meaning in cases like
`fontSize.xs.1.lineHeight` where it should be converted to
`--font-size-xs--line-height`, not `--font-size-xs-1-line-height`.

To solve this, we make sure to only apply the `--` check if the `1`
occurs somewhere in the middle instead of at the very end.

With this change, the following migrations will happen correctly:

```diff
- [--value:theme(spacing.1)]
+ [--value:var(--spacing-1)]
```

```diff
- [--value:theme(fontSize.xs.1.lineHeight)]
+ [--value:var(--font-size-xs--line-height)]
```

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-19 15:19:10 +02:00
Robin Malfait
fd8315bec7
Migrate from, via, and to arbitrary values to bare values (#14725)
This PR migrates arbitrary values for the `from-*`, `via-*` and `to-*`
utilities
to bare values.

Input:
```html
<div class="from-[28%]"></div>
<div class="via-[28%]"></div>
<div class="to-[28%]"></div>
```

Output:
```html
<div class="from-28%"></div>
<div class="via-28%"></div>
<div class="to-28%"></div>
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-19 09:05:38 -04:00
Robin Malfait
2abf228124
Minify arbitrary values when printing candidates (#14720)
This PR will optimize and simplify the candidates when printing the
candidate again after running codemods.

When we parse a candidate, we will add spaces around operators, for
example `p-[calc(1px+1px)]]` will internally be handled as `calc(1px +
1px)`. Before this change, we would re-print this as:
`p-[calc(1px_+_1px)]`.

This PR changes that by simplifying the candidate again so that the
output is `p-[calc(1px+1px)]`. In addition, if _you_ wrote
`p-[calc(1px_+_1px)]` then we will also simplify it to the concise form
`p-[calc(1px_+_1px)]`.


Some examples:

Input:
```html
<div class="[p]:flex"></div>
<div class="[&:is(p)]:flex"></div>
<div class="has-[p]:flex"></div>
<div class="px-[theme(spacing.4)-1px]"></div>
```

Output before:
```html
<div class="[&:is(p)]:flex"></div>
<div class="[&:is(p)]:flex"></div>
<div class="has-[&:is(p)]:flex"></div>
<div class="px-[var(--spacing-4)_-_1px]"></div>
```

Output after:
```html
<div class="[p]:flex"></div>
<div class="[p]:flex"></div>
<div class="has-[p]:flex"></div>
<div class="px-[var(--spacing-4)-1px]"></div>
```

---

This is alternative implementation to #14717 and #14718
Closes: #14717 
Closes: #14718
2024-10-18 22:44:25 +02:00