Part-of #14558
After handling `@import` of stylesheets in core, we can no longer gate
out features based on finding a specific sequence in the input CSS, as
this string will not contain contents from other stylesheets.
So, consider the following input CSS:
```css
@import "tailwindcsss";
@import "./styles.css";
```
We can't opt-out of the traversal to search for `@apply` based on it
because it, of course, does not contain the contents of `./styles.css`
yet.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
One of the breaking changes of v4 is the [inversion of variant order
application](https://github.com/tailwindlabs/tailwindcss/pull/13478). In
v3, variants are applied "inside-out".
For example a candidate like `*:first:underline` would produce the
following CSS in v3:
```css
.\*\:first\:underline:first-child > * {
text-decoration-line: underline;
}
```
To get the same behavior in v4, you would need to invert the candidate
order to `first:*:underline`. This would generate the following CSS in
v4:
```css
:where(.first\:\*\:underline:first-child > *) {
text-decoration-line: underline;
}
```
## The Migration
The most naive approach would be to invert the variants for every
candidate with at least two variants. This, however, runs into one issue
and some unexpected inconsistencies. I have identified the following
areas:
1. Some pseudo class variants _must appear at the end of the selector_.
v3 was patching over this by doing some manual reordering in for these
variants. For example, in v3, both of these variants create the same
output CSS: `hover:before:underline` and `before:hover:underline`. In v4
we simplified this system though and no longer generate the same output
in both cases. Instead, you'd always want to write
`hover:before:underline`, ensuring that these variants will appear at
the end.
For an exact list of which variants these affect, take a look [at this
diff](https://github.com/tailwindlabs/tailwindcss/pull/13478/files#diff-7779a0eebf6b980dd3abd63b39729b3023cf9a31c91594f5a25ea020b066e1c0L228-L246).
2. The `dark` variant and other at-rule variants are usually written
before other variants. This is more of a recommendation to make it
easier to read candidates rather than a difference in behavior as
`@media` queries are hoisted by the engine. For this reason, both of
these variants are _correct_ yet in real applications we prefer the
first one: `lg:hover:underline`, `hover:lg:underline`.
To avoid shuffling these rules across all candidates during the
migration, we bucket `dark` and other at-rule variants into a special
bucket that will not have their order changed (since people wrote stacks
like `sm:max-lg:` before and we want to keep them as-is) and appear
before all other variants.
3. For some variant stacks, the order does not matter. E.g.:
`focus:hover:underline` and `hover:focus:underline` will be the same. We
don't want to needlessly shuffle their order if we have to.
With these considerations, the migration now works as follows:
- If there is less then two variants, we do not need to migrate the
candidate
- If _every_ variant in the stack is an order-independent variant, we do
not need to migrate the candidate
- _Note that this is currently hardcoded to only support `&:hover` and
`&:focus`._
- Otherwise, we loop over the candidates and put them into three
buckets:
- `mediaVariants` hold variants that only contribute `@media` rules
_and_ the `dark` variant.
- `pseudoElementVariants` hold variants that _must appear at the end of
the selector_. This is based on the allow list from v3/early v4.
- `regularVariants` contains the rest.
- We now compute if any of the variants inside `regularVariants` is
order dependent.
- With this list of variants, we now construct the new order of variants
as:
```ts
[
...atRuleVariants,
...(anyRegularVariantOrderDependent ? regularVariants.reverse() :
regularVariants),
...pseudoElementVariants,
]
```
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
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 (8.4.41 → 8.4.47) ·
[Repo](https://github.com/postcss/postcss) ·
[Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/postcss/postcss/releases/tag/8.4.47">8.4.47</a></h4>
<blockquote><ul dir="auto">
<li>Removed debug code.</li>
</ul></blockquote>
<h4><a
href="https://github.com/postcss/postcss/releases/tag/8.4.46">8.4.46</a></h4>
<blockquote><ul dir="auto">
<li>Fixed <code class="notranslate">Cannot read properties of undefined
(reading 'before')</code>.</li>
</ul></blockquote>
<h4><a
href="https://github.com/postcss/postcss/releases/tag/8.4.45">8.4.45</a></h4>
<blockquote><ul dir="auto">
<li>Removed unnecessary fix which could lead to infinite loop.</li>
</ul></blockquote>
<h4><a
href="https://github.com/postcss/postcss/releases/tag/8.4.44">8.4.44</a></h4>
<blockquote><ul dir="auto">
<li>Another way to fix <code class="notranslate">markClean is not a
function</code> error.</li>
</ul></blockquote>
<h4><a
href="https://github.com/postcss/postcss/releases/tag/8.4.43">8.4.43</a></h4>
<blockquote><ul dir="auto">
<li>Fixed <code class="notranslate">markClean is not a function</code>
error.</li>
</ul></blockquote>
<h4><a
href="https://github.com/postcss/postcss/releases/tag/8.4.42">8.4.42</a></h4>
<blockquote><ul dir="auto">
<li>Fixed CSS syntax error on long minified files (by <a
href="https://bounce.depfu.com/github.com/varpstar">@varpstar</a>).</li>
</ul></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/postcss/feedback">Please let us
know.</a></em></p>
</details>
<details>
<summary>Commits</summary>
<p><a
href="57e02115e4...5e6fd1302d">See
the full diff on Github</a>. The new version differs by 33 commits:</p>
<ul>
<li><a
href="5e6fd1302d"><code>Release
8.4.47 version</code></a></li>
<li><a
href="714bc10258"><code>Typo</code></a></li>
<li><a
href="439d20e651"><code>Release
8.4.46 version</code></a></li>
<li><a
href="b93582f68e"><code>Update
dependencies</code></a></li>
<li><a
href="c51e46767d"><code>Fix
error on inserting node without raws in some cases</code></a></li>
<li><a
href="829ae47d6b"><code>Update
dependencies</code></a></li>
<li><a
href="5aaaec2214"><code>Update
remaining workflow jobs to use latest version of actions
(#1968)</code></a></li>
<li><a
href="448c4f34d6"><code>Release
8.4.45 version</code></a></li>
<li><a
href="1c77d2e333"><code>Update
unnecessary check</code></a></li>
<li><a
href="f38b329323"><code>Try
to fix CI</code></a></li>
<li><a
href="d442dc75e3"><code>Release
8.4.44 version</code></a></li>
<li><a
href="3c7cda099c"><code>Another
way to fix markClean() is undefined issue</code></a></li>
<li><a
href="b985ed1667"><code>Release
8.4.43 version</code></a></li>
<li><a
href="3025b743bf"><code>Update
dependencies</code></a></li>
<li><a
href="79ff9800c3"><code>Update
AST if it is not made by PostCSS >= 8.4.41</code></a></li>
<li><a
href="0fda48a1b1"><code>Release
8.4.42 version</code></a></li>
<li><a
href="cd5b08cfa2"><code>Add
ESLint to CI</code></a></li>
<li><a
href="0975cc209d"><code>Sort
source code and fix ESLint</code></a></li>
<li><a
href="36950b4ff9"><code>Try
to fix old Node.js tests</code></a></li>
<li><a
href="fbb6d60eae"><code>Update
dependencies</code></a></li>
<li><a
href="118ebc9a9a"><code>Clean
up code</code></a></li>
<li><a
href="9e7bdca1d2"><code>Pretty
CssSyntaxError from onelined (minified) css (#1965)</code></a></li>
<li><a
href="45a24250ee"><code>Merge
pull request #1961 from nex3/readonly-array</code></a></li>
<li><a
href="0cb325a1d5"><code>Use
`ReadonlyArray` for argument types that aren't
modified</code></a></li>
<li><a
href="a886628603"><code>Merge
pull request #1957 from nex3/protected-normalize</code></a></li>
<li><a
href="13a16b0dc8"><code>Merge
pull request #1958 from nex3/typedoc</code></a></li>
<li><a
href="51022c2a42"><code>Fix
a few TypeDoc warnings</code></a></li>
<li><a
href="d6fa30b3cc"><code>Add
a protected `markDirty()` method on `Node`</code></a></li>
<li><a
href="58c50ad191"><code>Declare
`Container.normalize()` as a protected method</code></a></li>
<li><a
href="ea262f3b3f"><code>Merge
pull request #1956 from
Juneezee/refactor/replace-indexOf-with-startsWith</code></a></li>
<li><a
href="c37da3c225"><code>Replace
`indexOf === 0` with `startsWith`</code></a></li>
<li><a
href="4b96e7df14"><code>Merge
pull request #1955 from
Marukome0743/Marukome0743-patch-1</code></a></li>
<li><a
href="edcc9b13b9"><code>chore(docs):
improve visual appearance of images in README.md</code></a></li>
</ul>
</details>
---

[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>
Replaces #11271 — the merge conflicts are killing me and it's way easier
to just do it again (added you as a co-author though @lukewarlow so
you're still credited!)
This PR adds the following new utilities for the `color-scheme`
property:
| Class | CSS |
| ------------------- | -------------------------- |
| `scheme-normal` | `color-scheme: normal` |
| `scheme-dark` | `color-scheme: dark` |
| `scheme-light` | `color-scheme: light` |
| `scheme-light-dark` | `color-scheme: light dark` |
| `scheme-only-dark` | `color-scheme: dark only` |
| `scheme-only-light` | `color-scheme: light only` |
Went with `scheme-*` for the utilities because there are currently no
other CSS properties with the word `scheme` in them and
`scheme-light-dark` is going to be a common value which is three words
already even with the shortened property name.
I considered setting `color-scheme: light dark` by default as part of
Preflight for this PR but decided against it, at least for this PR. I
think that could still be a useful default but we should think about it
a bit more because if you're building a light-mode-only site it'll force
you to do some extra work.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Luke Warlow <lwarlow@igalia.com>
I noticed our prefix tests were missing an explicit test for `@import
"tailwindcss" prefix(tw)` so this PR tweaks an existing test to test
that case.
Also noticed that `prefix.test.ts` was in the `compat` folder even
though this is a v4 feature, so moved it out to the root.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds a new migration that can migrate Tailwind CSS v3 style
prefixes into Tailwind CSS v4.
The migration is split into three separate pieces of work:
1. Firstly, we need to read the full JavaScript config to get the _old_
prefix option. This is necessary because in v4, we will not allow things
like custom-separators for the prefix. From this option we will then try
and compute a new prefix (in 90% of the cases this is going to just
remove the trailing `-` but it can also work in more complex cases).
2. Then we migrate all Candidates. The important thing here is that we
need to operate on the raw candidate string because by relying on
`parseCandidate` (which we do for all other migrations) would not work,
as the candidates are not valid in v4 syntax. More on that in a bit.
3. Lastly we also make sure to update the CSS config to include the new
prefix. This is done by prepending the prefix option like so:
```css
@import "tailwindcss" prefix(tw);
```
### Migrating candidates
The main difference between v3 prefixes and v4 prefixes is that in v3,
the prefix was _part of the utility_ where as in v4 it is _always in
front of the CSS class.
So, for example, this candidate in v3:
```
hover:-tw-mr-4
```
Would be converted to the following in v4:
```
tw:hover:-mr-4
```
Since the first example _won't parse as a valid Candidate in v4, as the
`tw-mr` utility does not exist, we have to operate on the raw candidate
string first. To do this I created a fork of the `parseCandidate`
function _without any validation of utilities or variants_. This is used
to identify part of the candidate that is the `base` and then ensuring
the `base` starts with the old prefix. We then remove this to create an
"unprefixed" candidate that we validate against a version of the
DesignSystem _with no prefixes configured_. If the variant is valid this
way, we can then print it again with the `DesignSystem` that has the new
prefix to get the migrated version.
Since we set up the `DesignSystem` to include the new prefix, we can
also be certain that migrations that happen afterwards would still
disqualify candidates that aren't valid according to the new prefix
policy. This does mean we need to have the prefix fixup be the first
step in our pipeline.
One interesting bit is that in v3, arbitrary properties did not require
prefixes where as in v4 they do. So the following candidate:
```
[color:red]
```
Will be converted to:
```
tw:[color:red]
```
When your Vite or postcss project has multiple Tailwind CSS roots with
different configs, they should not influence each other (with the
exception of the same candidates being used).
I noticed some more unexpected values being passed through as _bare
values_: Decimal places with zero.
These should not generate CSS but currently does:
- `from-25.%`
- `from-25.0%`
- `from-25.00%`
- etc.
This PR changes it so that only the Ubuntu runner starts when doing a
pull request. On a successfull `next` merge, all runners shoould start.
Furthermore this increases the retry count for integration test to 3.
This is mainly so that rare Windows flakes we still see won't become
noise when we enabled the Discord notification.
In v4, we're [removing automatic var
injection](https://github.com/tailwindlabs/tailwindcss/pull/13657)
(please refer to this PR for more detail as to why).
Automatic var injection made it so that if you have a candidate like
`bg-[--my-color]`, v3 would automatically wrap the content of the
arbitrary section with a `var(…)`, resulting in the same as typing
`bg-[var(--my-color)]`.
This PR adds codemods that go over various arbitrary fields and does the
`var(…)` injection for you. To be precise, we will add `var(…)` to:
- Modifiers, e.g.: `bg-red-500/[var(--my-opacity)]`
- Variants, e.g.: `supports-[var(--test)]:flex`
- Arbitrary candidates, e.g.: `[color:var(--my-color)]`
- Arbitrary values for functional candidates, e.g.:
`bg-[var(--my-color)]`
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR adds support for the `blocklist` config option when using a JS
config file in v4. You can now block certain classes from being
generated at all. This is useful in cases where scanning files sees
things that look like classes but are actually not used. For example, in
paragraphs in a markdown file:
```js
// tailwind.config.js
export default {
blocklist: ['bg-red-500'],
}
```
```html
<!-- index.html -->
<div class="bg-red-500 text-black/75"></div>
```
Output:
```css
.text-black/75 {
color: rgba(0, 0, 0, 0.75);
}
```
This PR exposes when using the the `DEBUG` environment variable. This
follows the `DEBUG` conventions where:
- `DEBUG=1`
- `DEBUG=true`
- `DEBUG=*`
- `DEBUG=tailwindcss`
Will enable the debug information, but when using:
- `DEBUG=0`
- `DEBUG=false`
- `DEBUG=-tailwindcss`
It will not.
This currently only exposes some timings related to:
1. Scanning for candidates
2. Building the CSS
3. Optimizing the CSS
We can implement a more advanced version of this where we also expose
more fine grained information such as the files we scanned, the amount
of candidates we found and so on. But I believe that this will be enough
to start triaging performance related issues.
This PR inserts the `@import` in a more sensible location when running
codemods.
The idea is that we replace `@tailwind base; @tailwind components;
@tailwind utilities;` with the much simple `@import "tailwindcss";`. We
did this by adding the `@import` to the top of the file.
While this is correct, this means that the diff might not be as clear.
For example, if you have a situation where you have a license comment:
```css
/**! My license comment */
@tailwind base;
@tailwind components;
@tailwind utilities;
```
This resulted in:
```css
@import "tailwindcss";
/**! My license comment */
```
While it is not wrong, it feels weird that this behaves like this. In
this commit we make sure that it is injected in-place (the first
`@tailwind` at-rule we find) and fixup the position if we can't inject
it in-place.
The above example results in this:
```css
/**! My license comment */
@import "tailwindcss";
```
However, there are scenario's where you can't replace the `@tailwind`
directives directly. E.g.:
```css
/**! My license comment */
html {
color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
```
If we replace the `@tailwind` directives in-place, it would look like
this:
```css
/**! My license comment */
html {
color: red;
}
@import "tailwindcss";
```
But this is invalid CSS, because you can't have CSS above an `@import`
at-rule. There are some exceptions like:
- `@charset`
- `@import`
- `@layer foo, bar;` (just the order, without a body)
- comments
In this scenario, we inject the import in the nearest place where it is
allowed to. In this case:
```css
/**! My license comment */
@import "tailwindcss";
@layer base {
html {
color: red;
}
}
```
Additionally, we will wrap the existing CSS in an `@layer` of the first
Tailwind directive we saw. In this case an `@layer base`. This ensures
that utilities still win from the default styles.
Also note that the (license) comment is allowed to exist before the
`@import`, therefore we do not put the `@import` above it. This also
means that the diff doesn't touch the license header at all, which makes
the diffs cleaner and easier to reason about.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
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.8 → 1.1.10) ·
[Repo](https://github.com/DefinitelyTyped/DefinitelyTyped)
Sorry, we couldn't find anything useful about this release.
---

[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>
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?
#### ✳️ turbo (2.1.1 → 2.1.2) ·
[Repo](https://github.com/turborepo/turbo)
Sorry, we couldn't find anything useful about this release.
---

[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>
This PR lands a quick interface update for template migration with some
lessons learned form our existing migrations. Specifically, this version
attempts to:
- Allow migrations to access the raw candidate. This way we can migrate
candidates that _would not parse as valid in v4_. This will help us
migrate prefixes in candidates from v3 to v4.
- There is no more awkward "return null" if nothing has changed. The
return `null` was necessary because we relied on mutating the Variant
and since parsing/printing could remove some information, it was not
easy to find out wether a candidate needed to be migrated at all. With a
string though, we can do this cheaply by returning the `rawCandidate`.
- We previously asserted that if `parseCandidate` returns more than one
candidate, we only picked the first one. This behavior is now moved into
the migrations where we have more context. For now though, we still do
not need to worry about this since in all cases, these duplicate
candidates would serialize to the same `Candidate`. It is helpful if you
only want to run a migration on a specific type of candidate (e.g. if
there's a `static` one and a more generic `functional` one).
- We need access to the `DesignSystem` inside migrations now to be able
to `parseCandidate`s.
Opening this up as a separate PR since it can take some time to iron out
the edge cases for the individual codemod PRs and I don't want to be
rebasing all the time.
## Before
```ts
type Migration = (candidate: Candidate) => Candidate | null
```
## After
```ts
type Migration = (designSystem: DesignSystem, rawCandidate: string) => string
```
In v4, we're making room for more gradient primitives with the addition
of [gradient and conic gradient
utilities](https://github.com/tailwindlabs/tailwindcss/pull/14467). To
make this clearer, we are renaming all v3 `bg-gradient-*` utilities to
`bg-linear-*` to make it clear that these refer to linear gradients.
This PR adds a migration that will automatically update the class names
based on this migration.
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/react (18.3.3 → 18.3.9) ·
[Repo](https://github.com/DefinitelyTyped/DefinitelyTyped)
Sorry, we couldn't find anything useful about this release.
---

[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>
Fixes#14521
When using the CLI to read files from `stdin` like this:
```bash
npx tailwindcss --input=- -o bar.css < foo.css
```
We need to set the `base` path to be the current working directory
(`process.cwd()`). However, `cwd()` already _is_ a directory and calling
`dirname()` on it did go to the parent directory _which might not have
the `tailwindcss` dependency installed.
This PR fixes an issue where a CSS rule with a selector that contains
multiple selectors lost everything but the last selector.
While testing the `npx @tailwindcss/upgrade` codemods on real world
projects, I noticed that we lost one of the selectors in the
`docker/docs` repository.
```diff
diff --git a/assets/css/toc.css b/assets/css/toc.css
index 91ff92d7cd..3b2432e913 100644
--- a/assets/css/toc.css
+++ b/assets/css/toc.css
@@ -2,7 +2,7 @@
#TableOfContents {
.toc a {
@apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
- &[aria-current="true"],
+
&:hover {
@apply border-l-2 border-l-gray-light bg-gradient-to-r from-gray-light-100 font-medium text-black dark:border-l-gray-dark dark:from-gray-dark-200 dark:text-white;
}
```
This PR fixes the issue by not overriding the `node.selector` internally
with the last selector we handled. Instead, we let the selector parser
handle it entirely.
This PR adds the initial setup and a first codemod for the template
migrations. These are a new set of migrations that operate on files
defined in the Tailwind v3 config as part of the `content` option (so
your HTML, JavaScript, TSX files etc.).
The migration for this is integrated in the new `@tailwindcss/upgrade`
package and will require pointing the migration to an input JavaScript
config file, like this:
```
npx @tailwindcss/upgrade --config tailwind.config.js
```
The idea of template migrations is to apply breaking changes from the v3
to v4 migration within your template files.
## Migrating !important syntax
The first migration that I’m adding with this PR is to ensure we use the
v4 important syntax that has the exclamation mark at the end of the
utility.
For example, this:
```html
<div class="!flex sm:!block"></div>
```
Will now turn into:
```html
<div class="flex! sm:block!"></div>
```
## Architecture considerations
Implementation wise, we make use of Oxide to scan the content files fast
and efficiently. By relying on the same scanner als Tailwind v4, we
guarantee that all candidates that are part of the v4 output will have
gone through a migration.
Migrations itself operate on the abstract `Candidate` type, similar to
the type we use in the v4 codebase. It will parse the candidate into its
parts so they can easily be introspected/modified. Migrations are typed
as:
```ts
type TemplateMigration = (candidate: Candidate) => Candidate | null
```
`null` should be returned if the `Candidate` does not need a migration.
We currently use the v4 `parseCandidate` function to get an abstract
definition of the candidate rule that we can operate on. _This will
likely need to change in the future as we need to fork `parseCandidate`
for v3 specific syntax_.
Additionally, we're inlining a `printCandidate` function that can
stringify the abstract `Candidate` type. It is not guaranteed that this
is an identity function since some information can be lost during the
parse step. This is not a problem though, because migrations will only
run selectively and if none of the selectors trigger, the candidates are
not updated. h/t to @RobinMalfait for providing the printer.
So the overall flow of a migration looks like this:
- Scan the config file for `content` files
- Use Oxide to extract a list of candidate and their positions from
these `content` files
- Run a few migrations that operate on the `Candidate` abstract type.
- Print the updated `Candidate` back into the original `content` file.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR adds support for requiring a custom prefix on utility classes.
Prefixes work a bit differently in v4 than they did in v3:
- They look like a custom variant: `tw:bg-white`
- It is always first in a utility — even before other variants:
`tw:hover:bg-white`
- It is required on **all** utility classes — even arbitrary properties:
`tw:[color:red]`
- Prefixes also apply to generated CSS variables which will be separated
by a dash: `--tw-color-white: #fff;`
- Only alpha (a-z) characters are allowed in a prefix — so no `#tw#` or
`__` or similar prefixes are allowed
To configure a prefix you can use add `prefix(tw)` to your theme or when
importing Tailwind CSS like so:
```css
/* when importing `tailwindcss` */
@import 'tailwindcss' prefix(tw);
/* when importing the theme separately */
@import 'tailwindcss/theme' prefix(tw);
/* or when using an entirely custom theme */
@theme prefix(tw) {
--color-white: #fff;
--breakpoint-sm: 640px;
/* … */
}
```
This will configure Tailwind CSS to require a prefix on all utility
classes when used in HTML:
```html
<div class="tw:bg-white tw:p-4">
This will have a white background and 4 units of padding.
</div>
<div class="bg-white p-4">
This will not because the prefix is missing.
</div>
```
and when used in CSS via `@apply`:
```css
.my-class {
@apply tw:bg-white tw:p-4;
}
```
Additionally, the prefix will be added to the generated CSS variables.
You **do not** need to prefix the variables in the `@theme` block
yourself — Tailwind CSS handles this automatically.
```css
:root {
--tw-color-white: #fff;
--tw-breakpoint-sm: 640px;
}
```
A prefix is not necessary when using the `theme(…)` function in your CSS
or JS given that plugins will not know what the current prefix is and
must work with or without a prefix:
```css
.my-class {
color: theme(--color-white);
}
```
However, because the variables themselves are prefixed when outputting
the CSS, you **do** need to prefix the variables when using `var(…)` in
your CSS:
```css
.my-class {
color: var(--tw-color-white);
}
```
If you want to customize the prefix itself change `tw` to something
else:
```css
/* my:underline, my:hover:bg-red-500, etc… */
@import 'tailwindcss' prefix(my);
```
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
When CSS exists between two tailwind directives, then the CSS will be
wrapped in an `@layer` to ensure it all ends up in the correct location
in the final CSS file.
However, if the only thing between two tailwind directives is a comment,
then the comment will also be wrapped in an `@layer` directive.
E.g.:
```css
@tailwind base;
/* This is a comment */
@tailwind components;
/* This is another comment */
@tailwind utilities;
```
Results in:
```css
@import "tailwindcss";
@layer base {
/* This is a comment */
}
@layer components {
/* This is another comment */
}
```
In this case, the layers don't matter, so this can be simplified to:
```css
@import "tailwindcss";
/* This is a comment */
/* This is another comment */
```
This PR fixes an issue where some `@import` at-rules had an empty
`layer()` attached at the end of the `@import` string.
We should only add that if a Tailwind directive or Tailwind import such
as `@tailwind base` or `@import "tailwindcss/base"` preceded the current
`@import` at-rule. If there was no Tailwind directive, the `lastLayer`
will be empty and we don't need to attach it to the `@import` string.
This PR improves the missing layers codemod where everything after the
last Tailwind directive can stay as-is without wrapping it in a `@layer`
directive.
The `@layer` at-rules are only important for CSS that exists between
Tailwind directives.
E.g.:
```css
@tailwind base;
html {}
@tailwind components;
.btn {}
@tailwind utilities;
.foo {}
.bar {}
```
Was transformed into:
```css
@import "tailwindcss";
@layer base {
html {}
}
@layer components {
.btn {}
}
@layer utilities {
.foo {}
.bar {}
}
```
But the last `@layer utilities` is already in the correct spot, so we
can simplify this to just this instead:
```css
@import "tailwindcss";
@layer base {
html {}
}
@layer components {
.btn {}
}
.foo {}
.bar {}
```
This PR adds a codemod that ensures that some parts of your stylesheet
are wrapped in an `@layer`.
This is a follow-up PR of #14411, in that PR we migrate `@tailwind`
directives to imports.
As a quick summary, that will turn this:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
Into:
```css
@import 'tailwindcss';
```
But there are a few issues with that _if_ we have additional CSS on the
page. For example let's imagine we had this:
```css
@tailwind base;
body {
background-color: red;
}
@tailwind components;
.btn {}
@tailwind utilities;
```
This will now be turned into:
```css
@import 'tailwindcss';
body {
background-color: red;
}
.btn {}
```
But in v4 we use real layers, in v3 we used to replace the directive
with the result of that layer. This means that now the `body` and `.btn`
styles are in the incorrect spot.
To solve this, we have to wrap them in a layer. The `body` should go in
an `@layer base`, and the `.btn` should be in an `@layer components` to
make sure it's in the same spot as it was before.
That's what this PR does, the original input will now be turned into:
```css
@import 'tailwindcss';
@layer base {
body {
background-color: red;
}
}
@layer components {
.btn {
}
}
```
There are a few internal refactors going on as well, but those are less
important.
This PR adds CSS codemods for migrating existing `@layer utilities` to
`@utility` directives.
This PR has the ability to migrate the following cases:
---
The most basic case is when you want to migrate a simple class to a
utility directive.
Input:
```css
@layer utilities {
.foo {
color: red;
}
.bar {
color: blue;
}
}
```
Output:
```css
@utility foo {
color: red;
}
@utility bar {
color: blue;
}
```
You'll notice that the class `foo` will be used as the utility name, the
declarations (and the rest of the body of the rule) will become the body
of the `@utility` definition.
---
In v3, every class in a selector will become a utility. To correctly
migrate this to `@utility` directives, we have to register each class in
the selector and generate `n` utilities.
We can use nesting syntax, and replace the current class with `&` to
ensure that the final result behaves the same.
Input:
```css
@layer utilities {
.foo .bar .baz {
color: red;
}
}
```
Output:
```css
@utility foo {
& .bar .baz {
color: red;
}
}
@utility bar {
.foo & .baz {
color: red;
}
}
@utility .baz {
.foo .bar & {
color: red;
}
}
```
In this case, it could be that you know that some of them will never be
used as a utility (e.g.: `hover:bar`), but then you can safely remove
them.
---
Even classes inside of `:has(…)` will become a utility. The only
exception to the rule is that we don't do it for `:not(…)`.
Input:
```css
@layer utilities {
.foo .bar:not(.qux):has(.baz) {
display: none;
}
}
```
Output:
```css
@utility foo {
& .bar:not(.qux):has(.baz) {
display: none;
}
}
@utility bar {
.foo &:not(.qux):has(.baz) {
display: none;
}
}
@utility baz {
.foo .bar:not(.qux):has(&) {
display: none;
}
}
```
Notice that there is no `@utility qux` because it was used inside of
`:not(…)`.
---
When classes are nested inside at-rules, then these classes will also
become utilities. However, the `@utility <name>` will be at the top and
the at-rules will live inside of it. If there are multiple classes
inside a shared at-rule, then the at-rule will be duplicated for each
class.
Let's look at an example to make it more clear:
Input:
```css
@layer utilities {
@media (min-width: 640px) {
.foo {
color: red;
}
.bar {
color: blue;
}
@media (min-width: 1024px) {
.baz {
color: green;
}
@media (min-width: 1280px) {
.qux {
color: yellow;
}
}
}
}
}
```
Output:
```css
@utility foo {
@media (min-width: 640px) {
color: red;
}
}
@utility bar {
@media (min-width: 640px) {
color: blue;
}
}
@utility baz {
@media (min-width: 640px) {
@media (min-width: 1024px) {
color: green;
}
}
}
@utility qux {
@media (min-width: 640px) {
@media (min-width: 1024px) {
@media (min-width: 1280px) {
color: yellow;
}
}
}
}
```
---
When classes result in multiple `@utility` directives with the same
name, then the definitions will be merged together.
Input:
```css
@layer utilities {
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
}
```
Intermediate representation:
```css
@utility no-scrollbar {
&::-webkit-scrollbar {
display: none;
}
}
@utility no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
```
Output:
```css
@utility no-scrollbar {
&::-webkit-scrollbar {
display: none;
}
-ms-overflow-style: none;
scrollbar-width: none
}
```
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR updates the `hover` variant to only apply when `@media (hover:
hover)` matches.
```diff
.hover\:bg-black {
&:hover {
+ @media (hover: hover) {
background: black;
+ }
}
}
```
This is technically a breaking change because you may have built your
site in a way where some interactions depend on hover (like opening a
dropdown menu), and were relying on the fact that tapping on mobile
triggers hover.
To bring back the old hover behavior, users can override the `hover`
variant in their CSS file back to the simpler implementation:
```css
@import "tailwindcss";
@variant hover (&:hover);
```
I've opted to go with just `@media (hover: hover)` for this because it
seems like the best trade-off between the available options. Using
`(any-hover: hover)` would mean users would get sticky hover states when
tapping on an iPad if they have a mouse or trackpad connected, which
feels wrong to me because in those cases touch is still likely the
primary method of interaction.
Sites built with this feature in mind will be treating hover styles as
progressive enhancement, so it seems better to me that using an iPad
with a mouse would not have hover styles, vs. having sticky hover styles
in the same situation.
Of course users can always override this with whatever they want, so
making this the default isn't locking anyone in to a particular choice.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR is a continuation of #13537.
Currently we reverted the merged changes so that we can get a new alpha
version out without this change.
---
This PR removes automatic `var(…)` injection for arbitrary properties,
values and modifiers.
There are a few properties that use "dashed-ident" values, this means
that you can use `--my-thing` as-is without the `var(…)` around it.
E.g.:
```css
.foo {
/* Notice that these don't have `var(…)` */
view-timeline-name: --timeline-name;
anchor-name: --sidebar;
}
```
This causes issues because we are now injecting a `var(…)` where it's
not needed.
One potential solution is to create a list of properties where dashed
idents can be used. However, they can _also_ use CSS custom properties
that point to another dashed ident.
E.g.:
```css
.foo {
--target: --sidebar;
anchor-name: var(--target);
}
```
A workaround that some people used is adding a `_` in front of the
variable: `mt-[_--my-thing]` this way we don't automatically inject the
`var(…)` around it. This is a workaround and gross.
While the idea of automatic var injection is neat, this causes more
trouble than it's worth. Adding `var(…)` explicitly is better.
A side effect of this is that we can simplify the internals for the
`candidate` data structure because we don't need to track `dashedIdent`
separately anymore.
<!--
👋 Hey, thanks for your interest in contributing to Tailwind!
**Please ask first before starting work on any significant new
features.**
It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create an issue to first
discuss any significant new features. This includes things like adding
new utilities, creating new at-rules, or adding new component examples
to the documentation.
https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md
-->
This fixes the following issue
https://github.com/tailwindlabs/tailwindcss/issues/14305 by using
`:dir()`
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR brings `@import` resolution into Tailwind CSS core. This means
that our clients (PostCSS, Vite, and CLI) no longer need to depend on
`postcss` and `postcss-import` to resolve `@import`. Furthermore this
simplifies the handling of relative paths for `@source`, `@plugin`, or
`@config` in transitive CSS files (where the relative root should always
be relative to the CSS file that contains the directive). This PR also
fixes a plugin resolution bug where non-relative imports (e.g. directly
importing node modules like `@plugin '@tailwindcss/typography';`) would
not work in CSS files that are based in a different npm package.
### Resolving `@import`
The core of the `@import` resolution is inside
`packages/tailwindcss/src/at-import.ts`. There, to keep things
performant, we do a two-step process to resolve imports. Imagine the
following input CSS file:
```css
@import "tailwindcss/theme.css";
@import "tailwindcss/utilities.css";
```
Since our AST walks are synchronous, we will do a first traversal where
we start a loading request for each `@import` directive. Once all loads
are started, we will await the promise and do a second walk where we
actually replace the AST nodes with their resolved stylesheets. All of
this is recursive, so that `@import`-ed files can again `@import` other
files.
The core `@import` resolver also includes extensive test cases for
[various combinations of media query and supports conditionals as well
als layered
imports](https://developer.mozilla.org/en-US/docs/Web/CSS/@import).
When the same file is imported multiple times, the AST nodes are
duplicated but duplicate I/O is avoided on a per-file basis, so this
will only load one file, but include the `@theme` rules twice:
```css
@import "tailwindcss/theme.css";
@import "tailwindcss/theme.css";
```
### Adding a new `context` node to the AST
One limitation we had when working with the `postcss-import` plugin was
the need to do an additional traversal to rewrite relative `@source`,
`@plugin`, and `@config` directives. This was needed because we want
these paths to be relative to the CSS file that defines the directive
but when flattening a CSS file, this information is no longer part of
the stringifed CSS representation. We worked around this by rewriting
the content of these directives to be relative to the input CSS file,
which resulted in added complexity and caused a lot of issues with
Windows paths in the beginning.
Now that we are doing the `@import` resolution in core, we can use a
different data structure to persist this information. This PR adds a new
`context` node so that we can store arbitrary context like this inside
the Ast directly. This allows us to share information with the sub tree
_while doing the Ast walk_.
Here's an example of how the new `context` node can be used to share
information with subtrees:
```ts
const ast = [
rule('.foo', [decl('color', 'red')]),
context({ value: 'a' }, [
rule('.bar', [
decl('color', 'blue'),
context({ value: 'b' }, [
rule('.baz', [decl('color', 'green')]),
]),
]),
]),
]
walk(ast, (node, { context }) => {
if (node.kind !== 'declaration') return
switch (node.value) {
case 'red': assert(context.value === undefined)
case 'blue': assert(context.value === 'a')
case 'green': assert(context.value === 'b')
}
})
```
In core, we use this new Ast node specifically to persist the `base`
path of the current CSS file. We put the input CSS file `base` at the
root of the Ast and then overwrite the `base` on every `@import`
substitution.
### Removing the dependency on `postcss-import`
Now that we support `@import` resolution in core, our clients no longer
need a dependency on `postcss-import`. Furthermore, most dependencies
also don't need to know about `postcss` at all anymore (except the
PostCSS client, of course!).
This also means that our workaround for rewriting `@source`, the
`postcss-fix-relative-paths` plugin, can now go away as a shared
dependency between all of our clients. Note that we still have it for
the PostCSS plugin only, where it's possible that users already have
`postcss-import` running _before_ the `@tailwindcss/postcss` plugin.
Here's an example of the changes to the dependencies for our Vite client
✨ :
<img width="854" alt="Screenshot 2024-09-19 at 16 59 45"
src="https://github.com/user-attachments/assets/ae1f9d5f-d93a-4de9-9244-61af3aff1237">
### Performance
Since our Vite and CLI clients now no longer need to use `postcss` at
all, we have also measured a significant improvement to the initial
build times. For a small test setup that contains only a hand full of
files (nothing super-complex), we measured an improvement in the
**3.5x** range:
<img width="1334" alt="Screenshot 2024-09-19 at 14 52 49"
src="https://github.com/user-attachments/assets/06071fb0-7f2a-4de6-8ec8-f202d2cc78e5">
The code for this is in the commit history if you want to reproduce the
results. The test was based on the Vite client.
### Caveats
One thing to note is that we previously relied on finding specific
symbols in the input CSS to _bail out of Tailwind processing
completely_. E.g. if a file does not contain a `@tailwind` or `@apply`
directive, it can never be a Tailwind file.
Since we no longer have a string representation of the flattened CSS
file, we can no longer do this check. However, the current
implementation was already inconsistent with differences on the allowed
symbol list between our clients. Ideally, Tailwind CSS should figure out
wether a CSS file is a Tailwind CSS file. This, however, is left as an
improvement for a future API since it goes hand-in-hand with our planned
API changes for the core `tailwindcss` package.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR changes the behavior of the `transition-{property}` utilities to
respect any explicit timing function or duration set by the user using
the `ease-*` and `duration-*` utilities.
Say you have this HTML:
```html
<div class="transition-colors duration-500 ease-out lg:transition-all">
```
Currently, the `transition-duration` and `transition-timing-functions`
will be reset to their default values at the `lg` breakpoint even though
you've provided explicit values for them.
After this PR is merged, those values will be preserved at the `lg`
breakpoint.
This PR also adds `duration-initial` and `ease-initial` utilities to
"unset" explicit duration/timing-function values so that the defaults
from classes like `transition-all` will kick in, without having to
specify their explicit values.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds our custom gradient color properties (`--tw-gradient-from`,
`--tw-gradient-via`, and `--tw-gradient-to`) to the list of color
properties we transition in the `transition` and `transition-colors`
utilities.
As part of this I noticed that we had duplicate `@property` declarations
for these custom properties, so I've removed the duplicates.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
- Avoid cross-device copying in Windows CI by setting the tests dir to
the same drive as the workspace.
- Disable LTO and use a faster linker for the Rust build
Buid: ~3min -> ~2min
Integration Tests: ~8min -> ~3min20s
Fixes#14479.
Back in March we made a change to the `transition-*` utilities that
inlined the values of the `--default-transition-*` variables to fix a
bug where things would break if those variables didn't exist in your
CSS. At the time though we weren't outputting CSS variables as part of
the values of any utilities, for example `bg-red-500` didn't actually
reference the `--color-red-500` variable.
We later changed that but missed this situation, so these variables were
still inlined even though nothing else was.
This PR fixes that and makes things more consistent, so these variables
will be used as expected unless using the `@theme inline` option, like
with everything else.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds support for the
[`field-sizing`](https://developer.mozilla.org/en-US/docs/Web/CSS/field-sizing)
property which can be used to fit a text inputs, file inputs, textareas,
and selects to the size of the text rather than some implicit default
width.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
<!--
👋 Hey, thanks for your interest in contributing to Tailwind!
**Please ask first before starting work on any significant new
features.**
It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create an issue to first
discuss any significant new features. This includes things like adding
new utilities, creating new at-rules, or adding new component examples
to the documentation.
https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md
-->
```ts
// error: can't find `@tailwindcss/node` types file
import { compile } from '@tailwindcss/node';
```
This PR complements #14458 by adding new `shadow-initial` and
`inset-shadow-initial` utilities that make it possible to "undo" a
custom shadow color and revert to the default shadow color for the
current shadow size.
For example, in this example the shadow will be red on hover even though
the default color for the `shadow` utility is `rgb(0 0 0 / 5%)`:
```html
<div class="shadow-sm shadow-red-500 hover:shadow">
<!-- … -->
</div>
```
This is usually what you want, but if you actually want `hover:shadow`
to apply its default color, you need to know what the color is and add
it yourself:
```html
<div class="shadow-sm shadow-red-500 hover:shadow hover:shadow-black/5">
<!-- … -->
</div>
```
Using `shadow-initial`, you can achieve the same thing without having to
know what the original color was:
```html
<div class="shadow-sm shadow-red-500 hover:shadow hover:shadow-initial">
<!-- … -->
</div>
```
The `inset-shadow-initial` utility does the same thing for the
`inset-shadow-*` utilities.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds new `bg-radial-*` and `bg-conic-*` utilities for radial and
conic gradients. It also adds support for "arbitrary gradients", where
gradient utilities like `bg-linear-*`, `bg-radial-*`, and `bg-conic-*`
can now accept a complete gradient definition as their arbitrary value.
## Radial gradients
Radial gradients are created with the `bg-radial` utility, or the
`bg-radial-[…]` utility, combined with the existing `from-*`, `via-*`,
and `to-*` utilities.
The simple `bg-radial` utility just creates a radial gradient with no
position information, which defaults to `center`:
```
radial-gradient({from}, {via}, {to});
```
If you use the arbitrary value format, whatever you provide as the
arbitrary value is inserted into the first position:
```
radial-gradient({arbitrary value}, {from}, {via}, {to});
```
So a utility like `bg-radial-[at_top_left]` would produce this:
```
radial-gradient(at top left, {from}, {via}, {to});
```
This makes it possible to use some of the `radial-gradient(…)` features
that this PR doesn't add first class support for, like using values like
`circle at center` or providing a specific interpolation color space
like `in hsl longer hue`. We may add explicit APIs for these in the
future, but I'm proposing this PR first since those changes would be
purely additive and none of the decisions here would create any conflict
with those APIs.
## Conic gradients
Conic gradients are created with the `bg-conic`,
`bg-conic-{bareNumber}`, and `bg-conic-[…]` utilities, combined with the
existing `from-*`, `via-*`, and `to-*` utilities.
The `bg-conic` utility creates a conic gradient with no angle, which
defaults to `0deg`:
```
conic-gradient({from}, {via}, {to});
```
The `bg-conic-{bareNumber}` utilities create conic gradients using the
bare number as the angle:
```
conic-gradient(from {bareNumber}deg, {from}, {via}, {to});
```
The `bg-conic-[…]` arbitrary value utilities insert whatever you provide
as the arbitrary value into the first position verbatim:
```
conic-gradient({arbitraryValue}, {from}, {via}, {to});
```
So a utility like `bg-conic-[from_45deg_in_hsl]` would produce this:
```
conic-gradient(from 45deg in hsl, {from}, {via}, {to});
```
Note that the `from` keyword needs to be provided by the user when using
arbitrary values, but not when using bare values.
This makes it possible to use some of the `conic-gradient(…)` features
that this PR doesn't add first class support for, like using values like
`at 0 0` or providing a specific interpolation color space like `in hsl
longer hue`. We may add explicit APIs for these in the future, but I'm
proposing this PR first since those changes would be purely additive and
none of the decisions here would create any conflict with those APIs.
## Arbitrary gradients
Prior to this PR, utilities like `bg-linear-[…]` could only accept
positional information as their arbitrary value, like
`bg-linear-[to_top_right]`. All of the color stops could only be
provided using the `from-*`, `via-*`, and `to-*` utilities.
If you wanted to provide the complete gradient in one class, you needed
to use `bg-[…]` and write out the gradient function yourself:
```html
<div class="bg-[linear-gradient(to_right,var(--color-red-500),var(--color-yellow-400))]">
```
This PR refactors some things internally to make it possible to provide
the entire gradient as the arbitrary value to each background gradient
utility, like this:
```html
<div class="bg-linear-[to_right,var(--color-red-500),var(--color-yellow-400)]">
```
This is nice if you're doing something very custom and you want to be
able to look at the whole value together, while still avoiding some of
the boilerplate you'd have if you had to write out the entire gradient
function yourself.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>