Commit graph

6391 commits

Author SHA1 Message Date
Robin Malfait
23cee5c6e0
Allow anchor-size(…) in arbitrary values (#14394)
This PR fixes an issue where using `anchor-size` in arbitrary values
resulted in the incorrect css.

Input: `w-[calc(anchor-size(width)+8px)]`
Output:
```css
.w-\[calc\(anchor-size\(width\)\+8px\)\] {
  width: calc(anchor - size(width) + 8px);
}
```

This PR fixes that, by generating the correct CSS:
```css
.w-\[calc\(anchor-size\(width\)\+8px\)\] {
  width: calc(anchor-size(width) + 8px);
}
```
2024-09-17 17:44:17 +02:00
Philipp Spiess
9ef4aaa7d9
Create variants for aria, supports, and data JS config theme keys (#14407)
This PR adds support for the `aria`, `supports`, and `data` properties
found in JS config options. In v3, you could extend the theme to add
more variants by using an object syntax like this:

```ts
{
   theme: {
    extend: {
      aria: {
        polite: 'live="polite"',
      },
      supports: {
        'child-combinator': 'h2 > p',
      },
      data: {
        checked: 'ui~="checked"',
      },
    },
  }
}
```

Since we no longer rely on theme variables for these variants, the way
to make this work is by adding custom variants for each of these
manually added variants.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-17 17:09:42 +02:00
Philipp Spiess
ebaff18a9f
Fix stacking variant order when variants inside a group are treated as equal (#14431)
This PR fixes an issue with the order of CSS when using stacked variants
when two variants have the same order (as defined by the custom
comperator function).

## The problem

Take, for example, our breakpoint variants. Those are split into `max-*`
variants and a group containing all `min-*` variants as well as the
unprefixed static ones (e.g. `lg`, `sm`).

We currently define a custom sort order for all breakpoints variants
that will compare their order based on the resolved value provided. So
if you define `--breakpoint-sm: 100px` and `--breakpoint-lg: 200px`, we
first check if both breakpoints have the same unit and then we rank
based on the numerical value, making `sm` appear before `lg`.

But since the `min-*` variant and the `sm` variant share the same group,
this also means that `min-sm` and `sm` as well as `min-lg` and `lg` will
always have the same order (which makes sense—they also have the exact
same CSS they generate!)

The issue now arises when you use these together with variant stacking.
So, say you want to stack the two variants `max-lg:min-sm`. We always
want stacked variants to appear _after_ their non-stacked individual
parts (since they are more specific). To do this right now, we generate
a bitfield based on the variant order. If you have four variants like
this:


| Order | Variant |
| ------------- | ------------- |
| 0  | `max-lg`  |
| 1  | `max-sm`  |
| 2  | `min-sm`  |
| 3  | `min-lg`  |


We will assign one bit for each used variant starting from the lowest
bit, so for the stack `max-lg:min-sm` we will set the bitfield to `0101`
and those for the individual variants would result in `0100` (for
`min-sm`) and `0001` (for `max-lg`). We then convert this bitfield to a
number and order based on that number. This ensures that the stack
always sorts higher.

The issue now arises from the fact that the variant order also include
the unprefixed variants for a breakpoint. So in our case of `lg` and
`sm`, the full list would look like this:


| Order | Variant |
| ------------- | ------------- |
| 0  | `max-lg`  |
| 1  | `max-sm`  |
| 2  | `min-sm`  |
| 3  | `sm`  |
| 4  | `min-lg`  |
| 5  | `lg`  |

This logic now breaks when you start to compute a stack for something
like `max-lg:min-lg` _while also using the `lg` utility:

| Stack | Bitmap | Integer Value |
| ------------- | ------------- | ------------- |
| `max-lg:min-lg` | `010001` | 17 |
| `lg` | `100000` | 18 |

As you can see here, the sole `lg` variant will now sort higher than the
compound of `max-lg:min-lg`. That's not something we want!

## Proposed solution

To fix this, we need to encode the information of _same_ variant order
somehow. A single array like the example above is not sufficient for
this, since it will remove the information of the similar sort order.
Instead, we now computed a list of nested arrays for the order lookup
that will combine variants of similar values (while keeping the order
the same). So from the 6 item array above, we now have the following
nested array:

| Order | Variant |
| ------------- | ------------- |
| 0  | [`max-lg`]  |
| 1  | [`max-sm`]  |
| 2  | [`min-sm`, `sm`]  |
| 3  | [`min-lg`, `lg`]  |

When we use the first layer index for the bitfield, we can now see how
this solves the issue:

| Stack | Bitmap | Integer Value |
| ------------- | ------------- | ------------- |
| `max-lg:min-lg` | `1001` | 9 |
| `lg` | `1000` | 8 |

That's pretty-much it! There are a few other changes in this PR that
mostly handles with a small regression by this change where now, named
`group` variants and unnamed `group` variants would now have the same
order (something that was undefined behavior before).

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-17 17:00:12 +02:00
Philipp Spiess
c7cbdb8472
Resolve borderRadius when using dot notation inside the theme() function (#14436)
Fixes an issue where `borderRadius` was not properly upgraded when using
it in the `theme()` function like this:

```
rounded-[theme(borderRadius.lg)]
```

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-17 10:54:36 +02:00
Philipp Spiess
d9aad773aa
Further clean up compatibility APIs (#14408)
This PR builds on top of #14365 and adds a few more changes we discussed
during a sync on the latter PR:

- We now split `plugin-api.ts` into two files and moved it into
`compat/`. One file is now defining the comat plugin API only where as
another file deals with the compat hook.
- The walk for `@plugin` and `@config` is now happening inside the
compat hook.

The one remaining work item is to change the `loadPlugin` and
`loadConfig` APIs to a more unified `resolveModule` one that does not
care on what we try to load it for. I suggest we should make this change
at the same time we start working on finalizing the `tailwindcss` APIs,
since a lot of things will have to be rethought then anyways.
2024-09-13 11:26:08 +02:00
Philipp Spiess
adde6b07d3 Update change log to match release notes 2024-09-12 16:29:17 +02:00
Philipp Spiess
2ef87ab7fb
Release v4.0.0-alpha.24 (#14395) 2024-09-12 16:10:56 +02:00
Philipp Spiess
0eff7e7c57 Increase CI timeouts for Windows intergarion tests 2024-09-12 15:41:07 +02:00
Philipp Spiess
52f2993069
Pin rust toolchain to work around Windows regression (#14406)
This PR works around a current regression in the Rust toolchain that
caused our Windows workers to start failing with:

```
    Finished `test` profile [unoptimized + debuginfo] target(s) in 32.63s
     Running unittests src\lib.rs (target\debug\deps\tailwind_oxide-ce6a5d43a3798437.exe)
Load Node-API [napi_get_last_error_info] from host runtime failed: GetProcAddress failed
fatal runtime error: thread::set_current should only be called once per thread
Load Node-API [napi_get_uv_event_loop] from host runtime failed: GetProcAddress failed
Load Node-API [napi_fatal_exception] from host runtime failed: GetProcAddress failed
Load Node-API [napi_create_threadsafe_function] from host runtime failed: GetProcAddress failed
error: test failed, to rerun pass `-p tailwind-oxide --lib`
```

The workaround is to pin the rust toolchain version so that the
regression isn't applied when we build on Windows in test mode.
2024-09-12 14:07:43 +02:00
Philipp Spiess
7244f276c8
Don't assert on mangled CSS names (#14397)
This PR fixes an issue with the regex rule I oh-so-carefully constructed
that would fail the regex when the _randomness_ part contains a `t`
😶‍🌫️.
2024-09-11 17:37:36 +02:00
Philipp Spiess
63390c97b2
Throw a useful error when tailwindcss is used as a PostCSS plugin (#14378)
While upgrading a project to Tailwind CSS v4, I forgot to remove the
`tailwindcss` import from the PostCSS config. As a result of this, I was
greeted with the following message:

```
node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /Users/philipp/dev/project): [TypeError] Invalid PostCSS Plugin found at: plugins[0]

(@/Users/philipp/dev/project/postcss.config.js)
TypeError: Invalid PostCSS Plugin found at: plugins[0]
```

I don't think this was particularly helpful, so I’m proposing we add a
default function export to the `tailwindcss` package so when it's used
inside PostCSS, we can control the error message. So I changed it to
something along these lines:

```
It looks like you're trying to use the \`tailwindcss\` package as a PostCSS plugin. This is no longer possible since Tailwind CSS v4.

If you want to continue to use Tailwind CSS with PostCSS, please install \`@tailwindcss/postcss\` and change your PostCSS config file.
    at w (/Users/philipp/dev/project/node_modules/tailwindcss/node_modules/tailwindcss/dist/lib.js:1:21233)
    at Object.<anonymous> (/Users/philipp/dev/project/node_modules/tailwindcss/postcss.config.cjs:3:13)
    at Module._compile (node:internal/modules/cjs/loader:1358:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
    at Module.load (node:internal/modules/cjs/loader:1208:32)
    at Module._load (node:internal/modules/cjs/loader:1024:12)
    at cjsLoader (node:internal/modules/esm/translators:348:17)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:297:7)
    at ModuleJob.run (node:internal/modules/esm/module_job:222:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:316:24)
```

This is also a good place to link to the migration guides once we have
them 🙂

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-11 17:02:24 +02:00
Philipp Spiess
d2b5731811
Intellisense: Add example bare values to border completions (#14370)
Closes
https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1048

This PR adds a few bare value examples for border width completions. The
examples are taken from [our
docs](https://tailwindcss.com/docs/border-width).
2024-09-11 16:59:18 +02:00
Philipp Spiess
1e0dfbc6d0
Add matchVariant API (#14371)
This PR adds support for the `matchVariant` plugin API. I've copied over
all [V3
tests](f07dbff2a7/tests/match-variants.test.js)
and made sure they still pass.

## Sorted order of stacked arbitrary variants

The only difference in behavior is regarding the sort order of stacked
arbitrary variants: Sorting in this case now works by the latest defined
`matchVariant` taking precedence.

So, if you define a plugin like this:

```ts
matchVariant('testmin', (value) => `@media (min-width: ${value})`, {
  sort(a, z) {
    return parseInt(a.value) - parseInt(z.value)
  },
})

matchVariant('testmax', (value) => `@media (max-width: ${value})`, {
  sort(a, z) {
    return parseInt(z.value) - parseInt(a.value)
  },
})
```

The resulting CSS is first sorted by the `testmax` values descending and
then the `testmin` values ascending, so these candidates:

```txt
testmin-[150px]:testmax-[400px]:order-2
testmin-[100px]:testmax-[350px]:order-3
testmin-[100px]:testmax-[300px]:order-4
testmin-[100px]:testmax-[400px]:order-1
```

Will resolve to the order outlined by the `order-` utility.

## At-rules and placeholders support

Since we added support for at-rules and placeholders in the
`matchVariant` syntax like this:

```ts
matchVariant(
  'potato',
  (flavor) => `@media (potato: ${flavor}) { @supports (font:bold) { &:large-potato } }`,
)
```

We also added support for the same syntax to the `addVariant` API:

```ts
addVariant(
  'potato',
  '@media (max-width: 400px) { @supports (font:bold) { &:large-potato } }',
)
```

The only change necessary in core was to call functional variants for
when the variant value is set to `null`. This allows functional variants
to define the un-parameterized implementation like `potato:underline` as
opposed to `potato[big]:underline`.

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-11 16:45:07 +02:00
Adam Wathan
8b0fff6edd
Extract more backwards compatibility logic to compatibility layer (#14365)
I noticed a lot more backwards compatibility concerns had started
leaking into core, especially around the `theme` function, so did a bit
of work to try and pull that stuff out and into the compatibility layer.

Now the core version of `theme` only handles CSS variables (like
`--color-red-500`) and has no knowledge of the dot notation or how to
upgrade it. Instead, we unconditionally override that function in the
compatibility layer with a light version that _does_ know how to do the
dot notation upgrade, and override that again with the very heavy/slow
version that handles JS config objects only if plugins/JS configs are
actually used.

I've also renamed `registerPlugins` to `applyCompatibilityHooks` because
the name was definitely a bit out of date given how much work it's doing
now, and now call it unconditionally from core, leaving that function to
do any conditional optimizations itself internally.

Next steps I think would be to split up `plugin-api.ts` a bit and maybe
make `applyCompatibilityHooks` its own file, and move both of those
files into the `compat` folder so everything is truly isolated there.

My goal with this stuff is that if/when we ever decide to drop backwards
compatibility with these features in the future (maybe v5), that all we
have to do is delete the one line of code that calls
`applyCompatibilityHooks` in `index.ts`, and delete the `compat` folder
and we're done. I could be convinced that this isn't a worthwhile goal
if we feel it's making the codebase needlessly complex, so open to that
discussion as well.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-11 16:17:02 +02:00
Jordan Pittman
8c6c291869
Make config resolution lazy (#14362)
The internal `registerPlugins()` API is used to enable backwards
compatibility with v3 plugins and configs and it is called on every
build even when no v3 plugins or configs are used. This function has a
non-trivial cost in that case — around 5ms.

So this PR does a few things:

## Implements a simpler, faster `theme(…)` function

We now have a much simpler `theme(…)` function that can be used when
backwards compatibility is not necessary. It still supports many of the
same features:
- The modern, v4 style CSS variable syntax `theme(--color-red-500)`
- The legacy, v3 path style `theme(colors.red.500)`
- And the v3-style alpha modifier `theme(colors.red.500 / 50%)`
- Path upgrades so things like `theme(accentColor.red.500)` pulls from
`--color-red-500` when no `--accent-color-red-500` theme key exists

When you do have plugins or configs the more advanced `theme(…)`
function is swapped in for more complete backwards compatibility.

## `registerPlugins` registers globs

Before `registerPlugins` passed the `ResolvedConfig` out so we could
register globs in `compile()`. Since that one function is really the
main driver for backwards compat we decided to move the content path
registration into `registerPlugins` itself when it comes to paths
provided by plugins and configs.

This is an internal implementation detail (well this entire PR is) but
it's worth mentioning. This method is used to resolve a theme value from
a theme key.

## `registerPlugins` is now only called when necessary

All of the above work made it so that `registerPlugins` can be called
only as needed. This means that when no v3 plugins or configs are used,
`registerPlugins` is never called thus elminating the performance impact
of config resolution.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-07 13:18:30 -04:00
Jordan Pittman
783b32305f
Export Config type (#14360)
Right now the following does not work and instead produces a type error:

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

export default {
  // … config here
} satisfies Config
```

We were not exporting a `Config` type but thankfully this already exists
in the codebase so we just need to export it.

It does _not_ have all properties of an existing config as not all
features have been implemented (or in some cases necessary / relevant
for v4).

Notably missing are:
- `important`
- `prefix`
- `separator`
- `safelist`
- `blocklist`
- `future`
- `experimental`
- `corePlugins`

Also, explicit keys for theme are not currently specified but we should
probably bring this back even if just as an auto-complete aid.
2024-09-06 16:10:18 -04:00
Jordan Pittman
b1e22e121e
Allow configs to override default CSS theme values in theme() function provided to plugins and configs (#14359)
Previously, given the following CSS and configuration:

```css
/* app.css */

@theme default {
  --font-size-base: 1.25rem;
  --font-size-base--line-height: 1.5rem;
}
@tailwind utilities;
@config "./config.js";
```

```js
// config.js

export default {
  theme: {
    fontSize: {
      // …
      base: ['1rem', { lineHeight: '1.75rem' }],
    },

    // …
  },
};
```

When a config or a plugin asked for the value of `theme(fontSize.base)`
like so:

```js
// config.js
export default {
  theme: {
    // …

    typography: ({ theme }) => ({
      css: {
        '[class~="lead"]': {
          fontSize: theme('fontSize.base')[0],
          ...theme('fontSize.base')[1],
        },
      }
    }),
  },
};
```

We would instead pull the values from the CSS theme even through they're
marked with `@theme default`. This would cause the incorrect font size
and line height to be used resulting in something like this (in the case
of the typography plugin with custom styles):

  ```css
  .prose [class~="lead"] {
    font-size: 1.25rem;
    line-height: 1.5rem;
  }
  ```

After this change we'll now pull the values from the appropriate place
(the config in this case) and the correct font size and line height will
be used:

  ```css
  .prose [class~="lead"] {
    font-size: 1rem;
    line-height: 1.75rem;
  }
  ```

This will work even when some values are overridden in the CSS theme:

  ```css
  /* app.css */
  @theme default {
    --font-size-base: 1.25rem;
    --font-size-base--line-height: 1.5rem;
  }
  @theme {
    --font-size-base: 2rem;
  }
  @tailwind utilities;
  @config "./config.js";
  ```

which would result in the following CSS:

  ```css
  .prose [class~="lead"] {
    font-size: 2rem;
    line-height: 1.75rem;
  }
  ```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-06 16:05:26 -04:00
Philipp Spiess
ee35a1d047
Support CSS theme() functions inside @custom-media rules (#14358)
This PR will now also scan `@custom-media` rules for invocations of the
CSS `theme()` function.
2024-09-06 19:05:48 +02:00
Adam Wathan
7b59aac274
Properly resolve theme('someKey.DEFAULT') when only --some-key-* keys exist (#14354)
This PR fixes an issue where theme function calls like
`theme('transitionTimingFunction.DEFAULT')` would incorrectly resolve to
an object when the set of defined CSS theme values looked like this:

```css
@theme {
  --transition-timing-function-in: ease-in;
  --transition-timing-function-out: ease-out;
  --transition-timing-function-in-out: ease-out;
}
```

We were mistakenly retrieving the entire
`--transition-timing-function-*` namespace in this case and returning an
object, even though the user is explicitly asking for a single value by
including `.DEFAULT` in their call.

This ensures it resolves to null instead. Fixes an issue I ran into on
this live stream earlier today:

https://x.com/adamwathan/status/1831740214051799281

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-06 09:00:28 -04:00
Philipp Spiess
f028eae75e
Integration tests: Move all file writes into retry block (#14350)
There are still instances in which CI is flaky after #14332. This PR
applies the same fix (that is, moving the file write into the retrying
block) to all `retryAssertion` callbacks.
2024-09-06 10:48:49 +02:00
Robin Malfait
7f06777d6c
Use a bit flags for theme options instead of an object with booleans (#14337)
This PR is a small improvement to the theme options where it's just a
simple number now instead of an object with booleans.
2024-09-06 00:38:43 +02:00
Robin Malfait
af774e8f24
Improve the CLI output when nothing changed (#14351)
When we observe that no new candidates were found, then we can return
early because nothing really changed. There is also no need to
re-optimize (use Lightning CSS) in this case.

But this had a side effect that when no new candidates were detected,
that you didn't see any output either. This feels like nothing is
working from a DX perspective.

Typically you are changing things, so it's not really a problem. But the
moment you use a class that already existed (e.g.: in another file) you
also don't get any output because we have a shared cache.

This PR solves that by always showing the output. But it still doesn't
write to disk if nothing changed.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-05 17:00:57 -04:00
Jordan Pittman
c37473e17b set registry url 2024-09-05 10:52:11 -04:00
Jordan Pittman
15d1714c33 v4.0.0-alpha.23 2024-09-05 10:43:07 -04:00
Jordan Pittman
2f9de02f24 Fix changelog 2024-09-05 10:40:00 -04:00
Jordan Pittman
4b94373e52 Update changelog
The release didn’t happen yesterday so the date is wrong
2024-09-05 10:30:41 -04:00
Jordan Pittman
c2f4623a68 Tweak tag fetching in GH actions release workflow 2024-09-05 10:18:51 -04:00
Jordan Pittman
c7d9af58c5 fix release workflow 2024-09-05 09:58:09 -04:00
Jordan Pittman
aa0075f57f
Add GitHub release workflow (#14346)
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-09-05 09:45:29 -04:00
Philipp Spiess
27cced0d16 Remove leftover .debug 2024-09-05 14:46:01 +02:00
Philipp Spiess
4297655a7a
Add integration test for Vite CSS module support (#14349)
Wanted to make sure stuff works with CSS modules for both the postcss
and the lightningcss pipeline.
2024-09-05 14:24:50 +02:00
Philipp Spiess
8f8803d855
Move opacity modifier support into plugin theme() function (#14348)
This PR moves support for opacity modifies from the CSS `theme()`
function into the plugin `theme()` implementation, this will allow
plugins to use this, too:

```ts
let plugin = plugin(function ({ addUtilities, theme }) {
    addUtilities({
      '.percentage': {
        color: theme('colors.red.500 / 50%'),
      },
      '.fraction': {
        color: theme('colors.red.500 / 0.5'),
      },
      '.variable': {
        color: theme('colors.red.500 / var(--opacity)'),
      },
    })
  })
}
```

There's a small behavioral change for the CSS `theme()` function. Since
tuples are resolved by default for the CSS `theme()` function only,
these will no longer have opacity applied to their first values. This is
probably fine given the reduced complexity as I don't expect the first
values of tuples to be colors and the fix would mean we would have to
parse the modifier in different places.
2024-09-05 12:40:16 +02:00
Adam Wathan
d9558bbc4c v4.0.0-alpha.22 2024-09-04 15:50:57 -04:00
Adam Wathan
7725a5fbb6
Update CHANGELOG.md 2024-09-04 15:46:39 -04:00
Adam Wathan
2c89645d26
Update CHANGELOG.md 2024-09-04 15:45:25 -04:00
Adam Wathan
530774b186
Ensure --default-font-* and --default-mono-font-* variables respect theme customizations in JS config files (#14344)
This PR fixes an issue where variables like `--default-font-family`
wouldn't behave as expected when customizing `fontFamily.sans` or
`fontFamily.mono` in a JS config.

Because theme values added by JS config files are added as `reference`,
customizing `fontFamily.sans` means the `--font-family-sans` variable no
longer exists in the generated CSS.

The `--default-font-family` variable is set to `var(--font-family-sans)`
by default, so because that variable doesn't exist,
`--default-font-family` is effectively undefined and the browser default
font stack is used. This is unexpected because historically customizing
`fontFamily.sans` has updated your default font for your entire project.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 15:30:21 -04:00
Adam Wathan
262e99e5a9
Support arrays in JS config values (#14343)
This PR fixes a small bug where theme values could not be defined as
arrays in JS config files, for example:

```js
export default {
  theme: {
    fontFamily: {
      sans: ['Inter', 'system-ui', 'sans-serif'],
    },
  },
}
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 15:03:46 -04:00
Philipp Spiess
a3a16e64d2
Fix a crash with older Node.js versions (#14342)
Closes #14341

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-04 13:43:18 -04:00
Philipp Spiess
2dd52f5a0f
Vite: Add support for <style> tags in Astro files (#14340)
This works similar to the Vue setup. The styles that Astro will receive
might still contain Tailwind CSS APIs but since it's not picky, we can
pass that through to the regular Vite `transform` handlers for now.

This, however, will have issues like
https://github.com/tailwindlabs/tailwindcss/issues/14205. We have to fix
this together with Vue and other similar extensions later. For now, it
will break when syntax is used that lightningcss rewrites (like `@apply
text-3xl/tight;`)

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-04 19:14:05 +02:00
Jordan Pittman
805c8a0201
Don’t suggest named opacity modifiers in intellisense (#14339)
We removed named opacity modifier support in #14278 but we (read: me
lol) totally forgot about the suggestions in intellisense. So we need to
make sure that we don't suggest those either.
2024-09-04 16:57:32 +00:00
Adam Wathan
d6a67beb76
Add default option to @theme to support overriding default theme values from plugins/JS config files (#14327)
This PR adds a new `default` option to `@theme` to make it possible for
plugins/JS config files to override default theme values, and also
ensures that the final set of CSS variables we output takes into account
any theme values added by plugins/JS config files.

---

Previously, if you were using the default theme but also had a JS config
file that overrode any of those defaults like this:

```js
// ./tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        red: {
          '500': 'tomato',
        },
      }
    }
  }
}
```

…then utilities like `text-red-500` would correctly use `color: tomato`,
but the `--color-red-500` CSS variable would still be set to the default
value:

```css
:root {
  --color-red-500: #ef4444;
}
```

This feels like a straight-up bug — if `#ef4444` is not part of your
design system because you've overridden it, it shouldn't show up in your
set of CSS variables anywhere.

So this PR fixes this issue by making sure we don't print the final set
of CSS variables until all of your plugins and config files have had a
chance to update the theme.

---

The second issue is that we realized people have different expectations
about how plugin/config theme values should interact with Tailwind's
_default_ theme vs. explicitly user-configured theme values.

Take this setup for instance:

```css
@import "tailwindcss";
@config "./tailwind.config.js";
```

If `tailwind.config.js` overrides `red-500` to be `tomato`, you'd expect
`text-red-500` to actually be `tomato`, not the default `#ef4444` color.

But in this setup:

```css
@import "tailwindcss";
@config "./tailwind.config.js";
@theme {
  --color-red-500: #f00;
}
```

…you'd expect `text-red-500` to be `#f00`. This is despite the fact that
currently in Tailwind there is no difference here — they are both just
`@theme` blocks, one just happens to be coming from an imported file
(`@import "tailwindcss"`).

So to resolve this ambiguity, I've added a `default` option to `@theme`
for explicitly registering theme values as "defaults" that are safe to
override with plugin/JS config theme values:

```css
@import "tailwindcss";
@config "./tailwind.config.js";
@theme default {
  --color-red-500: #f00;
}
```

Now `text-red-500` would be `tomato` here as per the config file.

This API is not something users are generally going to interact with —
they will almost never want to use `default` explicitly. But in this PR
I've updated the default theme we ship with to include `default` so that
it interacts in a more intuitive way with plugins and JS config files.

---

Finally, this PR makes sure all theme values registered by
plugins/configs are registered with `isReference: true` to make sure
they do not end up in the final CSS at all.

This is important to make sure that the super weird shit we used to do
in configs in v3 doesn't get translated into nonsense variables that
pollute your output (hello typography plugin I'm looking at you).

If we don't do this, you'll end up with CSS variables like this:

```css
:root {
  --typography-sm-css-blockquote-padding-inline-start: 1.25em;
}
```

Preventing theme values registered in plugins/configs from outputting
CSS values also serves the secondary purpose of nudging users to migrate
to the CSS config if they do want CSS variables for their theme values.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 11:49:50 -04:00
Adam Wathan
6d0371afb1
Evaluate theme functions in plugins (#14326)
This PR fixes a bug where CSS `theme()` functions were not evaluated
when present in rules added by plugins, using either `@plugin` or
registering a plugin in a JS config file.

For example, prior to this PR the `theme()` functions in this plugin
would make it into the final CSS without being evaluated:

```js
// ./my-plugin.js
export default plugin(({ addBase }) => {
  addBase({
    '.my-rule': {
      background: 'theme(colors.primary)',
      color: 'theme(colors.secondary)',
    },
  })
})
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 11:49:01 -04:00
Philipp Spiess
44dd6da4fe
Integration tests: Fix Windows flake for Vite watch mode (#14332)
I noticed the Windows integration tests for Vite's `watch` mode have
been flaky. Moving the file write into the retrying assertion callback
seems to fix it and allows us to get rid of the arbitrary timeout (I
don't remember that I ever added this in the first place 😅 ).
2024-09-04 17:09:33 +02:00
Philipp Spiess
719a5351c1
Fix Nuxt integration (#14319)
We noticed that Nuxt projects were not working with the tailwindcss
project. The issue was traced down to the fact that Nuxt starts multiple
Vite dev servers and calling the experimental `waitForRequestsIdle()` on
one of the test servers would never resolve.

This was fixed upstream and is part of the latest Vite/Nuxt release:
https://github.com/vitejs/vite/issues/17980.

We still need to handle the fact that Vite can spawn multiple dev
servers. This is necessary because when we invalidate all roots, we need
to find that module inside all of the spawned servers. If we only look
at the _last server_ (what we have done before), we would not find the
module and thus could not invalidate it.
2024-09-04 10:53:15 -04:00
Philipp Spiess
e7ca667f76 Remove leftover TODO in Vite plugin 2024-09-04 11:43:41 +02:00
Philipp Spiess
835922812b
Rework Vite plugin to support lightningcss pre processor and fast rebuilds (#14269)
Fixes #14205
Fixes #14106

This PR reworks the Vite extension in order to supprt `lightningcss` as
the pre-processor, enable faster rebuilds, and adds support for `vite
build --watch` mode. To make this change possible, we've done two major
changes to the extension that have caused the other changes.

## 1. Tailwind CSS is a preprocessor

We now run all of our modifications in `enforce: 'pre'`. This means that
Tailwind CSS now gets the untransformed CSS files rather than the one
already going through postcss or lightningcss. We do this because
Tailwind CSS _is_ a preprocessor at the same level as those tools and we
do sometimes use the language in ways that [creates problems when it's
the input for other
bundlers](https://github.com/tailwindlabs/tailwindcss/pull/14269).

The correct solution here is to make Tailwind not depend on any other
transformations. The main reason we were not using the `enforce: 'pre'`
phase in Vite before was becuase we relied on the `@import` flattening
of postcss so we now have to do this manually. `@import` flattening is
now a concern that every Tailwind V4 client has to deal with so this
might actually be something we want to inline into tailwindcss in the
future.

## 2. A Vite config can have multiple Tailwind roots 

This is something that we have not made very explicit in the previous
iteration of the Vite plugin but we have to support multiple Tailwind
roots in a single Vite workspace. A Tailwind root is a CSS file that is
used to configure Tailwind. Technically, any CSS file can be the input
for `tailwindcss` but you have to add certain rules (e.g. `@import
"tailwindcss";`) to make the compiler do something.

A workspace can have multiple of these rules (e.g. by having different
Tailwind configures for different sub-pages). With the addition of
[support for `@source`
rules](https://github.com/tailwindlabs/tailwindcss/pull/14078) and [JS
config files](https://github.com/tailwindlabs/tailwindcss/pull/14239),
Tailwind roots become more complex and can have a custom list of
_dependencies_ (that is other JavaScript modules the compiler includes
as part of these new rules). In order to _only rebuild the roots we need
to_, we have to make this separation very clear.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 10:09:24 +02:00
Philipp Spiess
390e2d3e8d
Allow @plugin and @config to point to TS files (#14317)
Tailwind V3 used [jiti](https://github.com/unjs/jiti/) to allow
importing of TypeScript files for the config and plugins. This PR adds
the new Jiti V2 beta to our `@tailwindcss/node` and uses it if a native
`import()` fails. I added a new integration test to the CLI config
setup, to ensure it still works with our module cache cleanup.
2024-09-03 18:35:39 +02:00
Philipp Spiess
191c544c67
CSS theme(): Add unit test that combines CSS variable syntax with opacity modifier (#14323)
This PR adds a new test case to the branches that test the CSS `theme()`
function with the CSS variable syntax. The new case includes an opacity
modifier and ensures that the opacity is properly added.
2024-09-03 18:01:04 +02:00
Philipp Spiess
adc8dfb1a2
Ensure CSS theme() functions are evaluated in media query ranges with collapsed whitespace (#14321)
Fixes #14320

This PR adds `>`, `<`, and `=` as separators into the CSS value parser.
This is necessary because [`@media` range
context](https://www.w3.org/TR/mediaqueries-4/#mq-range-context) does
not require spaces around these operators so something like this is a
valid value for the range syntax:

```css
@media (40rem<width<=48rem) { 
  /* ... */
}
```

If you add our CSS `theme()` function to the mix, this rule look like
that:

```css
@media (theme(--breakpoint-sm)<width<=theme(--breakpoint-md)) {
  /* ... */
}
```

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-03 17:27:18 +02: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