339 Commits

Author SHA1 Message Date
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
Jordan Pittman
148d8707b9
Improve support for custom variants in group-*, peer-*, has-*, and not-* variants (#14743)
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-10-24 13:27:27 -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
dc9e034643
Ensure underscore in theme() are also preserved (#14781)
Quick follow-up to #14776 to treat the `theme()` function the same way.
2024-10-24 12:49:05 -04:00
Philipp Spiess
4c9df2209f
Don't escape underscores for the first parameter of var() (#14776)
This PR updates our arbitrary value decoder to:

- No longer require an escaping for underscores in the first parameter
of `var()`. Example:

    ```
    ml-[var(--spacing-1_5,_1rem)]
    ```

- Ensures that properties before an eventual `url()` are properly
unescaped. Example:
    ```
    bg-[no-repeat_url(./image.jpg)]
    ```

I will ensure that this properly works for the migrate use case in a
follow-up PR in the stack.

## Test Plan

Added unit tests as well as tests for the variant decoder. Additionally
this PR also adds a higher-level test using the public Tailwind APIs to
ensure this is properly propagated.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-24 11:41:58 -04:00
Philipp Spiess
35cd2ff1ee
Resolve third-party plugins with exports in their package.json (#14775)
This PR fixes an issue when trying to resolve plugins with `exports` in
their `package.json`, like `@headlessui/tailwindcss`. The missing
`conditionNames` in the enhanced resolver config would cause it to not
properly look up the name.

## Test Plan

I added a test using the `postcss` setup (the existing plugin tests are
inside the CLI setup but the CLI can only ever run in Module JS mode).

To ensure the tests are resolving to the right environment (CJS vs MJS),
I added logging of the `import.meta.url` value to the resolver code.
When run, this was the output:

![Screenshot 2024-10-24 at
15.28.10.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/0Y77ilPI2WoJfMLFiAEw/c0197934-7b61-47c4-bda5-de037b31d43a.png)

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-24 11:34:19 -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
Adam Wathan
d643d79f4b
Ensure individual logical property utilities are sorted later than left/right pair utilities (#14777)
Resolves #14772.

This PR fixes an issue where utilities like `ps-2` were sorted earlier
in the generated CSS than `px-3`, causing `ps-2` to not override `px-3`
as expected.

This happened because `px-3` uses `padding-left` and `padding-right`,
and `ps-2` uses `padding-inline-start`, and in `property-order.ts` we
sort those properties as follows:

```js
  ...
  'padding',
  'padding-inline',
  'padding-block',
  'padding-inline-start',
  'padding-inline-end',
  'padding-top',
  'padding-right',
  'padding-bottom',
  'padding-left',
  ...
```

Since `padding-left` and `padding-right` both appear later than
`padding-inline-start`, the `px-3` utility is sorted later in the CSS
since all of its properties are later in the sort order than all of
properties in `ps-2`.

To fix this, I'm using our internal `--tw-sort` property to tell
Tailwind to sort the `px-3` utility as if it used `padding-inline` to
ensure that it's sorted earlier in the CSS.

This PR applies this same fix for the `padding` utilities,
`scroll-margin` utilities, and `scroll-padding` utilities. No changes
have been made to the `margin` utilities because we were already
handling this correctly there.

Here you can see that `pl-2` overrides `px-6` as you'd expect:

<img width="1041" alt="image"
src="https://github.com/user-attachments/assets/fb330536-2131-4de8-a584-62edf380148f">

…and now with the change in this PR, `ps-2` also overrides `px-6` as
you'd expect:

<img width="1043" alt="image"
src="https://github.com/user-attachments/assets/c6799416-9c80-4fd5-bce4-ea1e4da53968">

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-24 10:58:41 -04:00
depfu[bot]
2e0446c503
Update picocolors 1.0.1 → 1.1.1 (minor) (#14771) 2024-10-24 11:25:50 +02:00
Robin Malfait
2ecb94347a
Refactor @media handling (#14765)
This PR is an internal refactor to improve the way we handle at-rules.
Essentially we check for the `@` symbol and bail early if that's not the
case.

We also improve the way `@media` is being handled by first checking for
`@media`, and then handle all the params separately.

Last but not least, we also inverted the `@theme` check condition such
that it is handled the same way we handle everything else.
2024-10-23 20:26:35 +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
816e7307de Escape JS theme configuration keys (#14739)
This PR fixes two issues related to how we tread JS theme keys in combination with CSS theme values:

1. When applying JS theme keys to our `Theme` class, we need to ensure they are escaped in the same way as reading CSS theme keys from CSS are.
2. When JS plugins use the `theme()` function to read a namespace that has values contributed to from the CSS theme and the JS theme, we need to ensure that the resulting set contains only unescaped theme keys.

For specific examples, please take a look at the test cases.
2024-10-22 16:56:16 +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
thecrypticace
c0f29225e4 Always emit keyframes registered in addUtilities (#14747)
Fixes #14732

cc @philipp-spiess this look like an okay fix?
2024-10-22 16:34:38 +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
c7b190f136 Prepare preflight for border compatibility (#14745)
This PR prepares the `preflight.css` so that we can introduce border style compatibility in a future PR.
2024-10-22 16:18:13 +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
philipp-spiess
d59f1b3e5d Vite: Fix issues when loading files via static asset queries (#14716)
Fixes: #14558

This PR fixes an issue where our Vite plugin would crash when trying to load stylesheets via certain static asset query parameters:

```ts
import raw from './style.css?raw'
import url from './style.css?url'
```

The proper behavior for our extension is to _not touch these file at all_. The `?raw` identifier should never transform anything and the `?url` one will emit a module which points to the asset URL. However, if that URL is loaded as a stylesheet, another transform hook is called and the file is properly transformed. I verified this in the Vite setup and have added an integration test ensuring these two features work as expected.

I've also greatly reduced the complexity of the Vite playground to make it easier to set up examples like this in the future.
2024-10-22 16:03:07 +00:00
Robin Malfait
557ed8ccec
Add postcss as a dependency of @tailwindcss/postcss (#14750)
This PR adds `postcss` as a dependency of `@tailwindcss/postcss`. 

If you are in an environment with Next.js where you can use the
`@tailwindcss/postcss` package, then `postcss` is required.

If you have `postcss` in your `package.json`, then everything is fine,
however if you don't then you will get an error that `postcss` cannot be
found.

Note: this only happens when you are using `npm`, if you are using
`pnpm`, then the `postcss` package can be resolved correctly and you
won't run into issues. This is also why the integration tests just
worked (because we use `pnpm`).

To make sure that this package works for most people in most
environments, we explicitly add `postcss` as a dependency of
`@tailwindcss/postcss`.

---

I wanted to create an integration test for this to make sure this works,
but we are currently using `pnpm` with some of `pnpm`'s features to make
sure that we can override dependencies that point to `.tgz` files.
2024-10-22 11:20:02 +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
Jordan Pittman
19de55792f
Ensure changes to the input CSS file result in a full rebuild (#14744)
Fixes #14726

I think we broke this when we changed core so that it can handle
`@import "…"` in CSS.
2024-10-21 20:29:33 +00: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
Adam Wathan
1c5bb39d60
Use 0 instead of none in OKLCH values (#14741)
This PR updates all of our OKCLH colors to use `0` instead of `none` due
to weird behavior in Chrome where using `color-mix` with colors using
`none` produces unexpected results:

<img width="1110" alt="image"
src="https://github.com/user-attachments/assets/2272e494-500b-4f75-b5c1-d41c714f0339">

Both `none` and `0` behave as expected in Safari and Firefox so
suspecting this is a bug in Chrome rather than spec'd behavior.

Fixes #14740

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-21 15:54:27 -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
depfu[bot]
b40fd24ca9
Update @types/bun 1.1.10 → 1.1.11 (patch) (#14727)
Here is everything you need to know about this update. Please take a
good look at what changed and the test results before merging this pull
request.

### What changed?




#### ✳️ @​types/bun (1.1.10 → 1.1.11) ·
[Repo](https://github.com/DefinitelyTyped/DefinitelyTyped)





Sorry, we couldn't find anything useful about this release.











---
![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-19 15:18:39 +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
Robin Malfait
c4b97f6067
Migrate flex-grow -> grow and flex-shrink -> shrink (#14721)
This PR adds missing legacy migrations for migrating `flex-grow` to
`grow` and `flex-shrink` to `shrink`.

We already migrated `flex-grow-0` to `grow-0` and `flex-shrink-0` to
`shrink-0`, but forgot about these cases.
2024-10-18 17:58:01 +00:00
Robin Malfait
b7c4d25ae4
Ensure existing spaces in attribute selectors are valid (#14703)
This PR fixes an issue where spaces in a selector generated invalid CSS.

Lightning CSS will throw those incorrect lines of CSS out, but if you
are in an environment where Lightning CSS doesn't run then invalid CSS
is generated.

Given this input:

```html
data-[foo_=_"true"]:flex
```

This will be generated:

```css
.data-\[foo_\=_\"true\"\]\:flex[data-foo=""true] {
  display: flex;
}
```

With this PR in place, the generated CSS will now be:

```css
.data-\[foo_\=_\"true\"\]\:flex[data-foo="true"] {
  display: flex;
}
```

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-18 19:51:43 +02:00
Philipp Spiess
5c1bfd3a91
content rules from the JS config that are also covered by the automatic source detection should not be migrated to CSS (#14714)
This PR changes the migration of `content` rules in the JS config to CSS codemods.

When a `content` rule is processed which matches files that are _also matched by the automatic content discovery in v4_, we do not need to emit CSS for that rule. 

Take, for example this v3 configuration file:

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

module.exports = {
  content: [
    './src/**/*.{html,js}', 
    './node_modules/my-external-lib/**/*.{html}'
  ],
} satisfies Config
```

Provided the base directories match up, the first rule will also be covered by the automatic content discovery in v4 and thus we only need to convert the second rule to CSS:

```css
@import "tailwindcss";
@source '../node_modules/my-external-lib/**/*.{html}';
```
2024-10-18 15:48:56 +02:00
Philipp Spiess
3da49f9837
Migrate static plugins with options to CSS (#14700)
This PR extends our JS configuration to CSS migration by also allowing `plugins` with options.  

An example of such config would be:

```js
import { type Config } from 'tailwindcss'
import myPlugin from "./myPlugin";

export default {
  plugins: [
    myPlugin({
      class: "tw",
    }),
  ],
} satisfies Config;
```

If the option object contains only values allowed in our CSS API, we can convert this to CSS entirely:

```css
@plugin './myPlugin' {
  class: 'tw';
}
```
2024-10-18 15:16:27 +02:00
Philipp Spiess
3e7695fb2c
Include simple config objects when extracting static plugins (#14699)
This PR updates the `extractStaticPlugins` function to also emit options as long as these are objects containing of only `string` and `number` values.

While doing this I also cleaned up the `require('custom-plugin')` detector to use a Tree-Sitter query instead of operating on the AST.

Here are the two cases we considered:

```js
import plugin1 from 'plugin1';

export default {
  plugins: [
    plugin1({
      foo: 'bar',
      num: 19,
    }),
    require('./plugin2')({
      foo: 'bar',
      num: 19,
    }),
  ]
}
```

The test plan also contains a number of scenarios that we do not want to migrate to CSS (because we do not have a CSS API we can use for e.g. nested objects). We do support all types that we also support in the CSS API.
2024-10-18 15:10:21 +02:00
Adam Wathan
b701ed6916
Prepare v4.0.0-alpha.28 release (#14709)
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-17 17:03:28 -04:00
Philipp Spiess
0971eadd8f
Resolve theme keys when migrating JS config to CSS (#14675)
With the changes in #14672, it now becomes trivial to actually resolve
the config (while still retaining the reset behavior). This means that
we can now convert JS configs that use _functions_, e.g.:

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

export default {
  theme: {
    extend: {
      colors: ({ colors }) => ({
        gray: colors.neutral,
      }),
    },
  },
} satisfies Config
```

This becomes:

```css
@import 'tailwindcss';

@theme {
  --color-gray-50: #fafafa;
  --color-gray-100: #f5f5f5;
  --color-gray-200: #e5e5e5;
  --color-gray-300: #d4d4d4;
  --color-gray-400: #a3a3a3;
  --color-gray-500: #737373;
  --color-gray-600: #525252;
  --color-gray-700: #404040;
  --color-gray-800: #262626;
  --color-gray-900: #171717;
  --color-gray-950: #0a0a0a;
}
```

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-10-17 16:36:47 -04:00
Adam Wathan
edb066e0aa
Interpolate gradients using OKLCH by default (#14708)
This PR updates all of our gradient utilities to interpolate using OKLCH
by default instead of sRGB. This results in a smoother transition
between colors that preserves saturation throughout the gradient, rather
than hitting the dreaded dull gray zone in between your color stops.

Here are a few examples comparing sRGB (top) to OKLCH (bottom):

<img width="736" alt="image"
src="https://github.com/user-attachments/assets/57a158b6-a3a2-4eda-813e-1b596c7d4b3a">

We only apply a default interpolation mode when _not_ using arbitrary
values with the gradient utility.

Simplified but clear:

```css
.bg-linear-to-r {
  background-image: linear-gradient(to right in oklch, var(--gradient-color-stops));
}

.bg-linear-[to_right] {
  background-image: linear-gradient(to right, var(--gradient-color-stops));
}

.bg-linear-[to_right_in_hsl] {
  background-image: linear-gradient(to right in hsl, var(--gradient-color-stops));
}
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-17 16:16:14 -04:00
Adam Wathan
72c30d422a
Support linear gradient angles as bare values (#14707)
This PR adds support for linear gradient angles as bare values, like
this:

```
bg-linear-45 => linear-gradient(45deg, …)
```

We already support this for [conic
gradients](https://github.com/tailwindlabs/tailwindcss/pull/14467), so
this makes these utilities more consistent.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-17 14:29:32 -04:00
Adam Wathan
feeb9f1b77
Remove invalid gradient fallbacks (#14705)
Prior to this PR we were providing fallback values for certain CSS
variables in our gradient utilities that just weren't necessary and
didn't do anything.

For example `bg-linear-to-r` was generating this:

```css
.bg-linear-to-r {
  --tw-gradient-position: to right;
  background-image: linear-gradient(
    var(--tw-gradient-stops, to right)
  );
}
```

…but `background-image: linear-gradient(to right)` is not valid CSS and
is thrown out by the browser.

This PR removes these fallback values entirely since there is nothing
sensible to fall back to anyways — you need to combine these utilities
with the `from-*`/`to-*` utilities or provide the complete gradient as
an arbitrary value for things to make sense.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-17 13:48:58 -04:00
Robin Malfait
4a4be27dc1
Migrate theme(…) to var(…) in CSS (#14695)
This PR is a follow up from https://github.com/tailwindlabs/tailwindcss/pull/14664 migrates all the `theme(…)` calls in your CSS to `var(…)` if we can.

In at-rules, like `@media` we can't use `var(…)` so we have to use the modern version of `theme(…)`.

In declarations, we can convert to `var(…)` unless there is a modifier used in the `theme(…)` function, then we can only convert to the new `theme(…)` syntax without dot notation.

Input:
```css
@media theme(spacing.4) {
  .foo {
    background-color: theme(colors.red.900);
    color: theme(colors.red.900 / 75%); /* With spaces around the `/` */
    border-color: theme(colors.red.200/75%); /* Without spaces around the `/` */
  }
}
```

Output:
```css
@media theme(--spacing-4) {
/*     ^^^^^^^^^^^^^^^^^^     Use `theme(…)` since `var(…)` is invalid in this position*/
  .foo {
    background-color: var(--color-red-900); /* Converted to var(…) */
    color: theme(--color-red-900 / 75%); /* Convert to modern theme(…) */
    border-color: theme(--color-red-200 / 75%); /* Convert to modern theme(…) — pretty printed*/
  }
}
```
2024-10-17 11:50:27 +02:00
Robin Malfait
aff858a3e6
Make themeToVar reusable (#14694)
This PR makes the `themeToVar` code we already use for migrating the `theme(…)` calls to `var(…)` calls in the candidates (found in source files), reusable for the next PR where we want to migrate `theme(…)` calls in your actual CSS.

(This shouldn't really require a separate PR, but I'm playing with Graphite's stacked PR feature to see how it works in practice 😅)
2024-10-17 11:44:40 +02:00
Adam Wathan
2d45f5aa9a
Add first draft of new wide-gamut color palette (#14693)
This PR updates all of the colors in our default theme to use OKLCH
instead of RGB and increases the overall chroma to take advantage of the
wider color gamut.

Just a first draft based on @danhollick's initial work — expecting these
will be further refined before a stable release as we continue to test
them.

<img width="628" alt="image"
src="https://github.com/user-attachments/assets/2de1bfca-fddd-47f9-b609-39f26abdee41">

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-16 15:24:53 -04:00
Philipp Spiess
9b15a5c62e
Don't generate invalid CSS when migrating a complex screens config (#14691)
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-10-16 18:08:27 +02:00
Robin Malfait
8dc343d9f6
Migrate theme(…) calls to var(…) or the modern theme(…) syntax (#14664)
This PR adds a codemod to convert `theme(…)` calls to `var(…)` calls. If
we can't safely do this, then we try to convert the `theme(…)` syntax
(dot notation) to the modern `theme(…)` syntax (with CSS variable-like
syntax).

### Let's look at some examples:

**Simple example:**

Input:
```html
<div class="bg-[theme(colors.red.500)]"></div>
```

Output:
```html
<div class="bg-[var(--color-red-500)]"></div>
```

---

**With fallback:**

Input:
```html
<div class="bg-[theme(colors.red.500,theme(colors.blue.500))]"></div>
```

Output:
```html
<div class="bg-[var(--color-red-500,var(--color-blue-500))]"></div>
```

---

**With modifiers:**

Input:
```html
<div class="bg-[theme(colors.red.500/75%)]"></div>
```

Output:
```html
<div class="bg-[var(--color-red-500)]/75"></div>
```

We can special case this, because if you are using that modifier syntax
we _assume_ it's being used in a `theme(…)` call referencing a color.
This means that we can also convert it to a modifier on the actual
candidate.

---

**With modifier, if a modifier is already present:**

Input:
```html
<div class="bg-[theme(colors.red.500/75%)]/50"></div>
```

Output:
```html
<div class="bg-[theme(--color-red-500/75%)]/50"></div>
```

In this case we can't use the `var(…)` syntax because that requires us
to move the opacity modifier to the candidate itself. In this case we
could use math to figure out the expected modifier, but that might be
too confusing. Instead, we convert to the modern `theme(…)` syntax.

---

**Multiple `theme(…)` calls with modifiers:**

Input:
```html
<div class="bg-[theme(colors.red.500/75%,theme(colors.blue.500/50%))]"></div>
```

Output:
```html
<div class="bg-[theme(--color-red-500/75%,theme(--color-blue-500/50%))]"></div>
```

In this case we can't convert to `var(…)` syntax because then we lose
the opacity modifier. We also can't move the opacity modifier to the
candidate itself e.g.: `/50` because we have 2 different variables to
worry about.

In this situation we convert to the modern `theme(…)` syntax itself.

---

**Inside variants:**

Input:
```html
<div class="max-[theme(spacing.20)]:flex"></div>
```

Output:
```html
<div class="max-[theme(--spacing-20)]:flex"></div>
```

Unfortunately we can't convert to `var(…)` syntax reliably because in
some cases (like the one above) the value will be used inside of an
`@media (…)` query and CSS doesn't support that at the time of writing
this PR.

So to be safe, we will not try to convert `theme(…)` to `var(…)` in
variants, but we will only upgrade the `theme(…)` call itself to modern
syntax.
2024-10-16 10:44:21 -04:00
Philipp Spiess
bf179916bf
Reset default @theme values for non extend JS theme config (#14672)
Imagine the following setup:

```css
/* src/input.css */
@import "tailwindcss";
@config "../tailwind.config.ts";
@theme {
  --color-red-500: #ef4444;
}
```

```ts
/* tailwind.config.ts */
export default {
  theme: {
    colors: {
      red: {
        600: '#dc2626'
      } 
    },
    extend: {
      colors: {
        400: '#f87171'
      }
    }
  }
}
```

Since the theme object in the JS config contains `colors` in the
non-`extends` block, you would expect this to _not pull in all the
default colors imported via `@import "tailwindcss";`_. This, however,
wasn't the case right now since all theme options were purely _additive_
to the CSS.

This PR makes it so that non-`extend` theme keys _overwrite default CSS
theme values_. The emphasis is on `default` here since you still want to
be able to overwrite your options via `@theme {}` in user space.

This now generates the same CSS that our upgrade codemods would also
generate as this would apply the new CSS right after the `@import
"tailwindcss";` rule resulting in:

```css
@import "tailwindcss";
@theme {
  --color-*: initial;
  --color-red-400: #f87171;
  --color-red-600: #dc2626;
}
@theme {
  --color-red-500: #ef4444;
}
```

## Keyframes

This PR also adds a new core API to unset keyframes the same way. We
previously had no option of doing that but while working on the above
codemods we noticed that keyframes should behave the same way:

```css
@import "tailwindcss";
@theme {
  --keyframes-*: initial;
  @keyframes spin {
    to {
      transform: rotate(361deg);
    }
  }
}
```

To do this, the keyframes bookeeping was moved from the main Tailwind
CSS v4 file into the `Theme` class.


_I’m not sure super of the API yet but we would need a way for the
codemods to behave the same as out interop layer here. Option B is that
we don't reset keyframes the same way we reset other theme variables_.
2024-10-16 16:06:09 +02:00
Robin Malfait
0e262a13e6
@apply is not allowed inside @keyframes (#14687)
This PR makes sure that you cannot use `@apply` inside `@keyframes`. 

While some utilities can be used in `@keyframes`, the moment you
introduce a variant, that's not going to work anymore because they need
to operate on selectors which `@keyframes` don't have.

This PR now removes all usages of `@apply` in `@keyframes`.
2024-10-16 13:55:14 +02:00