6114 Commits

Author SHA1 Message Date
Philipp Spiess
ca7b10e7d3
Make --theme(…) return CSS variables (#17036)
Closes #16945

This PR changes the `--theme(…)` function now return CSS `var(…)`
definitions unless used in places where `var(…)` is not valid CSS (e.g.
in `@media (width >= theme(--breakpoint-md))`):

```css
/* input */
@theme {
  --color-red: red;
}
.red {
  color: --theme(--color-red);
}

/* output */
:root, :host {
  --color-red: red;
}
.red {
  color: var(--color-red);
}
```

Furthermore, this adds an `--theme(… inline)` option to the `--theme(…)`
function to force the resolution to be inline, e.g.:

```css
/* input */
@theme {
  --color-red: red;
}
.red {
  color: --theme(--color-red inline);
}

/* output */
.red {
  color: red;
}
```

This PR also changes preflight and the default theme to use this new
`--theme(…)` function to ensure variables are prefixed correctly.

## Test plan

- Added unit tests and a test that pulls in the whole preflight under a
prefix theme.
2025-03-20 12:51:22 +01:00
Philipp Spiess
a1acaeeee0
Export PluginUtils from tailwindcss/plugin (#17299)
Closes #17293

We used to export this in v3 so might as well bring it back for the
`tailwindcss/plugin` export list.
2025-03-20 12:19:45 +01:00
Philipp Spiess
503bad4e75
Use bun-baseline for all x64 builds (#17267)
Closes #17259

This PR now also updates the MacOS x64 build to use `bun-baseline`,
meaning all x64 builds now use baseline for the improved hardware
compatibility.

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-20 12:16:04 +01:00
Robin Malfait
f369e22172
Fix class extraction followed by ( in Slim (#17278)
This PR fixes an issue where using the class shorthand in Slim
templates, followed by an `(` results in the last class being ignored.

E.g.:

```slim
body.border-t-4.p-8(class="#{body_classes}" data-hotwire-native="#{hotwire_native_app?}" data-controller="update-time-zone")
```

This is because we will eventually extract `p-8` but it's followed by an
invalid boundary character `(`.

To solve this, we make sure to replace the `(` with a space. We already
do a similar thing when the classes are followed by an `[`.

One caveat, we _can_ have `(` in our classes, like `bg-(--my-color)`.
But in my testing this is not something that can be used in the
shorthand version.

E.g.:
```slim
div.bg-(--my-color)
```

Compiles to:
```html
<div --my-color="" class="bg-"></div>
```

So I didn't add any special handling for this. Even when trying to
escape the `(`, `-` and `)` characters, it still doesn't work. E.g.:

```slim
div.bg-\(--my-color\)
```

Compiles to:
```html
<div class="bg-">\(--my-color\)</div>
```

# Test plan

1. Added test for the issue
2. Existing tests pass
3. Verified via the extractor tool:

| Before | After |
| --- | --- |
| <img width="958" alt="image"
src="https://github.com/user-attachments/assets/f72c420e-5429-424f-a01d-12f724062bf2"
/> | <img width="958" alt="image"
src="https://github.com/user-attachments/assets/b0cc8f2f-97a8-4fca-8813-3bb1da8d99a8"
/> |

---

Fixes: #17277
2025-03-19 09:50:30 -04:00
Robin Malfait
d698c10836
Ensure multiple --value(…) or --modifier(…) calls don't delete subsequent declarations (#17273)
This PR fixes a bug in the handling of `@utility`. Essentially if you
had a declaration where you used a `--modifier(…)` _and_ a `--value(…)`
and both caused the declaration to be removed, the declaration after the
current one would be removed as well.

This happened because 2 reasons:

1. Once we removed the declaration when we handled `--modifier(…)`, we
didn't stop the walk and kept going.
2. The `replaceWith(…)` code allows you to call the function multiple
times but immediately mutates the AST. This means that if you call it
multiple times that you are potentially removing / updating nodes
followed by the current one.

E.g.:

```css
@utility mask-r-* {
  --mask-right: linear-gradient(to left, transparent, black --value(percentage));
  --mask-right: linear-gradient(
    to left,
    transparent calc(var(--spacing) * --modifier(integer)),
    black calc(var(--spacing) * --value(integer))
  );
  mask-image: var(--mask-linear), var(--mask-radial), var(--mask-conic);
}
```

If this is used as `mask-r-10%`, then the first definition of
`--mask-right` is kept, but the second definition of `--mask-right` is
deleted because both `--modifier(integer)` and `--value(integer)` do not
result in a valid value.

However, the `mask-image` declaration was also removed because the
`replaceWith(…)` function was called twice. Once for
`--modifier(integer)` and once for `--value(integer)`.

# Test plan

1. Added a test to cover this case.
2. Existing tests pass.
3. Added a hard error if we call `replaceWith(…)` multiple times.
2025-03-19 13:25:53 +00:00
Devon Govett
cec7f0557b
Fix segmentation fault when loading @tailwindcss/oxide in a Worker thread (#17276)
When Tailwind is loaded in a Node Worker thread, it currently causes a
segmentation fault on Linux when the thread exits. This is due to a
longstanding issue in Rust that affects all native modules:
https://github.com/rust-lang/rust/issues/91979. I reported this years
ago but unfortunately it is still not fixed, and seems to have gotten
worse in Rust 1.83.0 and later. Looks like Tailwind recently updated
Rust versions and this issue started appearing when run in tools like
Parcel that use worker threads.

The workaround is to prevent the native module from ever being unloaded.
One way to do that is to always load the native module in the main
thread in addition to workers, but this is hard to enforce.
@Brooooooklyn found another method, which is to use a linker option for
this. I tested this on an Ubuntu system and verified it fixed the issue.
You can test with the following script.

```js
// test.js
const {Worker} = require('worker_threads');
new Worker('./worker.js');

// worker.js
require('@tailwindcss/oxide');
```

Without this change, a segmentation fault will occur.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2025-03-18 16:28:20 -04:00
Martijn Cuppens
1564bf092b
Remove redundant line-height from body (#15212)
It was added in #2729 to override line heights set on the body by
modern-normalize. However, it appears that modern-normalize never
included any line-height definitions—only a font-family rule was
present.

Ref:
https://github.com/sindresorhus/modern-normalize/blob/v1.1.0/modern-normalize.css

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-18 12:23:49 +01:00
Robin Malfait
d7c81164da
Pre process <template lang="…"> in Vue files (#17252)
This PR fixes an issue where `<template lang="…">…</template>` in Vue
files should be handled as-if it's the language specified in the `lang`
attribute.

To do this, we added a new Vue pre processor and run the content through
the same pre processor logic as we do for other languages.

Fixes: #17211

# Test plan

1. Added a test to verify this works
2. Existing tests still work

Visually verified against the reproduction in the issue:

| Before | After |
| --- | --- |
| <img width="1273" alt="image"
src="https://github.com/user-attachments/assets/d1accdeb-97cf-48ef-83fb-978832b3e599"
/> | <img width="1273" alt="image"
src="https://github.com/user-attachments/assets/ab7ec19c-b6c4-43be-8845-096ff4e58808"
/> |

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2025-03-17 13:54:37 +00:00
Benoît Rouleau
ebfde316e1
Add safe alignment utilities (#14607)
Fixes #7929 and #12916

This PR adds [safe alignment
utilities](https://www.stefanjudis.com/today-i-learned/safe-unsafe-alignment-in-css-flexbox/)
to Tailwind 4. I opted to include them for every justify/align
content/items/self property, but only for the `end` and `center` values.
I know that it doesn't make sense for `start` (as the point of safe
alignment is to fall back to `start` when it overflows), but I'm not
sure about `space-between`, `space-around`, or other values. I certainly
never encountered a situation where I needed `safe` with those.
2025-03-17 14:09:15 +01:00
Bendegúz Hajnal
1d2d50ee66
Add items-baseline-last utility (#13888)
This PR adds the `items-first-baseline` and `items-last-baseline`
utility classes that can control
[`baseline-position`](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items#formal_syntax)
for the [align-items
property](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items#baseline).

Browser support:
- MDN:
https://developer.mozilla.org/en-US/docs/Web/CSS/align-items#browser_compatibility
- Can I use `first baseline`:
https://caniuse.com/?search=align%20items%3A%20first%20baseline
- Can I use `last baseline`:
https://caniuse.com/?search=align%20items%3A%20last%20baseline

The feature were requested multiple times:

- https://github.com/tailwindlabs/tailwindcss/discussions/13518
- https://github.com/tailwindlabs/tailwindcss/discussions/12406
- https://github.com/tailwindlabs/tailwindcss/discussions/11623
- https://github.com/tailwindlabs/tailwindcss/discussions/4855

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-17 13:51:13 +01:00
Philipp Spiess
d6d913ec39
Don't use color-mix(…) on currentColor (#17247)
Closes #17194

This PR works around a crash when rendering opacity on `currentColor`
(as used by the placeholder styles in preflight) on Safari 16.4 and
Safari 16.5. Unfortunately it seems that the [`color-mix(…)` function is
not compatible with `currentColor` for these versions of
Safari](https://stackoverflow.com/questions/76436497/the-color-mix-property-involving-currentcolor-causes-safari-to-crash).
We tried a few different ways to work around this without success:

- Using an `@supports` media query to target these Safari versions and
overwriting the placeholder still makes these browsers crash.
- Changing the way we apply opacity to `currentColor` in core doesn't
seem to work for non-placeholder values:
https://github.com/tailwindlabs/tailwindcss/issues/17194#issuecomment-2728949181
However, a wrong opacity is still better than a complete browser crash.

The work-around of using the `oklab(…)` function does seem to work for
`::placeholder` styles in preflight though according to our testing so
this PR applies this change to preflight.

## Test plan

- See https://play.tailwindcss.com/WSsSTLHu8h?file=css 
- Tested on Chrome/Safari 16.4/Safari 18.3/Firefox

<img width="564" alt="Screenshot 2025-03-17 at 11 32 47"
src="https://github.com/user-attachments/assets/cfd0db71-f39a-4bc0-bade-cea70afe50ae"
/>
2025-03-17 13:23:02 +01:00
Robin Malfait
448949318e
Fix inferring data type of border-[…] with multiple values (#17248)
This PR fixes an issue where arbitrary values such as
`border-[12px_4px]` were incorrectly producing `border-color` instead of
`border-width` values.

To solve it, I extended the `<line-width>` check to make sure that every
part of the value is a valid `<line-width>`.

In order for a `line-width` to be valid, every part should be one of:

1. A keyword: `thin`, `medium`, `thick`
2. A length: `12px`
3. A number: `0`

Fixes: #17221

# Test plan

1. Added test to verify this works
2. All existing tests pass
2025-03-17 12:35:55 +01:00
depfu[bot]
1a88518d80
Update autoprefixer 10.4.20 → 10.4.21 (patch) (#17229) 2025-03-17 09:59:18 +00:00
depfu[bot]
6b2b26287c
Update eslint 9.20.1 → 9.22.0 (minor) (#17207) 2025-03-17 10:55:59 +01:00
depfu[bot]
48957c5411
Update @playwright/test 1.50.1 → 1.51.0 (minor) (#17184) 2025-03-14 17:39:35 +01:00
Jordan Pittman
50562a9c94
Fix -bg-conic-* utilities (#17174)
The negative versions were missing the `deg` in `<number>deg` so they
didn’t work whoops
2025-03-13 10:13:56 -04:00
Robin Malfait
3c5903c1ee
Prepare v4.0.14 release (#17173) v4.0.14 2025-03-13 12:36:34 +01:00
Robin Malfait
221855b195
Ensure candidate extraction works as expected in Clojure/ClojureScript (#17087)
This PR adds a Clojure/ClojureScript pre processor to make sure that
candidate extraction works as expected.


| Before | After |
| --- | --- |
| <img width="908" alt="image"
src="https://github.com/user-attachments/assets/98aba8b6-0c44-47c6-b87c-ecf955e5e007"
/> | <img width="908" alt="image"
src="https://github.com/user-attachments/assets/7a5ec3eb-1630-4b60-80bd-c07bc2381d3b"
/> |

You can see that the classes preceded by `:` are not properly extracted
in the before case, but they are in the after case. We do extract a few
more cases now like `:class` and `:className` itself, but at least we
also retrieve all the `flex-*` classes.

We could also always ignore `:class` and `:className` literals:
<img width="908" alt="image"
src="https://github.com/user-attachments/assets/f5a67cae-25d6-4811-b777-f72fdb5ef450"
/>
2025-03-13 11:31:27 +01:00
Philipp Spiess
74ccde4672
Upgrade lightningcss to 1.29.2 in Standalone (#17169)
Closes #17162
Closes #17163
Closes #17164
Closes #17165
Closes #17166
Closes #17167

Noticed that there was a second place pulling in the lightningcss
version numbers that wasn't covered by the previous upgrade PR.
Thankfully the APIs of the node bindings are still compatible.

To avoid this mistake in the future I also exported these sub-packages
as a workspace dependency so all the version strings appear right next
to each other.
2025-03-13 11:18:06 +01:00
depfu[bot]
26f91d2a43
Update turbo 2.4.2 → 2.4.4 (patch) (#17157) 2025-03-13 10:50:06 +01:00
Robin Malfait
cedd54fecf
Fix variants with <digit>.</digit> are extracted correctly (#17153)
This PR fixes an issue where if you use a number with a decimal in a
variant then it wasn't picked up correctly.

E.g.:
```
<div class="2xl:flex 1.5xl:flex"></div>
            ^^^^^^^^                        Picked up
                     ^^^^^^^^^^             Not picket up
```

This PR fixes that behavior by applying the same rules for utilities
where a `.` is valid if it is surrounded by numbers.

# Test plan

1. Added test to ensure this is picked up
2. Existing tests pass
3. Ran the extractor on a real example with the following results:

| Before | After |
| --- | --- |
| <img width="821" alt="image"
src="https://github.com/user-attachments/assets/a77ed5e4-6848-4fe3-8cbf-cf61ff8db41d"
/> | <img width="821" alt="image"
src="https://github.com/user-attachments/assets/61aca66a-e38d-4b61-bf86-e6286a89a3d9"
/> |

They are crossed out just because it's not a default value we know in
the system, but you can see that the `1.` part is also extracted now.

Fixes: #17148
2025-03-12 21:04:11 +00:00
Philipp Spiess
215f4f348b
Add @source inline(…) (#17147)
This PR adds a new experimental feature that can be used to force-inline
utilities based on an input string. The idea is that all utilities
matching the source string will be included in your CSS:

```css
/* input.css */
@source inline('underline');

/* output.css */
.underline {
   text-decoration: underline;
}
```

Additionally, the source input is brace-expanded, meaning you can use
one line to inline a whole namespace easily:
```css
/* input.css */
@source inline('{hover:,}bg-red-{50,{100..900..100},950}');

/* output.css */
.bg-red-50 {
  background-color: var(--color-red-50);
}
.bg-red-100 {
  background-color: var(--color-red-100);
}
.bg-red-200 {
  background-color: var(--color-red-200);
}
.bg-red-300 {
  background-color: var(--color-red-300);
}
.bg-red-400 {
  background-color: var(--color-red-400);
}
.bg-red-500 {
  background-color: var(--color-red-500);
}
.bg-red-600 {
  background-color: var(--color-red-600);
}
.bg-red-700 {
  background-color: var(--color-red-700);
}
.bg-red-800 {
  background-color: var(--color-red-800);
}
.bg-red-900 {
  background-color: var(--color-red-900);
}
.bg-red-950 {
  background-color: var(--color-red-950);
}
@media (hover: hover) {
  .hover\\:bg-red-50:hover {
    background-color: var(--color-red-50);
  }
  .hover\\:bg-red-100:hover {
    background-color: var(--color-red-100);
  }
  .hover\\:bg-red-200:hover {
    background-color: var(--color-red-200);
  }
  .hover\\:bg-red-300:hover {
    background-color: var(--color-red-300);
  }
  .hover\\:bg-red-400:hover {
    background-color: var(--color-red-400);
  }
  .hover\\:bg-red-500:hover {
    background-color: var(--color-red-500);
  }
  .hover\\:bg-red-600:hover {
    background-color: var(--color-red-600);
  }
  .hover\\:bg-red-700:hover {
    background-color: var(--color-red-700);
  }
  .hover\\:bg-red-800:hover {
    background-color: var(--color-red-800);
  }
  .hover\\:bg-red-900:hover {
    background-color: var(--color-red-900);
  }
  .hover\\:bg-red-950:hover {
    background-color: var(--color-red-950);
  }
}

```

This feature is also compatible with the `not` keyword that we're about
to add to `@source "…"` in a follow-up PR. This can be used to set up an
ignore list purely in CSS. The following code snippet, for example, will
ensure that the `.container` utility is never created:

```css
@theme {
  --breakpoint-sm: 40rem;
  --breakpoint-md: 48rem;
  --breakpoint-lg: 64rem;
  --breakpoint-xl: 80rem;
  --breakpoint-2xl: 96rem;
}
@source not inline("container");
@tailwind utilities;
```

## Test plan

- See added unit tests
- The new brace expansion library was also benchmarked against the
popular `braces` library:
  ```
  clk: ~3.96 GHz
  cpu: Apple M4 Max
  runtime: bun 1.1.34 (arm64-darwin)

benchmark avg (min … max) p75 / p99 (min … top 1%)
-------------------------------------------
-------------------------------
braces 31.05 ms/iter 32.35 ms █ █
(28.14 ms … 36.35 ms) 35.14 ms ██ █
( 0.00 b … 116.45 mb) 18.71 mb ██████▁▁▁██▁█▁██▁█▁▁█

./brace-expansion 19.34 ms/iter 21.69 ms █
(12.53 ms … 26.63 ms) 25.53 ms ▅ ▅ █ █
( 0.00 b … 114.13 mb) 11.86 mb █▁▅▁██▁▅█▅█▅▁█▅█▅▅▁▅█

┌ ┐
╷┌────┬─┐ ╷
braces ├┤ │ ├─────┤
╵└────┴─┘ ╵
                              ╷        ┌────┬───┐       ╷
            ./brace-expansion ├────────┤    │   ├───────┤
                              ╵        └────┴───┘       ╵
└ ┘
12.53 ms 23.84 ms 35.14 ms
  ```

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-12 13:55:33 +00:00
Robin Malfait
ca408d0612
Do not extract candidates containing JS string interpolation pattern ${ (#17142)
This PR fixes an issue where often people run into issues where they try
to use string interpolation and it doesn't work. Even worse, it could
result in crashes because we will actually generate CSS. This fix only
filters out candidates with a pattern like `${`. If this occurs in a
string position it is fine.

Another solution would be to add a pre processor for JS/TS (and all
thousand file extension combinations) but the problem is that you can
also write JS in HTML files so we would have to pre process HTML as well
which would not be ideal.

# Test plan

1. Added tests to prove this works in arbitrary values, arbitrary
variables in both utilities and variants.
2. Existing tests pass.
3. Some screenshots with before / after situations:

Given this input:
```ts
let color = '#0088cc';
let opacity = 0.8;
let name = 'variable-name';
let classes = [
  // Arbitrary Properties
  `[color:${color}]`
  `[${property}:value]`,
  `[--img:url('https://example.com?q=${name}')]`, // WONT WORK BUT VALID CSS

  // Arbitrary Values
  `bg-[${color}]`,

  // Arbitrary Variables
  `bg-(--my-${color})`,
  `bg-(--my-color,${color})`,

  // Arbitrary Modifier
  `bg-red-500/[${opacity}]`,
  `bg-red-500/(--my-${name})`,
  `bg-red-500/(--my-opacity,${opacity})`,

  // Arbitrary Variant
  `data-[state=${name}]:flex`,
  `supports-(--my-${name}):flex`,
  `[@media(width>=${value})]:flex`,
];
```

This is the result:

| Before | After |
| --- | --- |
| <img width="908" alt="image"
src="https://github.com/user-attachments/assets/c64d1b16-d39d-48a6-a098-bc4477cb4b0a"
/> | <img width="908" alt="image"
src="https://github.com/user-attachments/assets/d71aaf62-5e13-4174-82bb-690eb81aaeaf"
/> |

Fixes: #17054
Fixes: #15853
2025-03-12 12:09:13 +01:00
Robin Malfait
4455048c0b
Prepare release 4.0.13 (#17132) v4.0.13 2025-03-11 17:58:53 +01:00
Robin Malfait
37062928f9
Improve candidate extraction when candidates contain . characters (#17113)
This PR fixes an issue where some classes weren't properly extracted due
to some incorrect assumptions in the pre processors.

Templating languages such as Haml, Slim and Pug allow you to write
classes in a shorter way that are not properly contained inside of
strings. E.g.:
```slim
p.flex.px-2
```

These candidates are not properly extracted because there are no
bounding characters like quotes. To solve this, we pre-process it and
replace `.` with ` ` characters. This results in something like:
```
p flex px-2
```

However, this has some challenges on its own. Candidates like `px-2.5`
cannot be written in this shorthand form, instead they need to be in
strings. Now we _cannot_ replace the `.` because otherwise we would
change `px-2.5` to `px-2 5` which is wrong.

The next problem is that we need to know when they are in a "string".
This has another set of problems because these templating languages
allow you to write normal text that will eventually be the contents of
the HTML tags.

```haml
.text-red-500.text-3xl
  | This text can't should be red
                 ^ Wait, is this the start of a string now???
```

In this example, if we consider the `'` the start of a string, when it's
clearly not, how would we know it's for _sure_ not a string?

This ended up as a bit of a rabbit hole, but we came up with another
approach entirely if we think about the original problem we want to
solve which is when do we change `.` to ` ` characters.

One of the rules in our current extractor is that a `.` has to be
between 2 numbers. Which works great in a scenario like: `px-2.5`.
However, if you look at Haml or Slim syntax, this is also allowed:

```slim
p.bg-red-500.2xl:flex
           ^^^ Uh oh...
```

In this scenario, a `.` is surrounded by numbers so we shouldn't replace
it with a space. But as you can see, we clearly do... so we need another
heuristic in this case.

Luckily, one of the rules in Tailwind CSS is that a utility cannot start
with a number, but a variant _can_. This means that if we see a scenario
like `<digit>.<digit>` then we can just check if the value after the `.`
is a valid variant or not.

In this case it is a valid variant so we _do_ want to replace the `.`
with a ` ` even though we do have the `<digit>.<digit>` format.

🥴

# Test plan

1. Added additional tests.
2. Existing tests still pass

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-11 17:53:16 +01:00
Robin Malfait
22746e6a6b
drop mise.toml 2025-03-11 17:49:30 +01:00
Philipp Spiess
9d7f25316e
Don't extract links as arbitrary properties (#17129)
Closes #17128

This PR prevents extraction of links inside square brackets as valid
candidate:

```
[https://example/]
```

We do this by throwing out arbitrary properties when the value starts
with a slash (`/`).

## Test plan

- Added unit test

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-11 16:40:24 +00:00
Philipp Spiess
785cadeb21
Upgrade lightningcss (#17043)
Part of #15897
2025-03-11 17:39:30 +01:00
Robin Malfait
9ddeb091d7
Add JSON pre-processor (#17125)
This PR adds a small JSON pre processor to improve parsing JSON files.

Due to the sheer amount of potential `[` and `]` brackets, it could be
that parsing JSON files are way slower than they need to be.

We saw this while debugging this issue:
https://github.com/tailwindlabs/tailwindcss/issues/17092


# Test plan

1. Added test to verify the pre processing works
2. Existing tests still pass
2025-03-11 12:15:48 +00:00
Philipp Spiess
8bc633bb17
Add .node and .wasm to known binary file list (#17123)
Closes #17092

After a lot of spelunking we found one specific reason for the very slow
builds in the repro from #17092: Turns our we are needlessly scanning
the binary `.node` extension for class names 😬. This PR adds `.wasm` and
`.node` to the list of known binary extensions.

## Test plan

 - Check out the repro from `#17092`
 - Delete the `.gitignore` file
 - Observe that builds are very slow (`527.79s`)
 - Add a _pnpm override_ to load local versions of Oxide
 - `pnpm build` now completes in ~50s
2025-03-11 13:05:51 +01:00
depfu[bot]
5e2633bb6d
Update all of nextjs 15.1.7 → 15.2.1 (minor) (#17118) 2025-03-11 12:06:10 +01:00
depfu[bot]
a57cd2dce8
Update postcss 8.5.2 → 8.5.3 (patch) (#17116) 2025-03-11 10:58:22 +01:00
Robin Malfait
de145c5b06
Refactor: use compile time type state pattern (#17083)
This PR implements the state machines using the type state pattern at
compile time (via generic types) instead of a runtime state variable.
There is no runtime check to see what state we are in, instead we
transition to the new state when it's necessary.

This has some nice performance improvements for some of the state
machines, e.g.:

```diff
- ArbitraryVariableMachine: Throughput: 744.92 MB/s
+ ArbitraryVariableMachine: Throughput:   1.21 GB/s
```

We also don't have to store the current state because each machine runs
to completion. It's during execution that we can move to a new state if
necessary.


Unfortunately the diff is a tiny bit annoying to read, but essentially
this is what happened:

### The `enum` is split up in it's individual states as structs:
```rs
enum State {
  A,
  B,
  C,
}
```
Becomes:
```rs
struct A;
struct B;
struct C;
```

### Generics

The current machine will receive a generic `State` that we can default
to the `IdleState`. Then we use `PhantomData` to "use" the type because
the generic type is otherwise not used as a concrete value, it's just a
marker.

```rs
struct MyMachine {}
```
Becomes:
```rs
struct MyMachine<State = Idle> {
  _state: std::marker::PhantomData<State>
}
```

### Split 

Next, the `next` function used to match on the current state, but now
each match arm is moved to a dedicated implementation instead:
```rs
impl Machine for MyMachine {
  fn next(&mut self) -> MachineState {
    match self.state {
      State::A => { /* … */ },
      State::B => { /* … */ },
      State::C => { /* … */ },
    }
  }
}
``` 
Becomes:
```rs
impl Machine for MyMachine<A> {
  fn next(&mut self) -> MachineState {
    /* … */
  }
}
impl Machine for MyMachine<B> {
  fn next(&mut self) -> MachineState {
    /* … */
  }
}
impl Machine for MyMachine<C> {
  fn next(&mut self) -> MachineState {
    /* … */
  }
}
```

It's a bit more verbose, but now each state is implemented in its own
block. This also removes 2 levels of nesting which is a nice benefit.
2025-03-10 14:08:39 -04:00
Robin Malfait
cc3e852791
Treat starting single quote as verbatim text in Slim (#17085)
This PR fixes an issue in Slim templates where a single quote `'` at the
start of the line (excluding white space) is considered a line indicator
for verbatim text. It is not considered a string in this scenario.

So something like this:
```slim
div
  'Foo'
```

Will compile to:
```html
<div>Foo'</div>
```

Fixes: #17081
2025-03-10 11:45:26 +01:00
Robin Malfait
bc5a8c3683
Ensure classes between > and < are properly extracted (#17094)
This PR fixes an issue where candidates inside `>…<` were not always
correctly extracted. This happens in XML-like languages where the
classes are inside of these boundaries.

E.g.:
```html
<!-- Fluid template language -->
<f:variable name="bgStyle">
  <f:switch expression="{data.layout}">
    <f:case value="0">from-blue-900 to-cyan-200</f:case>
    <!--              ^^^^^^^^^^^^^^^^^^^^^^^^^      -->
    <f:case value="1">from-cyan-600 to-teal-200</f:case>
    <f:defaultCase>from-blue-300 to-cyan-100</f:defaultCase>
  </f:switch>
</f:variable>
```


Fixes: https://github.com/tailwindlabs/tailwindcss/issues/17088

# Test plan

1. Added a new test
2. Existing tests pass
2025-03-10 11:28:08 +01:00
Robin Malfait
7005ad7e00
Add Haml pre processor (#17051)
This PR ensures we extract candidates from Haml files.

Fixes: #17050
2025-03-07 22:32:15 +01:00
Robin Malfait
2f28e5fbcb
Prepare v4.0.12 release (#17033)
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
v4.0.12
2025-03-07 12:38:53 +01:00
Robin Malfait
f498e4a97c
Ensure extracting candidates from JS embedded in a PHP string works as expected (#17031)
This PR fixes an issue where candidates are not properly extractor when
they end in `\`. This can happen if you embed a programming language
like JS inside another language like PHP where you need to escape some
strings.

Here is an example of Livewire flux:
```blade
@php
if ($sidebarIsStashable) {
    $attributes = $attributes->merge([
        'x-init' => '$el.classList.add(\'-translate-x-full\'); $el.classList.add(\'transition-transform\')',
        //                                                ^                                            ^
    ]);
}
@endphp

<div x-data {{ $attributes->class('border-r w-64 p-4 min-h-dvh max-h-dvh top-0 fixed left-0') }}>
    {{ $slot }}
</div>
```
Where the `\'` is causing some issues.

Another solution might be to add a custom pre processor for blade files
where we drop the escaped characters, but that felt overkill for now
because some escapes are still valid.

Fixes: #17023

# Test plan

1. Added a test to cover this case.
2. Existing tests still pass
2025-03-07 12:19:01 +01:00
Philipp Spiess
225f3233b6
Enable URL rewriting for PostCSS (#16965)
Fixes #16636 

This PR enables URL rebasing for PostCSS. Furthermore it fixes an issue
where transitive imports rebased against the importer CSS file instead
of the input CSS file. While fixing this we noticed that this is also
broken in Vite right now and that our integration test swallowed that
when testing because it did not import any Tailwind CSS code and thus
was not considered a Tailwind file.

## Test plan

- Added regression integration tests
- Also validated it against the repro of
https://github.com/tailwindlabs/tailwindcss/issues/16962:
  
<img width="1149" alt="Screenshot 2025-03-05 at 16 41 01"
src="https://github.com/user-attachments/assets/85396659-d3d0-48c0-b1c7-6125ff8e73ac"
/>

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2025-03-07 12:18:10 +01:00
Robin Malfait
d18fed1dca
Add razor/cshtml pre processing (#17027)
This PR fixes an issue in Razor template files where `@sm:flex` doesn't
work and `@@sm:flex` is required.

In Tailwind CSS v3, some people used a custom transform to replace `@@`
with just `@`. But in Tailwind CSS v4 we don't have this.

However, we can add a pre processor for `.cshtml` and `.razor` files.

Fixes: #17022
2025-03-07 12:02:07 +01:00
depfu[bot]
bd1e540776
Update h3 1.15.0 → 1.15.1 (patch) (#17010) 2025-03-07 12:00:44 +01:00
Robin Malfait
d0a97467f4
Improve boundary classification (#17005)
This PR cleans up the boundary character checking by using similar
classification techniques as we used for other classification problems.

For starters, this moves the boundary related items to its own file,
next we setup the classification enum.

Last but not least, we removed `}` as an _after_ boundary character, and
instead handle that situation in the Ruby pre processor where we need
it. This means the `%w{flex}` will still work in Ruby files.

---

This PR is a followup for
https://github.com/tailwindlabs/tailwindcss/pull/17001, the main goal is
to clean up some of the boundary character checking code. The other big
improvement is performance. Changing the boundary character checking to
use a classification instead results in:

Took the best score of 10 runs each:
```diff
- CandidateMachine: Throughput: 311.96 MB/s
+ CandidateMachine: Throughput: 333.52 MB/s
```

So a ~20MB/s improvement.

# Test plan

1. Existing tests should pass. Due to the removal of `}` as an after
boundary character, some tests are updated.
2. Added new tests to ensure the Ruby pre processor still works as
expected.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2025-03-07 00:00:54 +00:00
Robin Malfait
57e91a671a
Ensure } and { are valid boundary characters (#17001) 2025-03-06 20:40:03 +01:00
Robin Malfait
85c6e04f44
Ensure strings in Pug and Slim templates are handled correctly (#17000)
This PR fixes an issue where strings in the Pug and Slim pre-processor
were handled using the `string_machine`. However, the `string_machine`
is not for strings inside of Tailwind CSS classes which means that
whitespace is invalid.

This means that parts of the code that _are_ inside strings will not be
inside strings and parts of the code that are not inside strings will be
part of a potential string. This is a bit confusing to wrap your head
around, but here is a visual representation of the problem:

```
.join(' ')
        ^  3. start of new string, which means that the `)` _could_ be part of a string if a new `'` occurs later.
       ^   2. whitespace is not allowed, stop string
      ^    1. start of string
```

Fixes: #16998

# Test plan

1. Added new test
2. Existing tests still pass
3. Added a simple test helper to make sure that we can extract the
correct candidates _after_ pre-processing
2025-03-06 17:24:00 +01:00
Philipp Spiess
3d0606b82d
Fix sorting of classes that have undefined declarations (#16995)
Closes #16973

Declaration values of `undefined` are an implementation detail and
skipped when printing the CSS. Thus, these should not count towards the
sort order at a..

## Test plan

- See added regression test
2025-03-06 15:20:12 +01:00
Philipp Spiess
b676da8ace
Prepare v4.0.11 release (#16987) v4.0.11 2025-03-06 11:09:39 +00:00
Philipp Spiess
bff387bf6b
Ensure arbitrary variables with data types are extracted correctly (#16986)
Closes #16983

This PR fixes an issue where the arbitrary variable machine did not
extract data type correctly.

## Test plan

- Added regression test
2025-03-06 12:05:33 +01:00
Robin Malfait
af132fbedb
Fix Slim attributes (#16985)
This PR fixes an issue in Slim templates where the start of attributes
causes some candidates to be missing.


```slim
.text-xl.text-red-600[
  data-foo="bar"
]
  | This line should be red
```

Because of the `[` attached to the `text-red-600`, the `text-red-600`
was not extracted because `[` is not a valid boundary character.

To solve this, we copied the Pug pre processor and created a dedicated
Slim pre processor. Next, we ensure that we replace `[` with ` ` in this
scenario (by also making sure that we don't replace `[` where it's
important).

Additionally, we noticed that `.` was also replaced inside of arbitrary
values such as URLs. This has been fixed for both Pug and Slim.

Fixes: #16975

# Test plan

1. Added failing tests
2. Existing tests still pass
2025-03-06 11:59:14 +01:00
Philipp Spiess
617b7abb81
Oxide: Extract arbitrary container queries (#16984)
Closes #16982

Handle the case of variants looking like this: `@[32rem]:flex`.

## Test plan

Added regression tests

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2025-03-06 11:55:42 +01:00
Hyunmin Woo (Hanul)
4a0236471e
Ensure classes containing number followed by dash or underscore are extracted correctly (#16980)
Fixes #16978, and also added support for dash.
Classes like `text-theme1-primary` or `text-theme1_primary` should be
treated as valid.

If this approach is not aligned with the project’s direction or there
are any concerns, please feel free to close or edit this PR 😃

<br/>

### As is

Classes conatining number followed by dash or underscore (e.g.
`bg-theme1-primary`, `text-title1_strong`) are ignored, and utility
classes are not generated.

### To be

Classes conatining number followed by dash or underscore (e.g.
`bg-theme1-primary`, `text-title1_strong`) are treated as valid
tailwindcss classes

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2025-03-06 11:44:43 +01:00