55 Commits

Author SHA1 Message Date
Adam Wathan
56288a318a
Remove input borders by default (#14929)
This PR reverts a change we made for v4 that added borders to inputs by
default. It feels like we have to go further than this for this to
actually be useful to anyone, and since there were no borders in v3 it's
also a breaking change.

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

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

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

---------

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

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

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

    /* ... */
  }
```

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

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

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

## Test Plan

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

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

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

    /* ... */
  }
```

## Test Plan

Added cases to the CSS `theme()` variable/JS plugin tests (interop
layer) and the integration tests (codemod layer).
2024-11-08 17:02:47 +01:00
Adam Wathan
192109bd01
Don't give input elements a transparent background by default (#14913)
Early in v4 development we decided to give all form controls a
transparent background, but in v3 we only did this for button elements.

This PR reverts that decision to make things consistent with v3, as
we've noticed this is something that tends to break for people when
upgrading from v3 to v4.

The default background color of form elements is the [`Field` system
color](https://developer.mozilla.org/en-US/docs/Web/CSS/system-color#field)
which automatically adapts to light and dark modes if you don't touch
it, so it feels reasonable to keep this as the default. Changing it just
makes upgrading harder and doesn't really make anything easier for
anyone else.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-08 10:19:29 -05:00
Adam Wathan
28e46badf7
Rename --font-size-* variables to --text-* (#14909)
This PR updates all of the `--font-size-*` variables to `--text-*`
instead to closer match the utility names.

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

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

    /* ... */
  }
```

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

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-11-07 14:08:06 -05:00
Adam Wathan
26638af3ef
Rename --width-* namespace to --container-* (#14898)
This PR renames all of the `--width-*` variables to `--container-*` to
better communicate the purpose of these tokens as layout container
sizes. These are the values that were historically stored under
`maxWidth` in the v3 and earlier eras, and were also re-used by the
container queries plugin.

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

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

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-06 20:50:30 -05:00
Adam Wathan
32cf4af2a4
Rename --transition-timing-function-* variables to --ease-* (#14886)
This PR renames the `--transition-timing-function-*` theme variables to
`--ease-*` to more closely match the utility names and be a bit more
terse in general.

```diff
  @theme {
-   --transition-timing-function-in: cubic-bezier(0.4, 0, 1, 1);
-   --transition-timing-function-out: cubic-bezier(0, 0, 0.2, 1);
-   --transition-timing-function-in-out: cubic-bezier(0.4, 0, 0.2, 1);

+   --ease-in: cubic-bezier(0.4, 0, 1, 1);
+   --ease-out: cubic-bezier(0, 0, 0.2, 1);
+   --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  }
```

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

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-06 10:51:34 -05:00
Adam Wathan
2aea6e9d37
Rename --font-family-* variables to --font-* (#14885)
This PR renames the `--font-family-*` theme variables to `--font-*` to
more closely match the utility names and be a bit more terse in general.

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

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

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-06 10:33:44 -05:00
Robin Malfait
c5b6df2a27
Optimize generated CSS output (#14873)
This PR improves the generated CSS by running it through Lightning CSS
twice.Right now Lightning CSS merges adjacent at-rules and at the end
flattens the nesting. This means that after the nesting is flattened,
the at-rules that are adjacent and could be merged together will not be
merged.

This PR improves our output by running Lightning CSS twice on the
generated CSS which will make sure to merge adjacent at-rules after the
nesting is flattened.

Note: in the diff output you'll notice that some properties are
duplicated. These need some fixes in Lightning CSS itself but they don't
break anything for us right now.

Related PR in Lightning CSS for the double `-webkit-backdrop-filter` can
be found here: https://github.com/parcel-bundler/lightningcss/pull/850

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-11-06 11:39:09 +00:00
Adam Wathan
8bd3c85420
Derive all font-weight values from theme (#14883)
This PR removes all of the static `font-weight` utilities that were
previously hard-coded into the framework in favor of deriving those
utilities from the `--font-weight-*` theme values instead.

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

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-05 16:06:47 -05:00
Adam Wathan
7175605c61
Remove fallbacks from theme var(...) calls (#14881)
This PR changes how we render `var(...)` calls for theme values,
removing the fallback values we were previously including.

```diff
  .text-white {
-   color: var(--color-white, #fff);
+   color: var(--color-white);
  }
```

We previously included the fallbacks only so you could see the value in
dev tools but this feels like a bad reason to bloat the CSS. I'd rather
just convince the Chrome team to surface this stuff better in dev tools
in the first place.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-05 15:44:21 -05:00
Adam Wathan
c50de9384a
Replace default explicit spacing scale with multiplier system (#14857)
This PR replaces the default spacing scale (`--spacing-*`) with a
generative system based on a default spacing _unit_.

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

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

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

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

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

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

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

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

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

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-05 15:22:50 -05:00
Adam Wathan
b63f493768
Make ease-linear a static utility (#14880)
This PR removes `--transition-timing-function-linear` from the default
theme in favor of a static `ease-linear` utility. Doesn't make sense for
this to be a design token since `linear` can only mean `linear`.

This is consistent with how we handle basically every other similar case
in the framework.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-11-05 12:34:44 -05:00
Adam Wathan
ca4e4aebd8
Adjust shadow, radius, and blur scales to ensure all utilities have a value suffix (#14849)
This PR reworks the default `--shadow-*` and `--inset-shadow-*` scales
to remove the bare `shadow` and `inset-shadow` utilities, and ensure
every shadow has an explicit size as part of the utility name.

Here's a complete list of changes:

| v3                | v4 Alpha          | Proposed           |
| ----------------- | ----------------- | ------------------ |
| _N/A_             | `shadow-xs`       | `shadow-2xs`       |
| `shadow-sm`       | `shadow-sm`       | `shadow-xs`        |
| `shadow`          | `shadow`          | `shadow-sm`        |
| `shadow-md`       | `shadow-md`       | `shadow-md`        |
| `shadow-lg`       | `shadow-lg`       | `shadow-lg`        |
| `shadow-xl`       | `shadow-xl`       | `shadow-xl`        |
| _N/A_ | `inset-shadow-xs` | `inset-shadow-2xs` |
| _N/A_ | `inset-shadow-sm` | `inset-shadow-xs`  |
| `shadow-inner`    | `inset-shadow`    | `inset-shadow-sm`     |

The motivation for this change is just to make the scale more
predictable — it's never been intuitive to me that `shadow` sits in
between `shadow-sm` and `shadow-md`.

This PR doesn't remove the ability to create classes like `shadow` and
`inset-shadow` by adding bare `--shadow` and `--inset-shadow` theme
variables, but does remove them from the default theme.

## Impact

We'll include a codemod for this in our upgrade tool to automate this
change for people upgrading from v3 to v4, but this is still sort of an
annoying breaking change admittedly and will make lots of educational
resources, example components, and LLM tools out of date for v4 😕 At the
same time I don't want to feel like we can never correct regrettable
legacy decisions just to preserve backward compatibility.

We made a similar change like this when we went from the v0.x color
palette to the v1.x color palette changing names like `bg-red` to
`bg-red-500` and that proved to definitely be the right decision long
term, so want to rip the band-aid off here too if we can.

Planning to make the same change for `rounded`, `drop-shadow`, and
`blur` as well — maybe in separate PRs but maybe just all in this one as
well since I don't think we want to do one and not all.

_Update_: I've also made the same changes to the `--radius-*`,
`--drop-shadow-*`, and `--blur-*` scales now, effectively removed the
`rounded`, `drop-shadow`, and `blur` classes by default, and changing
the meaning `rounded-sm`, `drop-shadow-sm`, and `blur-sm`.

We'll put together a codemod to handle this stuff in a separate PR.

---------

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

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

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

This PR changes the migration order to do the following:

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

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

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-11-04 16:52:11 +00:00
Adam Wathan
63b321b7ea
Remove --drop-shadow-none from default theme (#14847)
This PR removes `--drop-shadow-none` from the default theme which
shouldn't ever have been there since we handle all `*-none` utilities as
static/permanent utilities in the framework now.

I've added `drop-shadow-none` as an explicit static utility, and also
slightly improved test coverage for `getClassList` around drop shadows
while touching this part of the code.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-31 14:24:18 -04:00
Robin Malfait
d68a780f98
Auto source detection improvements (#14820)
This PR introduces a new `source(…)` argument and improves on the
existing `@source`. The goal of this PR is to make the automatic source
detection configurable, let's dig in.

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

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

E.g.:

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

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

E.g.:

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-10-29 20:33:34 +00:00
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
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
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
Robin Malfait
b1733ac1fd
Don't set display: none on elements that use hidden="until-found" (#14631)
Fixes an issue reported by the React Aria Components team here:

https://github.com/adobe/react-spectrum/issues/7160

Basically `hidden="until-found"` behaves very differently than `hidden`
and doesn't actually use `display: none`, so we don't want to apply the
behavior we apply for the regular `hidden` attribute.
2024-10-09 13:55:58 +02:00
Robin Malfait
35b84cc313
Improve @tailwindcss/postcss performance for initial builds (#14565)
This PR improves the performance of the `@tailwindcss/postcss` plugin.
Before this change we created 2 compiler instances instead of a single
one. On a project where a `tailwindcss.config.ts` file is used, this
means that the timings look like this:

```
[@tailwindcss/postcss] Setup compiler: 137.525ms
⋮
[@tailwindcss/postcss] Setup compiler: 43.95ms
```

This means that with this small change, we can easily shave of ~50ms for
initial PostCSS builds.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-10-03 16:21:54 +02:00
Robin Malfait
ab82efab7d
Expose timing information in debug mode (#14553)
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.
2024-09-30 14:39:21 +00:00
Philipp Spiess
79794744a9
Resolve @import in core (#14446)
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>
2024-09-23 17:05:55 +02:00
Adam Wathan
a51b63a05d
Don't override explicit leading-*, tracking-*, or font-{weight} utilities with font-size utility defaults (#14403)
This PR improves how the `text-{size}` utilities interact with the
`leading-*`, `tracking-*`, and `font-{weight}` utilities, ensuring that
if the user explicitly uses any of those utilities that those values are
not squashed by any defaults baked into the `text-{size}` utilities.

Prior to this PR, if you wrote something like this:

```html
<div class="text-lg leading-none md:text-2xl">
```

…the `leading-none` class would be overridden by the default line-height
value baked into the `text-2xl` utility at the `md` breakpoint. This has
been a point of confusion and frustration for people [in the
past](https://github.com/tailwindlabs/tailwindcss/issues/6504) who are
annoyed they have to keep repeating their custom `leading-*` value like
this:

```html
<div class="text-lg leading-none md:text-2xl md:leading-none lg:text-4xl lg:leading-none">
```

This PR lets you write this HTML instead but get the same behavior as
above:

```html
<div class="text-lg leading-none md:text-2xl lg:text-4xl">
```

It's important to note that this change _only_ applies to line-height
values set explicitly with a `leading-*` utility, and does not apply to
the line-height modifier.

In this example, the line-height set by `text-sm/6` does _not_ override
the default line-height included in the `md:text-lg` utility:

```html
<div class="text-sm/6 md:text-lg">
```

That means these two code snippets behave differently:

```html
<div class="text-sm/6 md:text-lg">…</div>
<div class="text-sm leading-6 md:text-lg">…</div>
```

In the top one, the line-height `md:text-lg` overrides the line-height
set by `text-sm/6`, but in the bottom one, the explicit `leading-6`
utility takes precedence.

This PR applies the same improvements to `tracking-*` and
`font-{weight}` as well, since all font size utilities can also
optionally specify default `letter-spacing` and `font-weight` values.

We achieve this using new semi-private CSS variables like we do for
things like transforms, shadows, etc., which are set by the `leading-*`,
`tracking-*`, and `font-{weight}` utilities respectively. The
`text-{size}` utilities always use these values first if they are
defined, and the default values become fallbacks for those variables if
they aren't present.

We use `@property` to make sure these variables are reset to `initial`
on a per element basis so that they are never inherited, like with every
other variable we define.

This PR does slightly increase the amount of CSS generated, because now
utilities like `leading-5` look like this:

```diff
  .leading-5 {
+   --tw-leading: 1.25rem;
    line-height: 1.25rem;
  }
```

…and utilites like `text-sm` include a `var(…)` lookup that they didn't
include before:

```diff
  .text-sm {
    font-size: 0.875rem;
-   line-height: var(--font-size-sm--line-height, 1.25rem);
+   line-height: var(--tw-leading, var(--font-size-sm--line-height, 1.25rem));
  }
```

If this extra CSS doesn't feel worth it for the small improvement in
behavior, we may consider just closing this PR and keeping things as
they are.

This PR is also a breaking change for anyone who was depending on the
old behavior, and expected the line-height baked into the `md:text-lg`
class to take precedence over the explicit `leading-6` class:

```html
<div class="text-sm leading-6 md:text-lg">…</div>
```

Personally I am comfortable with this because of the fact that you can
still get the old behavior by preferring a line-height modifier:

```html
<div class="text-sm/6 md:text-lg">…</div>
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-18 09:20:04 -04:00
Philipp Spiess
a1d56d8e24
Ensure content globs defined in @config files are relative to that file (#14314)
When you configure custom content globs inside an `@config` file, we
want to tread these globs as being relative to that config file and not
the CSS file that requires the content file. A config can be used by
multiple CSS configs.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-03 16:54:08 +02:00
Jordan Pittman
52012d90d7
Support loading config files via @config (#14239)
In Tailwind v4 the CSS file is the main entry point to your project and
is generally configured via `@theme`. However, given that all v3
projects were configured via a `tailwind.config.js` file we definitely
need to support those. This PR adds support for loading existing
Tailwind config files by adding an `@config` directive to the CSS —
similar to how v3 supported multiple config files except that this is
now _required_ to use a config file.

You can load a config file like so:

```
@import "tailwindcss";
@config "./path/to/tailwind.config.js";
```

A few notes:
- Both CommonJS and ESM config files are supported (loaded directly via
`import()` in Node)
- This is not yet supported in Intellisense or Prettier — should
hopefully land next week
- TypeScript is **not yet** supported in the config file — this will be
handled in a future PR.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-02 18:03:16 +02:00
Philipp Spiess
ab8972749c
Postcss: Bring back proper type exports (#14256)
Closes #14253

Since we changed the export strategy for the postcss client in #14132,
we accidentally no longer generated type exports for this package.

This PR adds a type export back. We now use a similar pattern to the
`./colors` and `./defaultTheme` exports in the tailwindcss package where
we have a separate cjs entrypoint.

The changes were validated manually in a playground project that were
installing the updated dependencies from tarballs.

Here is one example of it working as expected:
 
<img width="750" alt="Screenshot 2024-08-26 at 14 10 07"
src="https://github.com/user-attachments/assets/83de15f2-1543-4805-9231-9b8df1636c5e">
2024-08-26 15:54:07 +02:00
Robin Malfait
a902128640
Improve Oxide scanner API (#14187)
This PR updates the API for interacting with the Oxide API. Until now,
we used the name `scanDir(…)` which is fine, but we do way more work
right now.

We now have features such as:

1. Auto source detection (can be turned off, e.g.: `@tailwindcss/vite`
doesn't need it)
2. Scan based on `@source`s found in CSS files
3. Do "incremental" rebuilds (which means that the `scanDir(…)` result
was stateful).

To solve these issues, this PR introduces a new `Scanner` class where
you can pass in the `detectSources` and `sources` options. E.g.:

```ts
let scanner = new Scanner({
  // Optional, omitting `detectSources` field disables automatic source detection
  detectSources: { base: __dirname }, 

  // List of glob entries to scan. These come from `@source` directives in CSS.
  sources: [
    { base: __dirname, pattern: "src/**/*.css" },
    // …
  ],
});
```

The scanner object has the following API:

```ts
export interface ChangedContent {
  /** File path to the changed file */
  file?: string
  /** Contents of the changed file */
  content?: string
  /** File extension */
  extension: string
}
export interface DetectSources {
  /** Base path to start scanning from */
  base: string
}
export interface GlobEntry {
  /** Base path of the glob */
  base: string
  /** Glob pattern */
  pattern: string
}
export interface ScannerOptions {
  /** Automatically detect sources in the base path */
  detectSources?: DetectSources
  /** Glob sources */
  sources?: Array<GlobEntry>
}
export declare class Scanner {
  constructor(opts: ScannerOptions)
  scan(): Array<string>
  scanFiles(input: Array<ChangedContent>): Array<string>
  get files(): Array<string>
  get globs(): Array<GlobEntry>
}
```

The `scanFiles(…)` method is used for incremental rebuilds. It takes the
`ChangedContent` array for all the new/changes files. It returns whether
we scanned any new candidates or not.

Note that the `scanner` object is stateful, this means that we don't
have to track candidates in a `Set` anymore. We can just call
`getCandidates()` when we need it.

This PR also removed some unused code that we had in the `scanDir(…)`
function to allow for sequential or parallel `IO`, and sequential or
parallel `Parsing`. We only used the same `IO` and `Parsing` strategies
for all files, so I just got rid of it.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-08-16 15:05:42 +02:00
Jordan Pittman
1fdf67989f Remove errant console log calls 2024-08-08 15:29:47 -04:00
Philipp Spiess
921b4b673b
Use import to load plugins (#14132)
Alternative to #14110

This PR changes the way how we load plugins to be compatible with ES6
async `import`s. This allows us to load plugins even inside the browser
but it comes at a downside: We now have to change the `compile` API to
return a `Promise`...

So most of this PR is rewriting all of the call sites of `compile` to
expect a promise instead of the object.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-08-08 11:49:06 -04:00
Robin Malfait
541d84a3bb
Add @source support (#14078)
This PR is an umbrella PR where we will add support for the new
`@source` directive. This will allow you to add explicit content glob
patterns if you want to look for Tailwind classes in other files that
are not automatically detected yet.

Right now this is an addition to the existing auto content detection
that is automatically enabled in the `@tailwindcss/postcss` and
`@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use
the auto content detection, but uses the module graph instead.

From an API perspective there is not a lot going on. There are only a
few things that you have to know when using the `@source` directive, and
you probably already know the rules:

1. You can use multiple `@source` directives if you want.
2. The `@source` accepts a glob pattern so that you can match multiple
files at once
3. The pattern is relative to the current file you are in
4. The pattern includes all files it is matching, even git ignored files
1. The motivation for this is so that you can explicitly point to a
`node_modules` folder if you want to look at `node_modules` for whatever
reason.
6. Right now we don't support negative globs (starting with a `!`) yet,
that will be available in the near future.

Usage example:

```css
/* ./src/input.css */
@import "tailwindcss";
@source "../laravel/resources/views/**/*.blade.php";
@source "../../packages/monorepo-package/**/*.js";
```

It looks like the PR introduced a lot of changes, but this is a side
effect of all the other plumbing work we had to do to make this work.
For example:

1. We added dedicated integration tests that run on Linux and Windows in
CI (just to make sure that all the `path` logic is correct)
2. We Have to make sure that the glob patterns are always correct even
if you are using `@import` in your CSS and use `@source` in an imported
file. This is because we receive the flattened CSS contents where all
`@import`s are inlined.
3. We have to make sure that we also listen for changes in the files
that match any of these patterns and trigger a rebuild.

PRs:

- [x] https://github.com/tailwindlabs/tailwindcss/pull/14063
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14085
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14079
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14067
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14076
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14080
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14127
- [x] https://github.com/tailwindlabs/tailwindcss/pull/14135

Once all the PRs are merged, then this umbrella PR can be merged. 

> [!IMPORTANT]  
> Make sure to merge this without rebasing such that each individual PR
ends up on the main branch.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
Adam Wathan
e000caa0bd
Add support for inline option when defining @theme values (#14095)
This PR adds support for a new `inline` option when defining a `@theme`
block that tells Tailwind to use raw theme values for utilities instead
of referencing the corresponding generated CSS variable.

```css
/* Input */
@theme inline {
  --color-red-500: #ef4444;
  /* ... */
}


/* Example output */
:root {
  --color-red-500: #ef4444;
}

.text-red-500 {
  color: #ef4444;
}
```

This can be composed with the existing `reference` option in case you
want to define a `@theme` block as both `reference` (so the variables
aren't generated) and `inline`:

```css
/* Input */
@theme inline reference {
  --color-red-500: #ef4444;
  /* ... */
}


/* Example output */
.text-red-500 {
  color: #ef4444;
}
```

Since you can have multiple `@theme` blocks, you can even define some
values normally and some as inline based on how you're using them. For
example you might want to use `inline` for defining literal tokens like
`--color-red-500`, but include the variable for tokens that you want to
be able to theme like `--color-primary`:

```css
/* Input */
@theme inline {
  --color-red-500: #ef4444;
  /* ... */
}

@theme {
  --color-primary: var(--color-red-500);
}


/* Example output */
:root {
  --color-red-500: #ef4444;
  --color-primary: var(--color-red-500);
}

.text-red-500 {
  color: #ef4444;
}

.text-primary {
  color: var(--color-primary, var(--color-red-500));
}
```

## Breaking changes

Prior to this PR, you could `@import` a stylesheet that contained
`@theme` blocks as reference by adding the `reference` keyword to your
import:

```css
@import "./my-theme.css" reference;
```

Now that `reference` isn't the only possible option when declaring your
`@theme`, this syntax has changed to a new `theme(…)` function that
accepts `reference` and `inline` as potential space-separated values:

```css
@import "./my-theme.css";
@import "./my-theme.css" theme(reference);
@import "./my-theme.css" theme(inline);
@import "./my-theme.css" theme(reference inline);
```

If you are using the `@import … reference` option with an earlier alpha
release, you'll need to update your code to `@import … theme(reference)`
once this PR lands in a release.

## Motivation

This PR is designed to solve an issue pointed out in #14091.

Prior to this PR, generated utilities would always reference variables
directly, with the raw value as a fallback:

```css
/* Input */
@theme {
  --color-red-500: #ef4444;
  /* ... */
}


/* Example output */
:root {
  --color-red-500: #ef4444;
}

.text-red-500 {
  color: var(--color-red-500, #ef4444);
}
```

But this can create issues with variables resolving to an unexpected
value when a theme value is referencing another variable defined on
`:root`.

For example, say you have a CSS file like this:

```css
:root, .light {
  --text-fg: #000; 
}

.dark {
  --text-fg: #fff;
}

@theme {
  --color-fg: var(--text-fg);
}
```

Without `@theme inline`, we'd generate this output if you used the
`text-fg` utility:

```css
:root, .light {
  --text-fg: #000; 
}

.dark {
  --text-fg: #fff;
}

:root {
  --color-fg: var(--text-fg);
}

.text-fg {
  color: var(--color-fg, var(--text-fg));
}
```

Now if you wrote this HTML, you're probably expecting your text to be
the dark mode color:

```html
<div class="dark">
  <h1 class="text-fg">Hello world</h1>
</div>
```

But you'd actually get the light mode color because of this rule:

```css
:root {
  --color-fg: var(--text-fg);
}

.text-fg {
  color: var(--color-fg, var(--text-fg));
}
```

The browser will try to resolve the `--color-fg` variable, which is
defined on `:root`. When it tries to resolve the value, _it uses the
value of `var(--text-fg)` as it would resolve at `:root`_, not what it
would resolve to based on the element that has the `text-fg` class.

So `var(--color-fg)` resolves to `#000` because `var(--text-fg)`
resolved to `#000` at the point in the tree where the browser resolved
the value of `var(--color-fg)`.

By using `@theme inline`, the `.text-fg` class looks like this:

```css
.text-fg {
  color: var(--text-fg);
}
```

With this definition, the browser doesn't try to resolve `--color-fg` at
all and instead resolves `--text-fg` directly which correctly resolves
to `#fff` as expected.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 09:37:30 -04:00
Philipp Spiess
e920442e49
Prefix internal modules with internal-* (#14074)
Last week we discussed bringing in some consistency for our non-public
npm packages in the repo. We discussed using custom namespaces (e.g.
`@tailwindcss-internal`) vs. simple prefixes but it does not matter too
much if we are both consistent with our pattern and it's easy for us to
see whether a plugin is public or not.

Since we have a mixture of public namespaced (`@tailwindcss/*`) and
non-namespaced (`tailwindcss`) packages, I think it would be best if we
use a prefix to signal internal dependencies. This PR proposes we use
`internal-*` as the prefix and renames `test-utils` to
`internal-example-plugin` (since, really, this package is just an
example for the Tailwind plugin system).
2024-07-29 10:58:07 -04:00
Philipp Spiess
a2159e80f5
Add Windows CI (#14065)
This PR changes the GitHub action workflow for V4 to start running all
unit tests and build on both Ubuntu (our current default) _and_ Windows.
This is to ensure we catch issues with paths and other Windows-specific
things sooner. It does, however, not replace testing on Windows.
2024-07-29 16:50:06 +02:00
Alexander Kachkaev
87c9f32cbc
Remove cursor override for :disabled buttons (#14061)
Related to https://github.com/tailwindlabs/tailwindcss/issues/8961 and
https://github.com/tailwindlabs/tailwindcss/pull/8962

Before v4, buttons got this CSS in preflight:


9824cb64a0/src/css/preflight.css (L339-L353)

v4 (`next` branch) no longer has `cursor: pointer` in
[preflight.css](2fe2499635/packages/tailwindcss/preflight.css)

This PR removes additional CSS for `:disabled` buttons. It was meant to
undo an override that is no longer present.
2024-07-29 10:10:15 -04:00
Adam Wathan
54474086c8
Add support for basic addVariant plugins with new @plugin directive (#13982)
* Add basic `addVariant` plugin support

* Return early

* Load plugins right away instead later

* Use correct type for variant name

* Preliminary support for addVariant plugins in PostCSS plugin

* Add test for compounding plugin variants

* Add basic `loadPlugin` support to Vite plugin

* Add basic `loadPlugin` support to CLI

* add `io.ts` for integrations

* use shared `loadPlugin` from `tailwindcss/io`

* add `tailwindcss-test-utils` to `@tailwindcss/cli` and `@tailwindcss/vite`

* only add `tailwindcss-test-utils` to `tailwindcss` as a dev dependency

Because `src/io.ts` is requiring the plugin.

* move `tailwindcss-test-utils` to `@tailwindcss/postcss `

This is the spot where we actually need it.

* use newer pnpm version

* Duplicate loadPlugin implementation instead of exporting io file

* Remove another io reference

* update changelog

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-07-11 09:47:26 -04:00
Robin Malfait
f7686e1982
Add missing utilities that exist in v3 (#13971)
* replace `resize-both` with `resize`

* add missing `fill-none`

* add missing `accent-auto`

* add missing `blur-0` and `backdrop-blur-0`

We already have `blur-none`, but that sets the blur to `' '`, whereas
`blur-0` sets it to `blur(0)`.

* add missing `drop-shadow-none`

* support negative `hue-rotate` utilities

* support negative `backdrop-hue-rotate` utilities

* add missing `max-w-screen-*` utilities

* update changelog

* Revert "add missing `blur-0` and `backdrop-blur-0`"

This reverts commit 7c42e4e25d3c06b312107afb5325df4b452086a6.

* Revert "add missing `max-w-screen-*` utilities"

This reverts commit 0c68e890ccfb68d104b252bdb3a8a2b2c34a0793.
2024-07-10 16:05:16 +02:00
Benoît Rouleau
3b85780f89
Revert “Prevent Preflight from affecting list semantics” (#13907)
Due to difference in how it handles an empty `<li>`: https://codepen.io/benface/pen/MWdRdyY
2024-07-04 11:21:09 -04:00
Benoît Rouleau
332347ed83
Prevent Preflight from affecting list semantics (#13815)
* Prevent Preflight from affecting list semantics

* Use `list-style` property

* Update snapshots

* Update changelog

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-06-14 15:52:50 -04:00
Robin Malfait
5f2d654928
Add rounded-4xl utility (#13827)
* add `rounded-4xl`

* update tests to reflect change

* update changelog
2024-06-12 18:22:37 +02:00
Maxwell Barvian
7347cddb9a
[v4] Switch default breakpoints to rem (#13469)
* Switch breakpoints to rem #8378

* Fix broken test

* Update snapshots

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-04-09 21:04:58 -04:00
Adam Wathan
4aefd26f44
Don't reset ::first-letter in Preflight (#13408)
* Don't reset ::first-letter in Preflight

* Update changelog

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-03-30 08:06:53 -04:00
Jordan Pittman
fee039d82f
Inherit letter spacing in form controls (#13328)
* Inherit letter spacing in form controls

* Update changelog

* Update snapshots
2024-03-22 16:01:39 -04:00
Adam Wathan
b5df5e9202
Use variables with fallbacks for utility classes (#13177)
* Use variables with fallbacks for utility classes

* Update playwright test

* rename `resolveBare` to `resolveValue`

* make private methods really private

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-03-21 18:25:43 +01:00
Kris Braun
dadb096da2
3D transform utilities (#13248)
* 3D rotation utilities

* Validate rotate values

* Replace forEach with for loop

* transform-style, transform-box, and backface-visibility utilities

* Tests for transform utilities

* 'perspective' utility

* Fix tests

* Remove unnecessary suggestion; move function comments

* scale-z

* Fix Intellisense test

* perspective-origin

* scale-3d

* Only include the z component of scale if it's defined

We want to avoid triggerring unnecessary 3D transformations.

* Comment the reason for setting --tw-rotate

* Test full bare rotate

* Fix merge

* Comment on rotate arbitrary value

* perspective bare values

Support `perspective-123` (but not `perspective-potato`)

* scale-3d as a static modifier to scale

Instead of scale-3d taking a separate scale, it modifies scale to apply in three dimensions.

* Test that scale-x overrides scale

* scale arbitrary values

Support arbitrary value for scale (e.g. `scale-[1_2_3.5]`).

* Specify rotation axis using a modifier

Support single rotation angles in line with the [CSS `rotate` property](https://developer.mozilla.org/en-US/docs/Web/CSS/rotate). Using modifiers (e.g. `rotate-45/x`) makes it clearer that the axis of rotation is modified. Thanks @adamwathan for this suggestion.

Composing angles is only supported in CSS via a pipeline of `transform` functions. I'll add arbitrary value support to `transform` next as an escape hatch for those cases that need more complex transformations.

* Use property defaults for scale-3d

* `transform` arbitrary values

Support arbitrary values for `transform`. The `skew-x` and `skew-y` transforms are applied before any arbitrary transformations.

* Add translate-z and translate-3d

Both work the same way as scale-z and scale-3d.

* Add translate-[xyz]-px

* Comment on how skewX and skewY are applied

* Remove unnecessary suggest

* Simplify translate

* Fix up comment on rotate syntax

* Back to rotate-x and rotate-y rather than rotate modifiers

* 3D transform test fixes
2024-03-19 17:52:32 +01:00
Robin Malfait
0ee3508179
Move optimizeCss to the packages where it's used (#13230)
* add `@tailwindcss/optimize` as a separate package

* remove lightningcss from `tailwindcss`

* import `optimizeCss` from `@tailwindcss/optimize`

* ensure we use `src/` files in development

* move `devDependencies` after `dependencies`

Just for consistency

* inline `optimizeCss` in leaf packages

Instead of introducing a custom `@tailwindcss/optimize` package

* update changelog

* fix changelog
2024-03-13 17:25:16 +01:00
Adam Wathan
91fca13981
Don't rely on existence of --default-transition-* variables in transition utilities (#13219)
* Don't rely on existence of --default-transition-* variables in transition utilities

* Update changelog

* Add test with no default transition values defined

* Inline value for --default-transition-timing-function

This is more consistent with how things worked in v3 and ensures things will still work if the user suppresses the output of all CSS variables.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-03-13 12:14:05 -04:00
Robin Malfait
172bc5d822
Add incremental rebuilds to @tailwindcss/postcss (#13170)
* rename PostCSS plugin name from `tailwindcss-v4` to `@tailwindcss/postcss`

* add incremental rebuilds to `@tailwindcss/postcss`

* improve comment

* update changelog

* Simplify nested conditionals

* Simplify more conditionals

* Refactor file modification tracking

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-03-11 15:01:28 -04:00
Robin Malfait
d230f2e13b
Improve incremental builds (#13168)
* ensure we don't crash on deleted files

* change return type of `compile` to include a `rebuild()` function

This will allow us in the future to perform incremental rebuilds after
the initial rebuild. This is purely the API change so that we can
prepare all the call sites to use this new API.

* set `@tailwind utilities` nodes

Instead of replacing the node that represents the `@tailwind utilities`
with the generated AST nodes from the rawCandidates, we will set the
nodes of the `@tailwind utilities` rule to the AST nodes instead.

This way we dont' have to remove and replace the `@tailwind utilities`
rule with `n` new nodes. This will later allow us to track the
`@tailwindcss utilities` rule itself and update its `nodes` for
incremental rebuilds.

This also requires a small change to the printer where we now need to
print the children of the `@tailwind utilities` rule. Note: we keep the
same `depth` as-if the `@tailwindcss utilities` rule was not there.
Otherwise additional indentation would be present.

* move sorting to the `ast.sort()` call

This will allow us to keep sorting AST nodes in a single spot.

* move parser functions to the `DesignSystem`

This allows us to put all the parsers in the `DesignSystem`, this allows
us to scope the parsers to the current design system (the current theme,
current utility values and variants).

The implementation of these parsers are also using a `DefaultMap`
implementation. This allows us to make use of caching and only parse a
candidate, parse a variant or compile AST nodes for a given raw
candidate once if we've already done this work in the past.

Again, this is scoped to the `DesignSystem` itself. This means that if
the corresponding theme changes, then we will create a new
`DesignSystem` entirely and the caches will be garbage collected. This
is important because a candidate like `bg-primary` can be invalid in
`DesignSystem` A, but can be valid in `DesignSystem` B and vice versa.

* ensure we sort variants alphabetically by root

For incremental rebuilds we don't know all the used variants upfront,
which means that we can't sort them upfront either (what we used to do).

This code now allows us to sort the variants deterministically when
sorting the variants themselves instead of relying on the fact that they
used to be sorted before.

The sort itself could change slightly compared to the previous
implementation (especially when you used stacked variants in your
candidates), but it will still be deterministic.

* replace `localeCompare` comparisons

Use cheaper comparisons than `localeCompare` when comparing 2 strings.
We currently don't care if it is 100% correctly sorted, but we just want
consistent sorting. This is currently faster compared to
`localeCompare`.

Another benefit is that `localeCompare` could result in
non-deterministic results if the CSS was generated on 2 separate
computers where the `locale` is different.

We could solve that by adding a dedicated locale, but it would still be
slower compared to this.

* track invalid candidates

When an incoming raw candidates doesn't produce any output, then we can
mark it as an invalid candidate. This will allow us to reduce the amount
of candidates to handle in incremental rebuilds.

* add initial incremental rebuild implementation

This includes a number of steps:

1. Track the `@tailwind utilities` rule, so that we can adjust its nodes
   later without re-parsing the full incoming CSS.
2. Add the new incoming raw candidates to the existing set of
   candidates.
3. Parse the merged set to `compileCandidates` (this can accept any
   `Iterable<string>`, which means `string[]`, `Set<string>`, ...)
4. Get the new AST nodes, update the `@tailwind utilities` rule's nodes
   and re-print the AST to CSS.

* improvement 1: ignore known invalid candidates

This will reduce the amount of candidates to handle. They would
eventually be skipped anyway, but now we don't even have to re-parse
(and hit a cache) at all.

* improvement 2: skip work, when generated AST is the same

Currently incremental rebuilds are additive, which means that we are not
keeping track if we should remove CSS again in development.

We can exploit this information, because now we can quickly check the
amoutn of generated AST nodes.

- If they are the same then nothing new is generated — this means that
  we can re-use the previous compiled CSS. We don't even have to
  re-print the AST because we already did do that work in the past.
- If there are more AST nodes, something new is generated — this means
  that we should update the `@tailwind utilities` rule and re-print the
  CSS. We can store the result for future incremental rebuilds.

* improvement 3: skip work if no new candidates are detected

- We already know a set of candidates from previous runs.
- We also already know a set of candidates that are invalid and don't
  produce anything.

This means that an incremental rebuild could give us a new set of
candidates that either already exist or are invalid.

If nothing changes, then we can re-use the compiled CSS.

This actually happens more often than you think, and the bigger your
project is the better this optimization will be.

For example:

```
// Imagine file A exists:
<div class="flex items-center justify-center"></div>
<button class="text-red-500">Delete</button>
```

```
// Now you add a second file B:
<div class="text-red-500 flex"></div>
```

You just created a brand new file with a bunch of HTML elements and
classes, yet all of the candidates in file B already exist in file A, so
nothing changes to the actual generated CSS.

Now imagine the other hundreds of files that already contain hundreds of
classes.

The beauty of this optimization is two-fold:

- On small projects, compiling is very fast even without this check.
  This means it is performant.
- On bigger projects, we will be able to re-use existing candidates.
  This means it stays performant.

* remove `getAstNodeSize`

We can move this up the tree and move it to the `rebuild` function
instead.

* remove invalid candidate tracking from `DesignSystem`

This isn't used anywhere but only in the `rebuild` of the compile step.
This allows us to remove it entirely from core logic, and move it up the
chain where it is needed.

* replace `throwOnInvalidCandidate` with `onInvalidCanidate`

This was only needed for working with `@apply`, now this logic _only_
exists in the code path where we are handling `@apply`.

* update `compile` API signature

* update callsite of `compile()` function

* fix typo
2024-03-11 14:24:49 -04:00