Merge branch 'main' into fix-max-width-mapping
This commit is contained in:
commit
a02acb94bd
56 changed files with 2575 additions and 855 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
|
@ -13,13 +13,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Fixed
|
||||
|
||||
- Guard object lookups against inherited prototype properties ([#19725](https://github.com/tailwindlabs/tailwindcss/pull/19725))
|
||||
- Canonicalization: improve canonicalizations for `tracking-*` utilities by preferring non-negative utilities (e.g. `-tracking-tighter` → `tracking-wider`) ([#19827](https://github.com/tailwindlabs/tailwindcss/pull/19827))
|
||||
- Fix crash due to invalid characters in candidate ([#19829](https://github.com/tailwindlabs/tailwindcss/pull/19829))
|
||||
- Ensure query params in imports are considered unique resources when using `@tailwindcss/webpack` ([#19723](https://github.com/tailwindlabs/tailwindcss/pull/19723))
|
||||
- Canonicalization: collapse arbitrary values into shorthand utilities (e.g. `px-[1.2rem] py-[1.2rem]` → `p-[1.2rem]`) ([#19837](https://github.com/tailwindlabs/tailwindcss/pull/19837))
|
||||
- Canonicalization: collapse `border-{t,b}-*` into `border-y-*`, `border-{l,r}-*` into `border-x-*`, and `border-{t,r,b,l}-*` into `border-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842))
|
||||
- Canonicalization: collapse `scroll-m{t,b}-*` into `scroll-my-*`, `scroll-m{l,r}-*` into `scroll-mx-*`, and `scroll-m{t,r,b,l}-*` into `scroll-m-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842))
|
||||
- Canonicalization: collapse `scroll-p{t,b}-*` into `scroll-py-*`, `scroll-p{l,r}-*` into `scroll-px-*`, and `scroll-p{t,r,b,l}-*` into `scroll-p-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842))
|
||||
- Canonicalization: collapse `overflow-{x,y}-*` into `overflow-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842))
|
||||
- Canonicalization: collapse `overscroll-{x,y}-*` into `overscroll-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842))
|
||||
- Read from `--placeholder-color` instead of `--background-color` for `placeholder-*` utilities ([#19843](https://github.com/tailwindlabs/tailwindcss/pull/19843))
|
||||
- Upgrade: Ensure files are not emptied out when killing the upgrade process while it's running ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846))
|
||||
- Upgrade: Use `config.content` when migrating from Tailwind CSS v3 to Tailwind CSS v4 ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846))
|
||||
- Upgrade: Never migrate files that are ignored by git ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846))
|
||||
- Add `.env` and `.env.*` to default ignored content files ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846))
|
||||
- Canonicalization: migrate `overflow-ellipsis` into `text-ellipsis` ([#19849](https://github.com/tailwindlabs/tailwindcss/pull/19849))
|
||||
- Canonicalization: migrate `start-full` → `inset-s-full`, `start-auto` → `inset-s-auto`, `start-px` → `inset-s-px`, and `start-<number>` → `inset-s-<number>` as well as negative versions ([#19849](https://github.com/tailwindlabs/tailwindcss/pull/19849))
|
||||
- Canonicalization: migrate `end-full` → `inset-e-full`, `end-auto` → `inset-e-auto`, `end-px` → `inset-e-px`, and `end-<number>` → `inset-e-<number>` as well as negative versions ([#19849](https://github.com/tailwindlabs/tailwindcss/pull/19849))
|
||||
- Canonicalization: move the `-` sign inside the arbitrary value `-left-[9rem]` → `left-[-9rem]` ([#19858](https://github.com/tailwindlabs/tailwindcss/pull/19858))
|
||||
- Canonicalization: move the `-` sign outside the arbitrary value `ml-[calc(-1*var(--width))]` → `-ml-(--width)` ([#19858](https://github.com/tailwindlabs/tailwindcss/pull/19858))
|
||||
- Improve performance when scanning JSONL / NDJSON files ([#19862](https://github.com/tailwindlabs/tailwindcss/pull/19862))
|
||||
|
||||
## [4.2.2] - 2026-03-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Don't crash when candidates contain prototype properties like `row-constructor` ([#19725](https://github.com/tailwindlabs/tailwindcss/pull/19725))
|
||||
- Canonicalize `calc(var(--spacing)*…)` expressions into `--spacing(…)` ([#19769](https://github.com/tailwindlabs/tailwindcss/pull/19769))
|
||||
- Fix crash in canonicalization step when handling utilities with empty property maps ([#19727](https://github.com/tailwindlabs/tailwindcss/pull/19727))
|
||||
- Fix crash in canonicalization step when handling utilities containing `@property` at-rules (e.g. `shadow-sm border`) ([#19727](https://github.com/tailwindlabs/tailwindcss/pull/19727))
|
||||
- Skip full reload for server only modules scanned by client CSS when using `@tailwindcss/vite` ([#19745](https://github.com/tailwindlabs/tailwindcss/pull/19745))
|
||||
- Add support for Vite 8 in `@tailwindcss/vite` ([#19790](https://github.com/tailwindlabs/tailwindcss/pull/19790))
|
||||
- Improve canonicalization for bare values exceeding default spacing scale suggestions (e.g. `w-1234 h-1234` → `size-1234`) ([#19809](https://github.com/tailwindlabs/tailwindcss/pull/19809))
|
||||
- Fix canonicalization resulting in empty list (e.g. `w-5 h-5 size-5` → `` instead of `size-5`) ([#19812](https://github.com/tailwindlabs/tailwindcss/pull/19812))
|
||||
- Fix canonicalization resulting in empty list (e.g. `w-5 h-5 size-5` → `''` instead of `size-5`) ([#19812](https://github.com/tailwindlabs/tailwindcss/pull/19812))
|
||||
- Resolve tsconfig paths to allow for `@import '@/path/to/file';` when using `@tailwindcss/vite` ([#19803](https://github.com/tailwindlabs/tailwindcss/pull/19803))
|
||||
|
||||
## [4.2.1] - 2026-02-23
|
||||
|
||||
|
|
@ -3958,7 +3984,8 @@ No release notes
|
|||
|
||||
- Everything!
|
||||
|
||||
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.1...HEAD
|
||||
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.2...HEAD
|
||||
[4.2.2]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.1...v4.2.2
|
||||
[4.2.1]: https://github.com/tailwindlabs/tailwindcss/compare/v4.2.0...v4.2.1
|
||||
[4.2.0]: https://github.com/tailwindlabs/tailwindcss/compare/v4.1.18...v4.2.0
|
||||
[4.1.18]: https://github.com/tailwindlabs/tailwindcss/compare/v4.1.17...v4.1.18
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-android-arm-eabi",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-android-arm64",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-darwin-arm64",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-darwin-x64",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-freebsd-x64",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-linux-arm-gnueabihf",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-linux-arm64-gnu",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-linux-arm64-musl",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-linux-x64-gnu",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-linux-x64-musl",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-wasm32-wasi",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-win32-arm64-msvc",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide-win32-x64-msvc",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/oxide",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tailwindlabs/tailwindcss.git",
|
||||
|
|
|
|||
|
|
@ -2,3 +2,5 @@ package-lock.json
|
|||
pnpm-lock.yaml
|
||||
bun.lockb
|
||||
.gitignore
|
||||
.env
|
||||
.env.*
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ pub fn pre_process_input(content: Vec<u8>, extension: &str) -> Vec<u8> {
|
|||
"heex" | "eex" | "ex" | "exs" => Elixir.process(&content),
|
||||
"cshtml" | "razor" => Razor.process(&content),
|
||||
"haml" => Haml.process(&content),
|
||||
"json" => Json.process(&content),
|
||||
"json" | "jsonl" | "ndjson" => Json.process(&content),
|
||||
"md" | "mdx" => Markdown.process(&content),
|
||||
"pug" => Pug.process(&content),
|
||||
"rb" | "erb" => Ruby.process(&content),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import path from 'node:path'
|
||||
import { isRepoDirty } from '../../packages/@tailwindcss-upgrade/src/utils/git'
|
||||
import { candidate, css, html, js, json, test, ts, yaml } from '../utils'
|
||||
import { candidate, css, html, js, json, test, ts, txt, yaml } from '../utils'
|
||||
|
||||
test(
|
||||
'error when no CSS file with @tailwind is used',
|
||||
|
|
@ -171,6 +171,56 @@ test(
|
|||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'only migrates files matched by `config.content` when upgrading from v3 to v4',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^3",
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'tailwind.config.js': js`
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./src/**/*.html'],
|
||||
}
|
||||
`,
|
||||
'src/index.html': html`
|
||||
<div class="order-[0] bg-[--my-red]"></div>
|
||||
`,
|
||||
'src/input.css': css`
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
'templates/email.php': html`
|
||||
<div class="order-[0] bg-[--my-red]"></div>
|
||||
`,
|
||||
'notes/unrelated.txt': `order-[0] bg-[--my-red]`,
|
||||
},
|
||||
},
|
||||
async ({ exec, fs, expect }) => {
|
||||
await exec('npx @tailwindcss/upgrade')
|
||||
|
||||
expect(await fs.dumpFiles('./**/*.{html,php,txt}')).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- notes/unrelated.txt ---
|
||||
order-[0] bg-[--my-red]
|
||||
|
||||
--- src/index.html ---
|
||||
<div class="order-0 bg-(--my-red)"></div>
|
||||
|
||||
--- templates/email.php ---
|
||||
<div class="order-[0] bg-[--my-red]"></div>
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
`upgrades a v3 project with prefixes to v4`,
|
||||
{
|
||||
|
|
@ -2972,6 +3022,198 @@ test(
|
|||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'v4 ignores .env files during template migration',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4",
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'src/app.css': css`@import 'tailwindcss';`,
|
||||
'src/index.html': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
'src/.env': `TW_TEST_CLASS=order-[0]`,
|
||||
'src/.env.production': `TW_TEST_CLASS=order-[0]`,
|
||||
},
|
||||
},
|
||||
async ({ exec, fs, expect }) => {
|
||||
await exec('npx @tailwindcss/upgrade')
|
||||
|
||||
expect(await fs.dumpFiles('./src/**/{*,.env,.env.*}')).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- ./src/index.html ---
|
||||
<div class="order-0"></div>
|
||||
|
||||
--- ./src/.env ---
|
||||
TW_TEST_CLASS=order-[0]
|
||||
|
||||
--- ./src/.env.production ---
|
||||
TW_TEST_CLASS=order-[0]
|
||||
|
||||
--- ./src/app.css ---
|
||||
@import 'tailwindcss';
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'v4 linked configs respect `content` and still ignore gitignored files',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4",
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'tailwind.config.js': js`
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./src/*.html', './src/*.less'],
|
||||
}
|
||||
`,
|
||||
'src/app.css': css`
|
||||
@import 'tailwindcss';
|
||||
@config '../tailwind.config.js';
|
||||
`,
|
||||
|
||||
// Ignore all .html files
|
||||
'src/.gitignore': txt`
|
||||
*.html
|
||||
`,
|
||||
|
||||
// HTML files are in .gitignore, even though they are explicitly mentioned
|
||||
// in the `content` array. Still ignore them
|
||||
'src/do-not-migrate-me.html': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
|
||||
// Should be picked up by auto-content detection
|
||||
'templates/migrate-me.php': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
|
||||
// Does not get picked up by auto content detection (because it's a less
|
||||
// file), but was explicitly listed in the `content` array.
|
||||
//
|
||||
// A bit of a hacky way, I admit, but it allows us to differentiate
|
||||
// between git ignored files, auto content detection and explicitly listed
|
||||
// files.
|
||||
'src/migrate-me.less': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ exec, fs, expect }) => {
|
||||
await exec('npx @tailwindcss/upgrade')
|
||||
|
||||
expect(await fs.dumpFiles('./{src,templates}/**/*')).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- ./src/app.css ---
|
||||
@import 'tailwindcss';
|
||||
@config '../tailwind.config.js';
|
||||
|
||||
--- ./src/do-not-migrate-me.html ---
|
||||
<div class="order-[0]"></div>
|
||||
|
||||
--- ./src/migrate-me.less ---
|
||||
<div class="order-0"></div>
|
||||
|
||||
--- ./templates/migrate-me.php ---
|
||||
<div class="order-0"></div>
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'interrupting template migration does not truncate files',
|
||||
{
|
||||
timeout: 180_000,
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4",
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'src/app.css': css` @import 'tailwindcss'; `,
|
||||
'src/index.html': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
'hook.cjs': js`
|
||||
let fs = require('node:fs/promises')
|
||||
let path = require('node:path')
|
||||
let originalWriteFile = fs.writeFile.bind(fs)
|
||||
|
||||
fs.writeFile = async (file, contents, ...rest) => {
|
||||
// Mimic a bad write
|
||||
await originalWriteFile(file, '') // As-if we truncated first
|
||||
console.error('__TRUNCATED_TARGET__')
|
||||
await new Promise((r) => setTimeout(r, 50)) // Wait 50ms to allow us to kill the process
|
||||
await originalWriteFile(file, contents, ...rest) // Write the actual contents
|
||||
}
|
||||
`,
|
||||
'src/keep.php': `
|
||||
<?php
|
||||
|
||||
return [
|
||||
'keep' => 'this file should never be truncated',
|
||||
];
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ spawn, fs, expect }) => {
|
||||
let repeatedCandidates = Array.from(
|
||||
{ length: 250 },
|
||||
() => '<div class="order-[0]"></div>',
|
||||
).join('\n')
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
await fs.write(
|
||||
`src/templates/template-${i}.php`,
|
||||
`<?php\n\n${repeatedCandidates}\n\nreturn ['template' => ${i}];\n`,
|
||||
)
|
||||
}
|
||||
|
||||
let originalKeepFile = await fs.read('src/keep.php')
|
||||
let originalTemplate = await fs.read('src/templates/template-0.php')
|
||||
|
||||
let process = await spawn('npx @tailwindcss/upgrade --force', {
|
||||
env: {
|
||||
NODE_OPTIONS: '--require=./hook.cjs',
|
||||
},
|
||||
})
|
||||
|
||||
// We're only interested once we start migrating the templates
|
||||
await process.onStderr((message) => message.includes('Migrating templates'))
|
||||
|
||||
// Wait for the trigger that we are mid-write
|
||||
await process.onStderr((message) => message === '__TRUNCATED_TARGET__')
|
||||
|
||||
// Kill the process
|
||||
await process.dispose()
|
||||
|
||||
expect(await fs.read('src/keep.php')).toBe(originalKeepFile)
|
||||
expect(await fs.read('src/templates/template-0.php')).toBe(originalTemplate)
|
||||
|
||||
for (let [file, contents] of await fs.glob('src/**/*.{html,php,css}')) {
|
||||
expect(contents.trim(), `${file} should not be empty after interruption`).not.toBe('')
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'upgrades can run in a pnpm workspace',
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import path from 'node:path'
|
||||
import { describe } from 'vitest'
|
||||
import { css, html, json, test, ts } from '../utils'
|
||||
import { css, html, json, test, ts, txt } from '../utils'
|
||||
|
||||
test(
|
||||
`upgrade JS config files with flat theme values, darkMode, and content fields`,
|
||||
|
|
@ -322,6 +322,105 @@ test(
|
|||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'skips gitignored template files even when they are explicitly referenced in `content`',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^3",
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'.gitignore': txt`
|
||||
node_modules
|
||||
src/ignored
|
||||
`,
|
||||
'tailwind.config.ts': ts`
|
||||
import { type Config } from 'tailwindcss'
|
||||
|
||||
module.exports = {
|
||||
content: [
|
||||
'./src/migrate-me.html',
|
||||
'./src/ignored/do-not-migrate-me.html',
|
||||
'./node_modules/my-external-lib/template.html',
|
||||
],
|
||||
theme: {},
|
||||
plugins: [],
|
||||
} satisfies Config
|
||||
`,
|
||||
'src/input.css': css`
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
'src/migrate-me.html': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
'src/ignored/do-not-migrate-me.html': html`
|
||||
<div class="order-[0]"></div>
|
||||
`,
|
||||
'node_modules/my-external-lib/template.html': html`
|
||||
<div
|
||||
class="order-[0]"
|
||||
></div>
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ exec, fs, expect }) => {
|
||||
await exec('npx @tailwindcss/upgrade')
|
||||
|
||||
expect(
|
||||
await fs.dumpFiles(
|
||||
'{src/**/*.{css,html},node_modules/my-external-lib/template.html,.gitignore}',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- .gitignore ---
|
||||
node_modules
|
||||
src/ignored
|
||||
|
||||
--- src/input.css ---
|
||||
@import 'tailwindcss';
|
||||
|
||||
@source './ignored/do-not-migrate-me.html';
|
||||
@source '../node_modules/my-external-lib/template.html';
|
||||
|
||||
/*
|
||||
The default border color has changed to \`currentcolor\` in Tailwind CSS v4,
|
||||
so we've added these compatibility styles to make sure everything still
|
||||
looks the same as it did with Tailwind CSS v3.
|
||||
|
||||
If we ever want to remove these styles, we need to add an explicit border
|
||||
color utility to any element that depends on these defaults.
|
||||
*/
|
||||
@layer base {
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentcolor);
|
||||
}
|
||||
}
|
||||
|
||||
--- src/migrate-me.html ---
|
||||
<div class="order-0"></div>
|
||||
|
||||
--- node_modules/my-external-lib/template.html ---
|
||||
<div
|
||||
class="order-[0]"
|
||||
></div>
|
||||
|
||||
--- src/ignored/do-not-migrate-me.html ---
|
||||
<div class="order-[0]"></div>
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'upgrades JS config files with plugins',
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const PUBLIC_PACKAGES = (await fs.readdir(path.join(REPO_ROOT, 'dist'))).map((na
|
|||
)
|
||||
|
||||
interface SpawnedProcess {
|
||||
dispose: () => void
|
||||
dispose: () => Promise<void>
|
||||
flush: () => void
|
||||
onStdout: (predicate: (message: string) => boolean) => Promise<void>
|
||||
onStderr: (predicate: (message: string) => boolean) => Promise<void>
|
||||
|
|
@ -194,6 +194,7 @@ export function test(
|
|||
return disposePromise
|
||||
}
|
||||
disposables.push(dispose)
|
||||
|
||||
function onExit() {
|
||||
resolveDisposal?.()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,168 @@
|
|||
import { describe } from 'vitest'
|
||||
import { candidate, css, fetchStyles, html, js, retryAssertion, test, ts, txt } from '../utils'
|
||||
import {
|
||||
candidate,
|
||||
css,
|
||||
fetchStyles,
|
||||
html,
|
||||
js,
|
||||
json,
|
||||
retryAssertion,
|
||||
test,
|
||||
ts,
|
||||
txt,
|
||||
} from '../utils'
|
||||
|
||||
test(
|
||||
'resolves tsconfig paths in production build',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "workspace:^",
|
||||
"tailwindcss": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^8"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'tsconfig.json': json`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
'vite.config.ts': ts`
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
build: { cssMinify: false },
|
||||
plugins: [tailwindcss()],
|
||||
resolve: {
|
||||
tsconfigPaths: true,
|
||||
},
|
||||
})
|
||||
`,
|
||||
'index.html': html`
|
||||
<head>
|
||||
<link rel="stylesheet" href="./src/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="underline custom-underline">Hello, world!</div>
|
||||
</body>
|
||||
`,
|
||||
'src/index.css': css`
|
||||
@import '@/styles/base.css';
|
||||
@plugin '@/plugin.js';
|
||||
`,
|
||||
'src/styles/base.css': css`
|
||||
@reference 'tailwindcss/theme';
|
||||
@import 'tailwindcss/utilities';
|
||||
`,
|
||||
'src/plugin.js': js`
|
||||
export default function ({ addUtilities }) {
|
||||
addUtilities({ '.custom-underline': { 'border-bottom': '1px solid green' } })
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ fs, exec, expect }) => {
|
||||
await exec('pnpm vite build')
|
||||
|
||||
let files = await fs.glob('dist/**/*.css')
|
||||
expect(files).toHaveLength(1)
|
||||
let [filename] = files[0]
|
||||
|
||||
await fs.expectFileToContain(filename, [candidate`underline`, candidate`custom-underline`])
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'resolves tsconfig paths in dev mode',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "workspace:^",
|
||||
"tailwindcss": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^8"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'tsconfig.json': json`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
'vite.config.ts': ts`
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
build: { cssMinify: false },
|
||||
plugins: [tailwindcss()],
|
||||
resolve: {
|
||||
tsconfigPaths: true,
|
||||
},
|
||||
})
|
||||
`,
|
||||
'index.html': html`
|
||||
<head>
|
||||
<link rel="stylesheet" href="./src/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="underline custom-underline">Hello, world!</div>
|
||||
</body>
|
||||
`,
|
||||
'src/index.css': css`
|
||||
@import '@/styles/base.css';
|
||||
@plugin '@/plugin.js';
|
||||
`,
|
||||
'src/styles/base.css': css`
|
||||
@reference 'tailwindcss/theme';
|
||||
@import 'tailwindcss/utilities';
|
||||
`,
|
||||
'src/plugin.js': js`
|
||||
export default function ({ addUtilities }) {
|
||||
addUtilities({ '.custom-underline': { 'border-bottom': '1px solid green' } })
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ spawn, expect }) => {
|
||||
let process = await spawn('pnpm vite dev')
|
||||
await process.onStdout((m) => m.includes('ready in'))
|
||||
|
||||
let url = ''
|
||||
await process.onStdout((m) => {
|
||||
let match = /Local:\s*(http.*)\//.exec(m)
|
||||
if (match) url = match[1]
|
||||
return Boolean(url)
|
||||
})
|
||||
|
||||
await retryAssertion(async () => {
|
||||
let styles = await fetchStyles(url, '/index.html')
|
||||
expect(styles).toContain(candidate`underline`)
|
||||
expect(styles).toContain(candidate`custom-underline`)
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
|
||||
test(
|
||||
|
|
|
|||
|
|
@ -418,3 +418,78 @@ test(
|
|||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'@tailwindcss/webpack loader isolates cache by resource including query',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"main": "./src/index.js",
|
||||
"browser": "./src/index.js",
|
||||
"dependencies": {
|
||||
"css-loader": "^6",
|
||||
"webpack": "^5",
|
||||
"webpack-cli": "^5",
|
||||
"mini-css-extract-plugin": "^2",
|
||||
"tailwindcss": "workspace:^",
|
||||
"@tailwindcss/webpack": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'webpack.config.js': js`
|
||||
let MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
let path = require('node:path')
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
a: './src/a.js',
|
||||
b: './src/b.js',
|
||||
},
|
||||
output: {
|
||||
clean: true,
|
||||
},
|
||||
plugins: [new MiniCssExtractPlugin()],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /.css$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
'css-loader',
|
||||
'@tailwindcss/webpack',
|
||||
path.resolve(__dirname, 'query-loader.js'),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`,
|
||||
'query-loader.js': js`
|
||||
module.exports = function (source) {
|
||||
if (this.resourceQuery.includes('a')) {
|
||||
return '@import "tailwindcss/utilities"; @utility only-a {color: var(--color-red-500);}'
|
||||
}
|
||||
|
||||
if (this.resourceQuery.includes('b')) {
|
||||
return '@import "tailwindcss/utilities"; @utility only-b {color: var(--color-blue-500);}'
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
`,
|
||||
'src/a.js': js`import './index.css?a'`,
|
||||
'src/b.js': js`import './index.css?b'`,
|
||||
'src/index.css': css``,
|
||||
},
|
||||
},
|
||||
async ({ fs, exec }) => {
|
||||
await exec('pnpm webpack --mode=development')
|
||||
|
||||
await fs.expectFileToContain('dist/a.css', ['only-a', '--color-red-500'])
|
||||
await fs.expectFileToContain('dist/b.css', ['only-b', '--color-blue-500'])
|
||||
await fs.expectFileNotToContain('dist/a.css', ['only-b', '--color-blue-500'])
|
||||
await fs.expectFileNotToContain('dist/b.css', ['only-a', '--color-red-500'])
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@
|
|||
"packageManager": "pnpm@9.6.0",
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"lightningcss@1.31.1": "patches/lightningcss@1.31.1.patch",
|
||||
"@parcel/watcher@2.5.1": "patches/@parcel__watcher@2.5.1.patch"
|
||||
"@parcel/watcher@2.5.1": "patches/@parcel__watcher@2.5.1.patch",
|
||||
"lightningcss@1.32.0": "patches/lightningcss@1.32.0.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/browser",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.global.js",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/cli",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/node",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/postcss",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "PostCSS plugin for Tailwind CSS, a utility-first CSS framework for rapidly building custom user interfaces",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/standalone",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"private": true,
|
||||
"description": "Standalone CLI for Tailwind CSS",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/upgrade",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import fs from 'node:fs/promises'
|
|||
import path from 'node:path'
|
||||
import { pkg } from '../../utils/packages'
|
||||
import { highlight, info, relative, success, warn } from '../../utils/renderer'
|
||||
import { writeFileSafely } from '../../utils/write-file-safely'
|
||||
|
||||
// Migrates simple PostCSS setups. This is to cover non-dynamic config files
|
||||
// similar to the ones we have all over our docs:
|
||||
|
|
@ -50,7 +51,7 @@ export async function migratePostCSSConfig(base: string) {
|
|||
ranMigration = true
|
||||
|
||||
if (result) {
|
||||
await fs.writeFile(
|
||||
await writeFileSafely(
|
||||
packageJsonPath,
|
||||
JSON.stringify({ ...packageJson, postcss: result?.json }, null, 2),
|
||||
)
|
||||
|
|
@ -76,7 +77,7 @@ export async function migratePostCSSConfig(base: string) {
|
|||
ranMigration = true
|
||||
|
||||
if (result) {
|
||||
await fs.writeFile(jsonConfigPath, JSON.stringify(result.json, null, 2))
|
||||
await writeFileSafely(jsonConfigPath, JSON.stringify(result.json, null, 2))
|
||||
|
||||
didMigrate = true
|
||||
didAddPostcssClient = result.didAddPostcssClient
|
||||
|
|
@ -206,7 +207,7 @@ async function migratePostCSSJSConfig(configPath: string): Promise<{
|
|||
newLines.push(line)
|
||||
}
|
||||
}
|
||||
await fs.writeFile(configPath, newLines.join('\n'))
|
||||
await writeFileSafely(configPath, newLines.join('\n'))
|
||||
|
||||
return { didAddPostcssClient, didRemoveAutoprefixer, didRemovePostCSSImport }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type { Config } from '../../../../tailwindcss/src/compat/plugin-api'
|
|||
import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
|
||||
import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map'
|
||||
import { spliceChangesIntoString, type StringChange } from '../../utils/splice-changes-into-string'
|
||||
import { writeFileSafely } from '../../utils/write-file-safely'
|
||||
import { extractRawCandidates } from './candidates'
|
||||
import { isSafeMigration } from './is-safe-migration'
|
||||
import { migrateAutomaticVarInjection } from './migrate-automatic-var-injection'
|
||||
|
|
@ -119,12 +120,18 @@ export default async function migrateContents(
|
|||
return spliceChangesIntoString(contents, changes)
|
||||
}
|
||||
|
||||
export async function migrate(designSystem: DesignSystem, userConfig: Config | null, file: string) {
|
||||
export async function migrate(
|
||||
designSystem: DesignSystem,
|
||||
userConfig: Config | null,
|
||||
file: string,
|
||||
): Promise<boolean> {
|
||||
let fullPath = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file)
|
||||
let contents = await fs.readFile(fullPath, 'utf-8')
|
||||
|
||||
await fs.writeFile(
|
||||
fullPath,
|
||||
await migrateContents(designSystem, userConfig, contents, extname(file)),
|
||||
)
|
||||
let migrated = await migrateContents(designSystem, userConfig, contents, extname(file))
|
||||
if (migrated === contents) return false // Nothing changed
|
||||
if (migrated.trim() === '') return false // Emptied out, something went horribly wrong
|
||||
|
||||
await writeFileSafely(fullPath, migrated)
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { Scanner } from '@tailwindcss/oxide'
|
||||
import { globby } from 'globby'
|
||||
import { globby, isGitIgnored } from 'globby'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import pc from 'picocolors'
|
||||
|
|
@ -23,6 +23,7 @@ import { isRepoDirty } from './utils/git'
|
|||
import { pkg } from './utils/packages'
|
||||
import { eprintln, error, header, highlight, info, relative, success } from './utils/renderer'
|
||||
import * as version from './utils/version'
|
||||
import { writeFileSafely } from './utils/write-file-safely'
|
||||
|
||||
const options = {
|
||||
'--config': { type: 'string', description: 'Path to the configuration file', alias: '-c' },
|
||||
|
|
@ -42,6 +43,7 @@ if (flags['--help']) {
|
|||
|
||||
async function run() {
|
||||
let base = process.cwd()
|
||||
let isIgnored = await isGitIgnored({ cwd: base })
|
||||
|
||||
eprintln(header())
|
||||
eprintln()
|
||||
|
|
@ -95,6 +97,7 @@ async function run() {
|
|||
info('Searching for CSS files in the current directory and its subdirectories…')
|
||||
|
||||
files = await globby(['**/*.css'], {
|
||||
cwd: base,
|
||||
absolute: true,
|
||||
gitignore: true,
|
||||
// gitignore: true will first search for all .gitignore including node_modules folders, this makes the initial search much faster
|
||||
|
|
@ -250,7 +253,7 @@ async function run() {
|
|||
for (let sheet of stylesheets) {
|
||||
if (!sheet.file) continue
|
||||
|
||||
await fs.writeFile(sheet.file, sheet.root.toString())
|
||||
await writeFileSafely(sheet.file, sheet.root.toString())
|
||||
|
||||
if (sheet.isTailwindRoot) {
|
||||
success(`Migrated stylesheet: ${highlight(relative(sheet.file, base))}`, { prefix: '↳ ' })
|
||||
|
|
@ -293,6 +296,8 @@ async function run() {
|
|||
let designSystem = await sheet.designSystem()
|
||||
if (!designSystem) continue
|
||||
|
||||
let config = configBySheet.get(sheet)
|
||||
|
||||
// Figure out the source files to migrate
|
||||
let sources = (() => {
|
||||
// Disable auto source detection
|
||||
|
|
@ -300,43 +305,121 @@ async function run() {
|
|||
return []
|
||||
}
|
||||
|
||||
// No root specified, use the base directory
|
||||
// No root specified
|
||||
if (compiler.root === null) {
|
||||
// When coming from Tailwind CSS v3, we have to use the
|
||||
// `config.sources` (which came from `config.content` originally)
|
||||
if (version.isMajor(3)) {
|
||||
if (config?.sources) {
|
||||
return config.sources.map((source) => ({ ...source, negated: false }))
|
||||
}
|
||||
|
||||
// When we don't have any sources, then we have to fallback to no
|
||||
// sources at all. We cannot fallback to the `**/*` pattern.
|
||||
return []
|
||||
}
|
||||
|
||||
// When we are upgrading a Tailwind CSS v4 and up version, we use
|
||||
// the default `**/*` pattern. All custom `@source` directives will
|
||||
// be attached later as sources.
|
||||
return [{ base, pattern: '**/*', negated: false }]
|
||||
}
|
||||
|
||||
// Use the specified root
|
||||
return [{ ...compiler.root, negated: false }]
|
||||
})().concat(compiler.sources)
|
||||
|
||||
let config = configBySheet.get(sheet)
|
||||
let scanner = new Scanner({ sources })
|
||||
let filesToMigrate = []
|
||||
|
||||
let ignoredPaths = new Set<string>()
|
||||
|
||||
for (let file of scanner.files) {
|
||||
file = await fs.realpath(file).catch(() => file) // Ensure we are dealing with the real path, not symlinks
|
||||
if (file.endsWith('.css')) continue
|
||||
|
||||
// When a file is git ignored, then we don't want to migrate it even
|
||||
// if it was listed in the `config.content` array or part of any
|
||||
// `@source` directives.
|
||||
//
|
||||
// We can make this an option later to explicitly allow this, but
|
||||
// this should be the default. This guarantees that:
|
||||
//
|
||||
// 1. Files coming from node_modules aren't touched
|
||||
// 2. Generated files aren't changed (the source should update, not the target)
|
||||
// 3. You can see all the changes that happened
|
||||
try {
|
||||
if (isIgnored(file)) {
|
||||
let culprit = file
|
||||
|
||||
// To prevent print all ignored files, we can also walk up the
|
||||
// parent tree and log those instead _if_ they are:
|
||||
//
|
||||
// 1. Also git ignored
|
||||
// 2. Are not going outside of the current repo
|
||||
let parent = path.dirname(file)
|
||||
do {
|
||||
try {
|
||||
if (isIgnored(parent)) {
|
||||
culprit = parent
|
||||
}
|
||||
} catch {
|
||||
// Escaping the current repo
|
||||
break
|
||||
}
|
||||
|
||||
parent = path.dirname(parent)
|
||||
} while (parent)
|
||||
|
||||
if (ignoredPaths.has(culprit)) continue // Already logged, skip
|
||||
ignoredPaths.add(culprit)
|
||||
|
||||
if (culprit === file) {
|
||||
info(`Git ignored, skipping: ${highlight(relative(culprit, base))}`, {
|
||||
prefix: '↳ ',
|
||||
})
|
||||
} else {
|
||||
info(`Git ignored folder, skipping: ${highlight(relative(culprit, base))}`, {
|
||||
prefix: '↳ ',
|
||||
})
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
} catch (err) {
|
||||
info(`Outside repository, skipping: ${highlight(relative(file, base))}`, {
|
||||
prefix: '↳ ',
|
||||
})
|
||||
// Skip this file when we run into errors. E.g.: when the current
|
||||
// file is not part of the current git repo it will throw an error.
|
||||
continue
|
||||
}
|
||||
|
||||
if (seenFiles.has(file)) continue
|
||||
seenFiles.add(file)
|
||||
filesToMigrate.push(file)
|
||||
}
|
||||
|
||||
// Migrate each file
|
||||
let changes = 0
|
||||
await Promise.allSettled(
|
||||
filesToMigrate.map((file) =>
|
||||
migrateTemplate(designSystem, config?.userConfig ?? null, file),
|
||||
),
|
||||
filesToMigrate.map(async (file) => {
|
||||
let changed = await migrateTemplate(designSystem, config?.userConfig ?? null, file)
|
||||
if (changed) {
|
||||
changes++
|
||||
info(`Migrated ${highlight(relative(file, base))}`, { prefix: '↳ ' })
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
if (config?.configFilePath) {
|
||||
success(
|
||||
`Migrated templates for configuration file: ${highlight(relative(config.configFilePath, base))}`,
|
||||
`Migrated templates for configuration file: ${highlight(relative(config.configFilePath, base))} (${changes} file${changes === 1 ? '' : 's'} changed)`,
|
||||
{ prefix: '↳ ' },
|
||||
)
|
||||
} else {
|
||||
success(
|
||||
`Migrated templates for: ${highlight(relative(sheet.file ?? '<unknown>', base))}`,
|
||||
{
|
||||
prefix: '↳ ',
|
||||
},
|
||||
`Migrated templates for: ${highlight(relative(sheet.file ?? '<unknown>', base))} (${changes} file${changes === 1 ? '' : 's'} changed)`,
|
||||
{ prefix: '↳ ' },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
packages/@tailwindcss-upgrade/src/utils/write-file-safely.ts
Normal file
49
packages/@tailwindcss-upgrade/src/utils/write-file-safely.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { randomUUID } from 'node:crypto'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
|
||||
export async function writeFileSafely(file: string, contents: string) {
|
||||
// Resolve symlinks so the rename replaces the actual target file rather than
|
||||
// replacing the symlink itself with a regular file.
|
||||
let realFile = await fs.realpath(file).catch(() => file)
|
||||
|
||||
// Start by creating a new file in the current directory that is guaranteed to
|
||||
// be unique (via `uuid`). We can embed the `process.id` in case we need to
|
||||
// debug things later.
|
||||
//
|
||||
// While we can write this to a more global `/tmp` folder, I want to be 100%
|
||||
// sure that we are on the same file system (same drive) so the rename
|
||||
// operation is atomic. Once the file is written, we will rename the file. If
|
||||
// this fails, the old file is still intact, if it works we have an updated
|
||||
// file.
|
||||
//
|
||||
// If this still causes problems (but it will slow things down):
|
||||
// 1. We could make sure that we inherit the file permissions
|
||||
// 2. Use an explicit fsync to force a flush to disk
|
||||
let temporaryFile = path.join(
|
||||
path.dirname(realFile),
|
||||
`.${path.basename(realFile)}.tailwind-upgrade.${process.pid}.${randomUUID()}.tmp`,
|
||||
)
|
||||
|
||||
// Write file uses the `w` flag by default, which is defined as:
|
||||
// > Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
|
||||
// > https://nodejs.org/api/fs.html#file-system-flags
|
||||
//
|
||||
// Which means that if this function is actively running, and you cancel the
|
||||
// process at the wrong time, then the truncated files are present. Since all
|
||||
// these migrations happen in parallel, multiple files are open and available
|
||||
// to be written to, it could mean in multiple truncated files.
|
||||
//
|
||||
// Writing to a temp file first means that if the process is cancelled at this
|
||||
// point, that the old original file is still correct.
|
||||
//
|
||||
// The rename part should be atomic (especially because we guarantee it to be
|
||||
// on the same file system) so this either succeeds or doesn't happen.
|
||||
try {
|
||||
await fs.writeFile(temporaryFile, contents, 'utf8')
|
||||
await fs.rename(temporaryFile, realFile)
|
||||
} catch (error) {
|
||||
await fs.unlink(temporaryFile).catch(() => {})
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/vite",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -62,8 +62,12 @@ export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
|
|||
|
||||
let jsResolver = config!.createResolver(config!.resolve)
|
||||
|
||||
customCssResolver = (id: string, base: string) => cssResolver(id, base, true, isSSR)
|
||||
customJsResolver = (id: string, base: string) => jsResolver(id, base, true, isSSR)
|
||||
customCssResolver = async (id: string, base: string) => {
|
||||
let resolved = await cssResolver(id, base, false, isSSR)
|
||||
if (resolved && !resolved.endsWith('.css')) return undefined
|
||||
return resolved
|
||||
}
|
||||
customJsResolver = (id: string, base: string) => jsResolver(id, base, false, isSSR)
|
||||
} else {
|
||||
type ResolveIdFn = (
|
||||
environment: Environment,
|
||||
|
|
@ -105,8 +109,12 @@ export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
|
|||
|
||||
let jsResolver = createBackCompatIdResolver(env.config, env.config.resolve)
|
||||
|
||||
customCssResolver = (id: string, base: string) => cssResolver(env, id, base, true)
|
||||
customJsResolver = (id: string, base: string) => jsResolver(env, id, base, true)
|
||||
customCssResolver = async (id: string, base: string) => {
|
||||
let resolved = await cssResolver(env, id, base, false)
|
||||
if (resolved && !resolved.endsWith('.css')) return undefined
|
||||
return resolved
|
||||
}
|
||||
customJsResolver = (id: string, base: string) => jsResolver(env, id, base, false)
|
||||
}
|
||||
|
||||
return new Root(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tailwindcss/webpack",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A webpack loader for Tailwind CSS v4.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -40,8 +40,12 @@ interface CacheEntry {
|
|||
|
||||
const cache = new QuickLRU<string, CacheEntry>({ maxSize: 50 })
|
||||
|
||||
function getContextFromCache(inputFile: string, opts: LoaderOptions): CacheEntry {
|
||||
let key = `${inputFile}:${opts.base ?? ''}:${JSON.stringify(opts.optimize)}`
|
||||
function getCacheKey(resourceId: string, opts: LoaderOptions): string {
|
||||
return `${resourceId}:${opts.base ?? ''}:${JSON.stringify(opts.optimize)}`
|
||||
}
|
||||
|
||||
function getContextFromCache(resourceId: string, opts: LoaderOptions): CacheEntry {
|
||||
let key = getCacheKey(resourceId, opts)
|
||||
if (cache.has(key)) return cache.get(key)!
|
||||
let entry: CacheEntry = {
|
||||
mtimes: new Map<string, number>(),
|
||||
|
|
@ -61,6 +65,7 @@ export default async function tailwindLoader(
|
|||
let callback = this.async()
|
||||
let options = this.getOptions() ?? {}
|
||||
let inputFile = this.resourcePath
|
||||
let resourceId = this.resource
|
||||
let base = options.base ?? process.cwd()
|
||||
let shouldOptimize = options.optimize ?? process.env.NODE_ENV === 'production'
|
||||
let isCSSModuleFile = inputFile.endsWith('.module.css')
|
||||
|
|
@ -83,7 +88,7 @@ export default async function tailwindLoader(
|
|||
}
|
||||
|
||||
try {
|
||||
let context = getContextFromCache(inputFile, options)
|
||||
let context = getContextFromCache(resourceId, options)
|
||||
let inputBasePath = path.dirname(path.resolve(inputFile))
|
||||
|
||||
// Whether this is the first build or not
|
||||
|
|
@ -273,7 +278,7 @@ export default async function tailwindLoader(
|
|||
callback(null, result)
|
||||
} catch (error) {
|
||||
// Clear the cache entry on error to force a full rebuild next time
|
||||
let key = `${inputFile}:${options.base ?? ''}:${JSON.stringify(options.optimize)}`
|
||||
let key = getCacheKey(resourceId, options)
|
||||
cache.delete(key)
|
||||
|
||||
DEBUG && I.end(`[@tailwindcss/webpack] ${path.relative(base, inputFile)}`)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tailwindcss",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.2",
|
||||
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { expect, it } from 'vitest'
|
||||
import { canonicalizeCalcExpressions } from './canonicalize-calc-expressions'
|
||||
|
||||
it.each([
|
||||
['calc(-1 * var(--foo))', 'calc(var(--foo) * -1)'],
|
||||
['calc(1rem + var(--foo))', 'calc(var(--foo) + 1rem)'],
|
||||
['calc(2rem * calc(3px * var(--foo)))', 'calc(calc(var(--foo) * 3px) * 2rem)'],
|
||||
['calc(var(--b) + var(--a))', 'calc(var(--a) + var(--b))'],
|
||||
['calc(3px * 2rem)', 'calc(2rem * 3px)'],
|
||||
['calc(5px * 3px)', 'calc(3px * 5px)'],
|
||||
['calc(1 * 1rem)', 'calc(1rem * 1)'],
|
||||
['calc(10 + 2)', 'calc(2 + 10)'],
|
||||
])('`%s` → `%s` (%#)', (input, expected) => {
|
||||
expect(canonicalizeCalcExpressions(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['calc(1rem - var(--foo))'],
|
||||
['calc(1rem / 2)'],
|
||||
['calc(var(--a) + 1rem)'],
|
||||
['calc(2rem * 3px)'],
|
||||
])('should keep `%s` (%#)', (input) => {
|
||||
expect(canonicalizeCalcExpressions(input)).toBe(input)
|
||||
})
|
||||
82
packages/tailwindcss/src/canonicalize-calc-expressions.ts
Normal file
82
packages/tailwindcss/src/canonicalize-calc-expressions.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { dimensions } from './utils/dimensions'
|
||||
import * as ValueParser from './value-parser'
|
||||
import { walk, WalkAction } from './walk'
|
||||
|
||||
// Assumption: We already assume that we receive somewhat valid `calc()`
|
||||
// expressions. So we will see `calc(1 + 1)` and not `calc(1+1)`
|
||||
export function canonicalizeCalcExpressions(input: string): string {
|
||||
let [canonicalized, valueAst] = canonicalizeCalcExpressionsAst(ValueParser.parse(input))
|
||||
|
||||
return canonicalized ? ValueParser.toCss(valueAst) : input
|
||||
}
|
||||
|
||||
export function canonicalizeCalcExpressionsAst(
|
||||
ast: ValueParser.ValueAstNode[],
|
||||
): [canonicalized: boolean, ast: ValueParser.ValueAstNode[]] {
|
||||
let canonicalized = false
|
||||
|
||||
walk(ast, {
|
||||
exit(valueNode) {
|
||||
// We are only interested in binary expressions in `calc(…)` and `(…)`,
|
||||
// and only with the `*` or `+` operators.
|
||||
if (valueNode.kind !== 'function') return
|
||||
if (valueNode.value !== 'calc' && valueNode.value !== '') return
|
||||
if (valueNode.nodes.length !== 5) return
|
||||
if (valueNode.nodes[2].kind !== 'word') return
|
||||
if (valueNode.nodes[2].value !== '*' && valueNode.nodes[2].value !== '+') return
|
||||
|
||||
let lhs = valueNode.nodes[0]
|
||||
let rhs = valueNode.nodes[4]
|
||||
|
||||
if (shouldSwap(lhs, rhs)) {
|
||||
canonicalized = true
|
||||
|
||||
let replacement: ValueParser.ValueFunctionNode = {
|
||||
kind: 'function',
|
||||
value: valueNode.value,
|
||||
nodes: [
|
||||
rhs, // Now lhs
|
||||
valueNode.nodes[1], // Separator
|
||||
valueNode.nodes[2], // Operator
|
||||
valueNode.nodes[3], // Separator
|
||||
lhs, // Now rhs
|
||||
],
|
||||
}
|
||||
|
||||
return WalkAction.ReplaceSkip(replacement)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return [canonicalized, ast]
|
||||
}
|
||||
|
||||
function shouldSwap(lhs: ValueParser.ValueAstNode, rhs: ValueParser.ValueAstNode): boolean {
|
||||
let lhsDimension = lhs.kind === 'word' ? dimensions.get(lhs.value) : null
|
||||
let rhsDimension = rhs.kind === 'word' ? dimensions.get(rhs.value) : null
|
||||
|
||||
if (lhsDimension !== null && rhsDimension === null) return true
|
||||
if (lhsDimension === null && rhsDimension !== null) return false
|
||||
|
||||
if (lhsDimension !== null && rhsDimension !== null) {
|
||||
let [lhsValue, lhsUnit] = lhsDimension
|
||||
let [rhsValue, rhsUnit] = rhsDimension
|
||||
|
||||
// Within dimensions, keep unit-bearing values ahead of unitless numbers so
|
||||
// `1rem` sorts before `1`.
|
||||
if (lhsUnit === null && rhsUnit !== null) return true
|
||||
if (lhsUnit !== null && rhsUnit === null) return false
|
||||
|
||||
// Then sort dimensions numerically, and finally by unit for ties.
|
||||
if (lhsValue !== rhsValue) {
|
||||
return lhsValue - rhsValue > 0
|
||||
}
|
||||
|
||||
if (lhsUnit !== rhsUnit) {
|
||||
return (lhsUnit ?? '').localeCompare(rhsUnit ?? '') > 0
|
||||
}
|
||||
}
|
||||
|
||||
// Both nodes are unknown values (not dimensions), sort them as strings
|
||||
return ValueParser.toCss([lhs]).localeCompare(ValueParser.toCss([rhs])) > 0
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { randomUUID } from 'node:crypto'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
|
@ -92,30 +93,6 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
}
|
||||
|
||||
async function expectCanonicalization(
|
||||
input: string,
|
||||
candidate: string,
|
||||
expected: string,
|
||||
options: CanonicalizeOptions = DEFAULT_CANONICALIZATION_OPTIONS,
|
||||
) {
|
||||
candidate = prepare(candidate)
|
||||
expected = prepare(expected)
|
||||
|
||||
if (strategy === 'prefix') {
|
||||
input = input.replace("@import 'tailwindcss';", "@import 'tailwindcss' prefix(tw);")
|
||||
}
|
||||
|
||||
let designSystem = await designSystems.get(__dirname).get(input)
|
||||
let [actual] = designSystem.canonicalizeCandidates([candidate], options)
|
||||
|
||||
try {
|
||||
expect(actual).toBe(expected)
|
||||
} catch (err) {
|
||||
if (err instanceof Error) Error.captureStackTrace(err, expectCanonicalization)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async function expectCombinedCanonicalization(
|
||||
input: string,
|
||||
candidates: string,
|
||||
expected: string,
|
||||
|
|
@ -134,179 +111,190 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
try {
|
||||
expect(actual).toEqual(preparedExpected)
|
||||
} catch (err) {
|
||||
if (err instanceof Error) Error.captureStackTrace(err, expectCombinedCanonicalization)
|
||||
if (err instanceof Error) Error.captureStackTrace(err, expectCanonicalization)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------
|
||||
|
||||
test.each([
|
||||
/// Legacy bg-gradient-* → bg-linear-*
|
||||
['bg-gradient-to-t', 'bg-linear-to-t'],
|
||||
['bg-gradient-to-tr', 'bg-linear-to-tr'],
|
||||
['bg-gradient-to-r', 'bg-linear-to-r'],
|
||||
['bg-gradient-to-br', 'bg-linear-to-br'],
|
||||
['bg-gradient-to-b', 'bg-linear-to-b'],
|
||||
['bg-gradient-to-bl', 'bg-linear-to-bl'],
|
||||
['bg-gradient-to-l', 'bg-linear-to-l'],
|
||||
['bg-gradient-to-tl', 'bg-linear-to-tl'],
|
||||
|
||||
/// theme(…) to `var(…)`
|
||||
// Keep candidates that don't contain `theme(…)` or `theme(…, …)`
|
||||
['[color:red]', 'text-[red]'],
|
||||
|
||||
// Handle special cases around `.1` in the `theme(…)`
|
||||
['[--value:theme(spacing.1)]', '[--value:--spacing(1)]'],
|
||||
['[--value:theme(fontSize.xs.1.lineHeight)]', '[--value:var(--text-xs--line-height)]'],
|
||||
['[--value:theme(spacing[1.25])]', '[--value:--spacing(1.25)]'],
|
||||
|
||||
// Should not convert invalid spacing values to calc
|
||||
['[--value:theme(spacing[1.1])]', '[--value:theme(spacing[1.1])]'],
|
||||
|
||||
// Convert to `var(…)` if we can resolve the path
|
||||
['[color:theme(colors.red.500)]', 'text-red-500'], // Arbitrary property
|
||||
['[color:theme(colors.red.500)]/50', 'text-red-500/50'], // Arbitrary property + modifier
|
||||
['bg-[theme(colors.red.500)]', 'bg-red-500'], // Arbitrary value
|
||||
['bg-[size:theme(spacing.4)]', 'bg-size-[--spacing(4)]'], // Arbitrary value + data type hint
|
||||
|
||||
// Pretty print CSS functions preceded by an operator to prevent consecutive
|
||||
// operator characters.
|
||||
['w-[calc(100dvh-theme(spacing.2))]', 'w-[calc(100dvh-(--spacing(2)))]'],
|
||||
['w-[calc(100dvh+theme(spacing.2))]', 'w-[calc(100dvh+(--spacing(2)))]'],
|
||||
['w-[calc(100dvh/theme(spacing.2))]', 'w-[calc(100dvh/(--spacing(2)))]'],
|
||||
['w-[calc(100dvh*theme(spacing.2))]', 'w-[calc(100dvh*(--spacing(2)))]'],
|
||||
|
||||
// Convert to `var(…)` if we can resolve the path, but keep fallback values
|
||||
['bg-[theme(colors.red.500,red)]', 'bg-(--color-red-500,red)'],
|
||||
|
||||
// Keep `theme(…)` if we can't resolve the path
|
||||
['bg-[theme(colors.foo.1000)]', 'bg-[theme(colors.foo.1000)]'],
|
||||
|
||||
// Keep `theme(…)` if we can't resolve the path, but still try to convert the
|
||||
// fallback value.
|
||||
['bg-[theme(colors.foo.1000,theme(colors.red.500))]', 'bg-red-500'],
|
||||
|
||||
// Use `theme(…)` (deeply nested) inside of a `calc(…)` function
|
||||
['text-[calc(theme(fontSize.xs)*2)]', 'text-[calc(var(--text-xs)*2)]'],
|
||||
|
||||
// Multiple `theme(… / …)` calls should result in modern syntax of `theme(…)`
|
||||
// - Can't convert to `var(…)` because that would lose the modifier.
|
||||
// - Can't convert to a candidate modifier because there are multiple
|
||||
// `theme(…)` calls.
|
||||
//
|
||||
// If we really want to, we can make a fancy migration that tries to move it
|
||||
// to a candidate modifier _if_ all `theme(…)` calls use the same modifier.
|
||||
[
|
||||
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]',
|
||||
'text-[--theme(--color-red-500/50,--theme(--color-blue-500/50))]',
|
||||
],
|
||||
[
|
||||
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]/50',
|
||||
'text-[--theme(--color-red-500/50,--theme(--color-blue-500/50))]/50',
|
||||
],
|
||||
|
||||
// Convert the `theme(…)`, but try to move the inline modifier (e.g. `50%`),
|
||||
// to a candidate modifier.
|
||||
// Arbitrary property, with simple percentage modifier
|
||||
['[color:theme(colors.red.500/75%)]', 'text-red-500/75'],
|
||||
|
||||
// Arbitrary property, with numbers (0-1) without a unit
|
||||
['[color:theme(colors.red.500/.12)]', 'text-red-500/12'],
|
||||
['[color:theme(colors.red.500/0.12)]', 'text-red-500/12'],
|
||||
|
||||
// Arbitrary property, with more complex modifier (we only allow whole numbers
|
||||
// as bare modifiers). Convert the complex numbers to arbitrary values instead.
|
||||
['[color:theme(colors.red.500/12.34%)]', 'text-red-500/[12.34%]'],
|
||||
['[color:theme(colors.red.500/var(--opacity))]', 'text-red-500/(--opacity)'],
|
||||
['[color:theme(colors.red.500/.12345)]', 'text-red-500/1234.5'],
|
||||
['[color:theme(colors.red.500/50.25%)]', 'text-red-500/50.25'],
|
||||
|
||||
// Arbitrary value
|
||||
['bg-[theme(colors.red.500/75%)]', 'bg-red-500/75'],
|
||||
['bg-[theme(colors.red.500/12.34%)]', 'bg-red-500/[12.34%]'],
|
||||
|
||||
// Arbitrary property that already contains a modifier
|
||||
['[color:theme(colors.red.500/50%)]/50', 'text-[--theme(--color-red-500/50%)]/50'],
|
||||
|
||||
// Values that don't contain only `theme(…)` calls should not be converted to
|
||||
// use a modifier since the color is not the whole value.
|
||||
[
|
||||
'shadow-[shadow:inset_0px_1px_theme(colors.white/15%)]',
|
||||
'shadow-[inset_0px_1px_--theme(--color-white/15%)]',
|
||||
],
|
||||
|
||||
// Arbitrary value, where the candidate already contains a modifier
|
||||
// This should still migrate the `theme(…)` syntax to the modern syntax.
|
||||
['bg-[theme(colors.red.500/50%)]/50', 'bg-[--theme(--color-red-500/50%)]/50'],
|
||||
|
||||
// Variants, we can't use `var(…)` especially inside of `@media(…)`. We can
|
||||
// still upgrade the `theme(…)` to the modern syntax.
|
||||
['max-[theme(screens.lg)]:flex', 'max-[--theme(--breakpoint-lg)]:flex'],
|
||||
// There are no variables for `--spacing` multiples, so we can't convert this
|
||||
['max-[theme(spacing.4)]:flex', 'max-[theme(spacing.4)]:flex'],
|
||||
|
||||
// This test in itself doesn't make much sense. But we need to make sure
|
||||
// that this doesn't end up as the modifier in the candidate itself.
|
||||
['max-[theme(spacing.4/50)]:flex', 'max-[theme(spacing.4/50)]:flex'],
|
||||
|
||||
// `theme(…)` calls in another CSS function is replaced correctly.
|
||||
// Additionally we remove unnecessary whitespace.
|
||||
['grid-cols-[min(50%_,_theme(spacing.80))_auto]', 'grid-cols-[min(50%,--spacing(80))_auto]'],
|
||||
|
||||
// `calc(var(--spacing)*…)` to `--spacing(…)`
|
||||
['pt-[min(20%,calc(var(--spacing)*8))]', 'pt-[min(20%,--spacing(8))]'],
|
||||
['pt-[min(20%,calc(var(--spacing)*var(--other)))]', 'pt-[min(20%,--spacing(var(--other)))]'],
|
||||
['pt-[calc(var(--spacing)*8)]', 'pt-8'],
|
||||
['pt-[calc(var(--spacing)*var(--other))]', 'pt-[--spacing(var(--other))]'],
|
||||
|
||||
['[padding-top:min(20%,calc(var(--spacing)*8))]', 'pt-[min(20%,--spacing(8))]'],
|
||||
[
|
||||
'[padding-top:min(20%,calc(var(--spacing)*var(--other)))]',
|
||||
'pt-[min(20%,--spacing(var(--other)))]',
|
||||
],
|
||||
['[padding-top:calc(var(--spacing)*8)]', 'pt-8'],
|
||||
['[padding-top:calc(var(--spacing)*var(--other))]', 'pt-[--spacing(var(--other))]'],
|
||||
|
||||
// `theme(…)` calls valid in v3, but not in v4 should still be converted.
|
||||
['[--foo:theme(transitionDuration.500)]', '[--foo:theme(transitionDuration.500)]'],
|
||||
|
||||
// Renamed theme keys
|
||||
['max-w-[theme(screens.md)]', 'max-w-(--breakpoint-md)'],
|
||||
['w-[theme(maxWidth.md)]', 'w-md'],
|
||||
|
||||
// Invalid cases
|
||||
['[--foo:theme(colors.red.500/50/50)]', '[--foo:theme(colors.red.500/50/50)]'],
|
||||
['[--foo:theme(colors.red.500/50/50)]/50', '[--foo:theme(colors.red.500/50/50)]/50'],
|
||||
|
||||
// Partially invalid cases
|
||||
[
|
||||
'[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]',
|
||||
'[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]',
|
||||
],
|
||||
[
|
||||
'[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]/50',
|
||||
'[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]/50',
|
||||
],
|
||||
|
||||
// If a utility sets `property` and `--tw-{property}` with the same value,
|
||||
// we can ignore the `--tw-{property}`. This is just here for composition.
|
||||
// This means that we should be able to upgrade the one _without_ to the one
|
||||
// _with_ the variable
|
||||
['[font-weight:400]', 'font-normal'],
|
||||
['[line-height:0]', 'leading-0'],
|
||||
['[border-style:solid]', 'border-solid'],
|
||||
])(testName, { timeout }, async (candidate, expected) => {
|
||||
await expectCanonicalization(
|
||||
css`
|
||||
describe('deprecated utilities', () => {
|
||||
test.each([
|
||||
/// Legacy bg-gradient-* → bg-linear-*
|
||||
['bg-gradient-to-t', 'bg-linear-to-t'],
|
||||
['bg-gradient-to-tr', 'bg-linear-to-tr'],
|
||||
['bg-gradient-to-r', 'bg-linear-to-r'],
|
||||
['bg-gradient-to-br', 'bg-linear-to-br'],
|
||||
['bg-gradient-to-b', 'bg-linear-to-b'],
|
||||
['bg-gradient-to-bl', 'bg-linear-to-bl'],
|
||||
['bg-gradient-to-l', 'bg-linear-to-l'],
|
||||
['bg-gradient-to-tl', 'bg-linear-to-tl'],
|
||||
])(testName, { timeout }, async (candidate, expected) => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`,
|
||||
candidate,
|
||||
expected,
|
||||
)
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
let deprecated: [string, string][] = [
|
||||
['order-none', 'order-0'],
|
||||
['break-words', 'wrap-break-word'],
|
||||
['overflow-ellipsis', 'text-ellipsis'],
|
||||
|
||||
['start-full', 'inset-s-full'],
|
||||
['-start-full', '-inset-s-full'],
|
||||
['start-auto', 'inset-s-auto'],
|
||||
['start-px', 'inset-s-px'],
|
||||
['-start-px', '-inset-s-px'],
|
||||
['start-8', 'inset-s-8'], // Within default spacing scale
|
||||
['-start-8', '-inset-s-8'], // Within default spacing scale
|
||||
['start-123', 'inset-s-123'], // Outside of default spacing scale
|
||||
['-start-123', '-inset-s-123'], // Outside of default spacing scale
|
||||
|
||||
['end-full', 'inset-e-full'],
|
||||
['-end-full', '-inset-e-full'],
|
||||
['end-auto', 'inset-e-auto'],
|
||||
['end-px', 'inset-e-px'],
|
||||
['-end-px', '-inset-e-px'],
|
||||
['end-8', 'inset-e-8'], // Within default spacing scale
|
||||
['-end-8', '-inset-e-8'], // Within default spacing scale
|
||||
['end-123', 'inset-e-123'], // Outside of default spacing scale
|
||||
['-end-123', '-inset-e-123'], // Outside of default spacing scale
|
||||
]
|
||||
|
||||
test.each(deprecated)(testName, { timeout }, async (candidate, expected) => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
describe('With custom implementation', () => {
|
||||
// Creating a shared CSS file such that we can re-use the same design
|
||||
// system for all of these.
|
||||
let customImplementations = deprecated
|
||||
.map(
|
||||
([candidate]) => css`
|
||||
@utility ${candidate} {
|
||||
--custom-${randomUUID()}: implementation;
|
||||
}
|
||||
`,
|
||||
)
|
||||
.join('\n')
|
||||
|
||||
// Keep the current utility because of the custom implementation
|
||||
test.each(deprecated.map(([candidate]) => [candidate, candidate]))(
|
||||
testName,
|
||||
{ timeout },
|
||||
async (candidate, expected) => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
|
||||
${customImplementations}
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('arbitrary utilities', () => {
|
||||
describe('arbitrary properties', () => {
|
||||
test.each([
|
||||
/// theme(…) to `var(…)`
|
||||
// Keep candidates that don't contain `theme(…)` or `theme(…, …)`
|
||||
['[color:red]', 'text-[red]'],
|
||||
|
||||
// Handle special cases around `.1` in the `theme(…)`
|
||||
['[--value:theme(spacing.1)]', '[--value:--spacing(1)]'],
|
||||
['[--value:theme(fontSize.xs.1.lineHeight)]', '[--value:var(--text-xs--line-height)]'],
|
||||
['[--value:theme(spacing[1.25])]', '[--value:--spacing(1.25)]'],
|
||||
|
||||
// Should not convert invalid spacing values to calc
|
||||
['[--value:theme(spacing[1.1])]', '[--value:theme(spacing[1.1])]'],
|
||||
|
||||
// Convert to `var(…)` if we can resolve the path
|
||||
['[color:theme(colors.red.500)]', 'text-red-500'], // Arbitrary property
|
||||
['[color:theme(colors.red.500)]/50', 'text-red-500/50'], // Arbitrary property + modifier
|
||||
|
||||
// Multiple `theme(… / …)` calls should result in modern syntax of `theme(…)`
|
||||
// - Can't convert to `var(…)` because that would lose the modifier.
|
||||
// - Can't convert to a candidate modifier because there are multiple
|
||||
// `theme(…)` calls.
|
||||
//
|
||||
// If we really want to, we can make a fancy migration that tries to move it
|
||||
// to a candidate modifier _if_ all `theme(…)` calls use the same modifier.
|
||||
[
|
||||
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]',
|
||||
'text-[--theme(--color-red-500/50,--theme(--color-blue-500/50))]',
|
||||
],
|
||||
[
|
||||
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]/50',
|
||||
'text-[--theme(--color-red-500/50,--theme(--color-blue-500/50))]/50',
|
||||
],
|
||||
|
||||
// Convert the `theme(…)`, but try to move the inline modifier (e.g. `50%`),
|
||||
// to a candidate modifier.
|
||||
// Arbitrary property, with simple percentage modifier
|
||||
['[color:theme(colors.red.500/75%)]', 'text-red-500/75'],
|
||||
|
||||
// Arbitrary property, with numbers (0-1) without a unit
|
||||
['[color:theme(colors.red.500/.12)]', 'text-red-500/12'],
|
||||
['[color:theme(colors.red.500/0.12)]', 'text-red-500/12'],
|
||||
|
||||
// Arbitrary property, with more complex modifier (we only allow whole numbers
|
||||
// as bare modifiers). Convert the complex numbers to arbitrary values instead.
|
||||
['[color:theme(colors.red.500/12.34%)]', 'text-red-500/[12.34%]'],
|
||||
['[color:theme(colors.red.500/var(--opacity))]', 'text-red-500/(--opacity)'],
|
||||
['[color:theme(colors.red.500/.12345)]', 'text-red-500/1234.5'],
|
||||
['[color:theme(colors.red.500/50.25%)]', 'text-red-500/50.25'],
|
||||
|
||||
// Arbitrary property that already contains a modifier
|
||||
['[color:theme(colors.red.500/50%)]/50', 'text-[--theme(--color-red-500/50%)]/50'],
|
||||
|
||||
// `calc(var(--spacing)*…)` to `--spacing(…)`
|
||||
['[padding-top:min(20%,calc(var(--spacing)*8))]', 'pt-[min(20%,--spacing(8))]'],
|
||||
[
|
||||
'[padding-top:min(20%,calc(var(--spacing)*var(--other)))]',
|
||||
'pt-[min(20%,--spacing(var(--other)))]',
|
||||
],
|
||||
['[padding-top:calc(var(--spacing)*8)]', 'pt-8'],
|
||||
['[padding-top:calc(var(--spacing)*var(--other))]', 'pt-[--spacing(var(--other))]'],
|
||||
|
||||
// `theme(…)` calls valid in v3, but not in v4 should still be converted.
|
||||
['[--foo:theme(transitionDuration.500)]', '[--foo:theme(transitionDuration.500)]'],
|
||||
|
||||
// Invalid cases
|
||||
['[--foo:theme(colors.red.500/50/50)]', '[--foo:theme(colors.red.500/50/50)]'],
|
||||
['[--foo:theme(colors.red.500/50/50)]/50', '[--foo:theme(colors.red.500/50/50)]/50'],
|
||||
|
||||
// Partially invalid cases
|
||||
[
|
||||
'[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]',
|
||||
'[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]',
|
||||
],
|
||||
[
|
||||
'[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]/50',
|
||||
'[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]/50',
|
||||
],
|
||||
|
||||
// If a utility sets `property` and `--tw-{property}` with the same value,
|
||||
// we can ignore the `--tw-{property}`. This is just here for composition.
|
||||
// This means that we should be able to upgrade the one _without_ to the one
|
||||
// _with_ the variable
|
||||
['[font-weight:400]', 'font-normal'],
|
||||
['[line-height:0]', 'leading-0'],
|
||||
['[border-style:solid]', 'border-solid'],
|
||||
])(testName, { timeout }, async (candidate, expected) => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
test.each([
|
||||
// Arbitrary property to static utility
|
||||
['[text-wrap:balance]', 'text-balance'],
|
||||
|
|
@ -317,10 +305,6 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
['[display:_flex]', 'flex'],
|
||||
['[display:flex_]', 'flex'],
|
||||
|
||||
// Arbitrary property to static utility
|
||||
// Map number to keyword-like value
|
||||
['leading-[1]', 'leading-none'],
|
||||
|
||||
// Arbitrary property to named functional utility
|
||||
['[color:var(--color-red-500)]', 'text-red-500'],
|
||||
['[background-color:var(--color-red-500)]', 'bg-red-500'],
|
||||
|
|
@ -348,20 +332,6 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
['[grid-column:2]', 'col-2'],
|
||||
['[grid-column:1234]', 'col-1234'],
|
||||
|
||||
// Arbitrary value to bare value
|
||||
['border-[2px]', 'border-2'],
|
||||
['border-[1234px]', 'border-1234'],
|
||||
|
||||
// Arbitrary value with data type, to more specific arbitrary value
|
||||
['bg-[position:123px]', 'bg-position-[123px]'],
|
||||
['bg-[size:123px]', 'bg-size-[123px]'],
|
||||
|
||||
// Arbitrary value with inferred data type, to more specific arbitrary value
|
||||
['bg-[123px]', 'bg-position-[123px]'],
|
||||
|
||||
// Arbitrary value with spacing mul
|
||||
['w-[64rem]', 'w-256'],
|
||||
|
||||
// Complex arbitrary property to arbitrary value
|
||||
[
|
||||
'[grid-template-columns:repeat(2,minmax(100px,1fr))]',
|
||||
|
|
@ -369,13 +339,6 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
],
|
||||
// Complex arbitrary property to bare value
|
||||
['[grid-template-columns:repeat(2,minmax(0,1fr))]', 'grid-cols-2'],
|
||||
|
||||
// Arbitrary value to bare value with percentage
|
||||
['from-[25%]', 'from-25%'],
|
||||
|
||||
// Arbitrary percentage value must be a whole number. Should not migrate to
|
||||
// a bare value.
|
||||
['from-[2.5%]', 'from-[2.5%]'],
|
||||
])(testName, { timeout }, async (candidate, expected) => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
|
|
@ -392,7 +355,129 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('arbitrary values', () => {
|
||||
test.each([
|
||||
// Convert to `var(…)` if we can resolve the path
|
||||
['bg-[theme(colors.red.500)]', 'bg-red-500'], // Arbitrary value
|
||||
['bg-[size:theme(spacing.4)]', 'bg-size-[--spacing(4)]'], // Arbitrary value + data type hint
|
||||
|
||||
// Pretty print CSS functions preceded by an operator to prevent consecutive
|
||||
// operator characters.
|
||||
['w-[calc(100dvh-theme(spacing.2))]', 'w-[calc(100dvh-(--spacing(2)))]'],
|
||||
['w-[calc(100dvh+theme(spacing.2))]', 'w-[calc(100dvh+(--spacing(2)))]'],
|
||||
['w-[calc(100dvh/theme(spacing.2))]', 'w-[calc(100dvh/(--spacing(2)))]'],
|
||||
['w-[calc(100dvh*theme(spacing.2))]', 'w-[calc(100dvh*(--spacing(2)))]'],
|
||||
|
||||
// Convert to `var(…)` if we can resolve the path, but keep fallback values
|
||||
['bg-[theme(colors.red.500,red)]', 'bg-(--color-red-500,red)'],
|
||||
|
||||
// Keep `theme(…)` if we can't resolve the path
|
||||
['bg-[theme(colors.foo.1000)]', 'bg-[theme(colors.foo.1000)]'],
|
||||
|
||||
// Keep `theme(…)` if we can't resolve the path, but still try to convert the
|
||||
// fallback value.
|
||||
['bg-[theme(colors.foo.1000,theme(colors.red.500))]', 'bg-red-500'],
|
||||
|
||||
// Use `theme(…)` (deeply nested) inside of a `calc(…)` function
|
||||
['text-[calc(theme(fontSize.xs)*2)]', 'text-[calc(var(--text-xs)*2)]'],
|
||||
|
||||
// Arbitrary value
|
||||
['bg-[theme(colors.red.500/75%)]', 'bg-red-500/75'],
|
||||
['bg-[theme(colors.red.500/12.34%)]', 'bg-red-500/[12.34%]'],
|
||||
|
||||
// Values that don't contain only `theme(…)` calls should not be converted to
|
||||
// use a modifier since the color is not the whole value.
|
||||
[
|
||||
'shadow-[shadow:inset_0px_1px_theme(colors.white/15%)]',
|
||||
'shadow-[inset_0px_1px_--theme(--color-white/15%)]',
|
||||
],
|
||||
|
||||
// Arbitrary value, where the candidate already contains a modifier
|
||||
// This should still migrate the `theme(…)` syntax to the modern syntax.
|
||||
['bg-[theme(colors.red.500/50%)]/50', 'bg-[--theme(--color-red-500/50%)]/50'],
|
||||
|
||||
// Variants, we can't use `var(…)` especially inside of `@media(…)`. We can
|
||||
// still upgrade the `theme(…)` to the modern syntax.
|
||||
['max-[theme(screens.lg)]:flex', 'max-[--theme(--breakpoint-lg)]:flex'],
|
||||
// There are no variables for `--spacing` multiples, so we can't convert this
|
||||
['max-[theme(spacing.4)]:flex', 'max-[theme(spacing.4)]:flex'],
|
||||
|
||||
// This test in itself doesn't make much sense. But we need to make sure
|
||||
// that this doesn't end up as the modifier in the candidate itself.
|
||||
['max-[theme(spacing.4/50)]:flex', 'max-[theme(spacing.4/50)]:flex'],
|
||||
|
||||
// `theme(…)` calls in another CSS function is replaced correctly.
|
||||
// Additionally we remove unnecessary whitespace.
|
||||
['grid-cols-[min(50%_,_theme(spacing.80))_auto]', 'grid-cols-[min(50%,--spacing(80))_auto]'],
|
||||
|
||||
// `calc(var(--spacing)*…)` to `--spacing(…)`
|
||||
['pt-[min(20%,calc(var(--spacing)*8))]', 'pt-[min(20%,--spacing(8))]'],
|
||||
['pt-[min(20%,calc(var(--spacing)*var(--other)))]', 'pt-[min(20%,--spacing(var(--other)))]'],
|
||||
['pt-[calc(var(--spacing)*8)]', 'pt-8'],
|
||||
['pt-[calc(var(--spacing)*var(--other))]', 'pt-[--spacing(var(--other))]'],
|
||||
|
||||
// Renamed theme keys
|
||||
['max-w-[theme(screens.md)]', 'max-w-(--breakpoint-md)'],
|
||||
['w-[theme(maxWidth.md)]', 'w-md'],
|
||||
|
||||
// Arbitrary property to static utility
|
||||
// Map number to keyword-like value
|
||||
['leading-[1]', 'leading-none'],
|
||||
|
||||
// Arbitrary value to bare value
|
||||
['border-[2px]', 'border-2'],
|
||||
['border-[1234px]', 'border-1234'],
|
||||
|
||||
// Arbitrary value with data type, to more specific arbitrary value
|
||||
['bg-[position:123px]', 'bg-position-[123px]'],
|
||||
['bg-[size:123px]', 'bg-size-[123px]'],
|
||||
|
||||
// Arbitrary value with inferred data type, to more specific arbitrary value
|
||||
['bg-[123px]', 'bg-position-[123px]'],
|
||||
|
||||
// Arbitrary value with spacing mul
|
||||
['w-[64rem]', 'w-256'],
|
||||
|
||||
// Arbitrary value to bare value with percentage
|
||||
['from-[25%]', 'from-25%'],
|
||||
|
||||
// Arbitrary percentage value must be a whole number. Should not migrate to
|
||||
// a bare value.
|
||||
['from-[2.5%]', 'from-[2.5%]'],
|
||||
|
||||
// Negative arbitrary values can be simplified
|
||||
// 1. Try to move the sign _inside_ the arbitrary value
|
||||
// 2. Try to move the sign _out_ of the arbitrary value
|
||||
['-mt-[12rem]', '-mt-48'], // Arbitrary value → bare value
|
||||
['-mt-[-12rem]', 'mt-48'], // Double negation
|
||||
['-mt-[12.34rem]', 'mt-[-12.34rem]'], // Move `-` inside
|
||||
['-mt-[-12.34rem]', 'mt-[12.34rem]'], // Move `-` inside, double negation
|
||||
['-mt-[12.34px]', 'mt-[-12.34px]'],
|
||||
['-mt-[-12.34px]', 'mt-[12.34px]'],
|
||||
['-mt-[492px]', '-mt-123'], // Moving inside, allows us to migrate to a bare value
|
||||
['-mt-[calc(-1*492px)]', 'mt-123'], // Double negation and constant folding into bare value
|
||||
['-mt-[-492px]', 'mt-123'],
|
||||
['-mt-[calc(-1*-492px)]', '-mt-123'], // Constant folding with calc expressions
|
||||
['-mt-(--my-var)', '-mt-(--my-var)'], // Keep as-is
|
||||
['-mt-[var(--my-var)]', '-mt-(--my-var)'], // Keep as-is, but convert to shorthand
|
||||
['mt-[calc(var(--my-var)*-1)]', '-mt-(--my-var)'], // Move `-` out
|
||||
['mt-[calc(-1*var(--my-var))]', '-mt-(--my-var)'], // Move `-` out
|
||||
['-mt-[calc(var(--my-var)*-1)]', 'mt-(--my-var)'], // Move `-` out
|
||||
['-mt-[calc(-1*var(--my-var))]', 'mt-(--my-var)'], // Move `-` out
|
||||
['mt-[calc(-1*calc(-1*var(--my-var)))]', 'mt-(--my-var)'], // Move `-` out
|
||||
['-mt-[calc(-1*calc(-1*var(--my-var)))]', '-mt-(--my-var)'], // Move `-` out
|
||||
])(testName, { timeout }, async (candidate, expected) => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('arbitrary utilities', () => {
|
||||
test('migrate with custom static utility `@utility custom {…}`', { timeout }, async () => {
|
||||
let candidate = '[--key:value]'
|
||||
let expected = 'custom'
|
||||
|
|
@ -610,71 +695,6 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
})
|
||||
})
|
||||
|
||||
describe('deprecated utilities', () => {
|
||||
test('`order-none` → `order-0`', { timeout }, async () => {
|
||||
let candidate = 'order-none'
|
||||
let expected = 'order-0'
|
||||
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
test('`order-none` → `order-none` with custom implementation', { timeout }, async () => {
|
||||
let candidate = 'order-none'
|
||||
let expected = 'order-none'
|
||||
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
|
||||
@utility order-none {
|
||||
order: none; /* imagine this exists */
|
||||
}
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
test('`break-words` → `wrap-break-word`', { timeout }, async () => {
|
||||
let candidate = 'break-words'
|
||||
let expected = 'wrap-break-word'
|
||||
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
test('`[overflow-wrap:break-word]` → `wrap-break-word`', { timeout }, async () => {
|
||||
let candidate = '[overflow-wrap:break-word]'
|
||||
let expected = 'wrap-break-word'
|
||||
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
|
||||
test('`break-words` → `break-words` with custom implementation', { timeout }, async () => {
|
||||
let candidate = 'break-words'
|
||||
let expected = 'break-words'
|
||||
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
|
||||
@utility break-words {
|
||||
break: words; /* imagine this exists */
|
||||
}
|
||||
`
|
||||
|
||||
await expectCanonicalization(input, candidate, expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('arbitrary variants', () => {
|
||||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
|
|
@ -1044,9 +1064,21 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
test.each([
|
||||
// 4 to 1
|
||||
['mt-1 mr-1 mb-1 ml-1', 'm-1'],
|
||||
['border-t-123 border-r-123 border-b-123 border-l-123', 'border-123'],
|
||||
['border-t-1 border-r-1 border-b-1 border-l-1', 'border'], // `border` is shorter than `border-1`
|
||||
['border-t-red-500 border-r-red-500 border-b-red-500 border-l-red-500', 'border-red-500'],
|
||||
['scroll-mt-1 scroll-mr-1 scroll-mb-1 scroll-ml-1', 'scroll-m-1'],
|
||||
['scroll-pt-1 scroll-pr-1 scroll-pb-1 scroll-pl-1', 'scroll-p-1'],
|
||||
|
||||
// 2 to 1
|
||||
['mt-1 mb-1', 'my-1'],
|
||||
['border-t-123 border-b-123', 'border-y-123'],
|
||||
['border-t-1 border-b-1', 'border-y'], // `border-y` is shorter than `border-y-1`
|
||||
['border-t-red-500 border-b-red-500', 'border-y-red-500'],
|
||||
['scroll-mt-1 scroll-mb-1', 'scroll-my-1'],
|
||||
['scroll-pt-1 scroll-pb-1', 'scroll-py-1'],
|
||||
['overflow-x-hidden overflow-y-hidden', 'overflow-hidden'],
|
||||
['overscroll-x-contain overscroll-y-contain', 'overscroll-contain'],
|
||||
|
||||
// Different order as above
|
||||
['mb-1 mt-1', 'my-1'],
|
||||
|
|
@ -1083,7 +1115,7 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
await expectCombinedCanonicalization(input, candidates, expected)
|
||||
await expectCanonicalization(input, candidates, expected)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -1117,9 +1149,43 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
|
|||
let input = css`
|
||||
@import 'tailwindcss';
|
||||
`
|
||||
await expectCombinedCanonicalization(input, candidates.trim(), expected)
|
||||
await expectCanonicalization(input, candidates.trim(), expected)
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1558
|
||||
test.each([
|
||||
['tracking-[-0.05em]', 'tracking-tighter'],
|
||||
['tracking-[-0.025em]', 'tracking-tight'],
|
||||
['tracking-[0em]', 'tracking-normal'],
|
||||
['tracking-[0.025em]', 'tracking-wide'],
|
||||
['tracking-[0.05em]', 'tracking-wider'],
|
||||
['tracking-[0.1em]', 'tracking-widest'],
|
||||
|
||||
// Negative values that don't make sense
|
||||
// See: https://tailwindcss.com/docs/letter-spacing#using-negative-values
|
||||
['-tracking-tighter', 'tracking-wider'],
|
||||
['-tracking-tight', 'tracking-wide'],
|
||||
['-tracking-normal', 'tracking-normal'],
|
||||
['-tracking-wide', 'tracking-tight'],
|
||||
['-tracking-wider', 'tracking-tighter'],
|
||||
])(testName, { timeout }, async (candidate, expected) => {
|
||||
await expectCanonicalization(
|
||||
css`
|
||||
@import 'tailwindcss';
|
||||
@theme {
|
||||
--tracking-tighter: -0.05em;
|
||||
--tracking-tight: -0.025em;
|
||||
--tracking-normal: 0em;
|
||||
--tracking-wide: 0.025em;
|
||||
--tracking-wider: 0.05em;
|
||||
--tracking-widest: 0.1em;
|
||||
}
|
||||
`,
|
||||
candidate,
|
||||
expected,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('theme to var', () => {
|
||||
|
|
@ -1195,84 +1261,120 @@ describe('options', () => {
|
|||
})
|
||||
})
|
||||
|
||||
// https://github.com/schoero/eslint-plugin-better-tailwindcss/issues/321
|
||||
test('a subset of classes should be canonicalizable', { timeout }, async () => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
describe('regressions', () => {
|
||||
// https://github.com/schoero/eslint-plugin-better-tailwindcss/issues/321
|
||||
{
|
||||
test('a subset of classes should be canonicalizable', { timeout }, async () => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
}
|
||||
|
||||
expect(
|
||||
designSystem.canonicalizeCandidates(['underline', 'h-4', 'w-4', 'text-sm'], options),
|
||||
).toEqual(['underline', 'text-sm', 'size-4'])
|
||||
})
|
||||
|
||||
test('collapse canonicalization is not affected by previous calls', { timeout }, async () => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
}
|
||||
|
||||
let target = ['underline', 'h-4', 'w-4']
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(target, options)).toEqual(['underline', 'size-4'])
|
||||
|
||||
designSystem.canonicalizeCandidates(['mb-4', 'text-sm'], options)
|
||||
designSystem.canonicalizeCandidates(['underline', 'mb-4'], options)
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(target, options)).toEqual(['underline', 'size-4'])
|
||||
expect(designSystem.canonicalizeCandidates(target.concat('text-sm'), options)).toEqual([
|
||||
'underline',
|
||||
'text-sm',
|
||||
'size-4',
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
expect(
|
||||
designSystem.canonicalizeCandidates(['underline', 'h-4', 'w-4', 'text-sm'], options),
|
||||
).toEqual(['underline', 'text-sm', 'size-4'])
|
||||
// https://github.com/tailwindlabs/tailwindcss/pull/19727
|
||||
test(
|
||||
'collapse does not crash when utilities with no standard properties are present',
|
||||
{ timeout },
|
||||
async () => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
}
|
||||
|
||||
// Shadow utilities use CSS custom properties and @property rules but may
|
||||
// produce empty property maps in the collapse algorithm. This should not
|
||||
// crash with "Cannot read properties of null" or "X is not iterable".
|
||||
expect(() =>
|
||||
designSystem.canonicalizeCandidates(['shadow-sm', 'border'], options),
|
||||
).not.toThrow()
|
||||
|
||||
expect(() => designSystem.canonicalizeCandidates(['shadow-md', 'p-4'], options)).not.toThrow()
|
||||
|
||||
expect(() =>
|
||||
designSystem.canonicalizeCandidates(['shadow-sm', 'shadow-md'], options),
|
||||
).not.toThrow()
|
||||
|
||||
// Verify the candidates are returned (not collapsed, since shadows can't
|
||||
// meaningfully collapse with unrelated utilities)
|
||||
expect(designSystem.canonicalizeCandidates(['shadow-sm', 'border'], options)).toEqual(
|
||||
expect.arrayContaining(['shadow-sm', 'border']),
|
||||
)
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(['shadow-sm', 'shadow-md'], options)).toEqual(
|
||||
expect.arrayContaining(['shadow-sm', 'shadow-md']),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/19835
|
||||
test.each([
|
||||
// Arbitrary values should be collapsed to another arbitrary value
|
||||
[
|
||||
['px-[1.2rem]', 'py-[1.2rem]', 'text-left'],
|
||||
['text-left', 'p-[1.2rem]'],
|
||||
],
|
||||
|
||||
// Arbitrary values could also be collapsed into a bare value
|
||||
[
|
||||
['px-[30.75rem]', 'py-[30.75rem]', 'text-left'],
|
||||
['text-left', 'p-123'],
|
||||
],
|
||||
])(
|
||||
'collapse canonicalization works for arbitrary values',
|
||||
{ timeout },
|
||||
async (candidates, expected) => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
}
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(candidates, options)).toEqual(expected)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('collapse canonicalization is not affected by previous calls', { timeout }, async () => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
}
|
||||
|
||||
let target = ['underline', 'h-4', 'w-4']
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(target, options)).toEqual(['underline', 'size-4'])
|
||||
|
||||
designSystem.canonicalizeCandidates(['mb-4', 'text-sm'], options)
|
||||
designSystem.canonicalizeCandidates(['underline', 'mb-4'], options)
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(target, options)).toEqual(['underline', 'size-4'])
|
||||
expect(designSystem.canonicalizeCandidates(target.concat('text-sm'), options)).toEqual([
|
||||
'underline',
|
||||
'text-sm',
|
||||
'size-4',
|
||||
])
|
||||
})
|
||||
|
||||
test(
|
||||
'collapse does not crash when utilities with no standard properties are present',
|
||||
{ timeout },
|
||||
async () => {
|
||||
let designSystem = await designSystems.get(__dirname).get(css`
|
||||
@import 'tailwindcss';
|
||||
`)
|
||||
|
||||
let options: CanonicalizeOptions = {
|
||||
collapse: true,
|
||||
logicalToPhysical: true,
|
||||
rem: 16,
|
||||
}
|
||||
|
||||
// Shadow utilities use CSS custom properties and @property rules but may
|
||||
// produce empty property maps in the collapse algorithm. This should not
|
||||
// crash with "Cannot read properties of null" or "X is not iterable".
|
||||
expect(() =>
|
||||
designSystem.canonicalizeCandidates(['shadow-sm', 'border'], options),
|
||||
).not.toThrow()
|
||||
|
||||
expect(() => designSystem.canonicalizeCandidates(['shadow-md', 'p-4'], options)).not.toThrow()
|
||||
|
||||
expect(() =>
|
||||
designSystem.canonicalizeCandidates(['shadow-sm', 'shadow-md'], options),
|
||||
).not.toThrow()
|
||||
|
||||
// Verify the candidates are returned (not collapsed, since shadows can't
|
||||
// meaningfully collapse with unrelated utilities)
|
||||
expect(designSystem.canonicalizeCandidates(['shadow-sm', 'border'], options)).toEqual(
|
||||
expect.arrayContaining(['shadow-sm', 'border']),
|
||||
)
|
||||
|
||||
expect(designSystem.canonicalizeCandidates(['shadow-sm', 'shadow-md'], options)).toEqual(
|
||||
expect.arrayContaining(['shadow-sm', 'shadow-md']),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ import {
|
|||
type NamedUtilityValue,
|
||||
type Variant,
|
||||
} from './candidate'
|
||||
import { canonicalizeCalcExpressionsAst } from './canonicalize-calc-expressions'
|
||||
import { keyPathToCssProperty } from './compat/apply-config-to-theme'
|
||||
import { constantFoldDeclaration } from './constant-fold-declaration'
|
||||
import { constantFoldDeclaration, constantFoldDeclarationAst } from './constant-fold-declaration'
|
||||
import type { DesignSystem as BaseDesignSystem } from './design-system'
|
||||
import { CompileAstFlags } from './design-system'
|
||||
import { expandDeclaration } from './expand-declaration'
|
||||
|
|
@ -77,6 +78,10 @@ interface DesignSystem extends BaseDesignSystem {
|
|||
number | null, // Rem value
|
||||
DefaultMap<SignatureFeatures, SignatureOptions>
|
||||
>
|
||||
[COMPARE_CANDIDATES_KEY]: DefaultMap<
|
||||
SignatureOptions,
|
||||
(a: Candidate | string, b: Candidate | string) => boolean
|
||||
>
|
||||
[INTERNAL_OPTIONS_KEY]: DefaultMap<
|
||||
SignatureOptions,
|
||||
DefaultMap<Features, InternalCanonicalizeOptions>
|
||||
|
|
@ -126,6 +131,7 @@ export function prepareDesignSystemStorage(
|
|||
designSystem.storage[PRE_COMPUTED_UTILITIES_KEY] ??= createPreComputedUtilitiesCache(designSystem)
|
||||
designSystem.storage[VARIANT_SIGNATURE_KEY] ??= createVariantSignatureCache(designSystem)
|
||||
designSystem.storage[PRE_COMPUTED_VARIANTS_KEY] ??= createPreComputedVariantsCache(designSystem)
|
||||
designSystem.storage[COMPARE_CANDIDATES_KEY] ??= createSignatureComparison(designSystem)
|
||||
|
||||
return designSystem
|
||||
}
|
||||
|
|
@ -139,6 +145,25 @@ function createSignatureOptionsCache(): DesignSystem['storage'][typeof SIGNATURE
|
|||
})
|
||||
}
|
||||
|
||||
const COMPARE_CANDIDATES_KEY = Symbol()
|
||||
function createSignatureComparison(designSystem: DesignSystem) {
|
||||
return new DefaultMap((options: SignatureOptions) => {
|
||||
let signatures = designSystem.storage[UTILITY_SIGNATURE_KEY].get(options)
|
||||
|
||||
return function hasSameSignature(a: Candidate | string, b: Candidate | string): boolean {
|
||||
let aCandidateString = typeof a === 'string' ? a : designSystem.printCandidate(a)
|
||||
let aSignature = signatures.get(aCandidateString)
|
||||
if (typeof aSignature !== 'string') return false
|
||||
|
||||
let bCandidateString = typeof b === 'string' ? b : designSystem.printCandidate(b)
|
||||
let bSignature = signatures.get(bCandidateString)
|
||||
if (typeof bSignature !== 'string') return false
|
||||
|
||||
return aSignature === bSignature
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function createSignatureOptions(
|
||||
baseDesignSystem: BaseDesignSystem,
|
||||
options?: CanonicalizeOptions,
|
||||
|
|
@ -198,7 +223,6 @@ export function canonicalizeCandidates(
|
|||
}
|
||||
|
||||
function collapseCandidates(options: InternalCanonicalizeOptions, candidates: string[]): string[] {
|
||||
if (candidates.length <= 1) return candidates
|
||||
let designSystem = options.designSystem
|
||||
|
||||
// To keep things simple, we group candidates such that we only collapse
|
||||
|
|
@ -321,10 +345,7 @@ function collapseCandidates(options: InternalCanonicalizeOptions, candidates: st
|
|||
if (relevantProperties.size === 0) return result
|
||||
|
||||
for (let parsedCandidate of parseCandidate(designSystem, candidate)) {
|
||||
if (
|
||||
parsedCandidate.kind !== 'functional' ||
|
||||
parsedCandidate.value?.kind !== 'named' // Necessary for bare values
|
||||
) {
|
||||
if (parsedCandidate.kind !== 'functional' || parsedCandidate.value === null) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -578,6 +599,7 @@ const UTILITY_CANONICALIZATIONS: UtilityCanonicalizationFunction[] = [
|
|||
bgGradientToLinear,
|
||||
themeToVarUtility,
|
||||
calcToSpacingFunction,
|
||||
optimizeArbitraryValueExpressions,
|
||||
arbitraryUtilities,
|
||||
bareValueUtilities,
|
||||
deprecatedUtilities,
|
||||
|
|
@ -1096,6 +1118,7 @@ function arbitraryUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
let designSystem = options.designSystem
|
||||
let utilities = designSystem.storage[PRE_COMPUTED_UTILITIES_KEY].get(options.signatureOptions)
|
||||
let signatures = designSystem.storage[UTILITY_SIGNATURE_KEY].get(options.signatureOptions)
|
||||
let hasSameSignature = designSystem.storage[COMPARE_CANDIDATES_KEY].get(options.signatureOptions)
|
||||
|
||||
let targetCandidateString = designSystem.printCandidate(candidate)
|
||||
|
||||
|
|
@ -1105,9 +1128,7 @@ function arbitraryUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
|
||||
// Try a few options to find a suitable replacement utility
|
||||
for (let replacementCandidate of tryReplacements(targetSignature, candidate)) {
|
||||
let replacementString = designSystem.printCandidate(replacementCandidate)
|
||||
let replacementSignature = signatures.get(replacementString)
|
||||
if (replacementSignature !== targetSignature) {
|
||||
if (!hasSameSignature(candidate, replacementCandidate)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -1128,11 +1149,29 @@ function arbitraryUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
// Find a corresponding utility for the same signature
|
||||
let replacements = utilities.get(targetSignature)
|
||||
|
||||
// Multiple utilities can map to the same signature. Not sure how to migrate
|
||||
// this one so let's just skip it for now.
|
||||
//
|
||||
// TODO: Do we just migrate to the first one?
|
||||
if (replacements.length > 1) return
|
||||
// Multiple utilities can map to the same signature.
|
||||
if (replacements.length > 1) {
|
||||
// Prefer positive values over negative values
|
||||
let maybeReplacement: string | undefined = undefined
|
||||
for (let replacement of replacements) {
|
||||
if (replacement[0] === '-') continue // Skip negative values
|
||||
|
||||
// If multiple non-negative replacements exists then we are unsure
|
||||
// what to do, so let's bail.
|
||||
if (maybeReplacement) return
|
||||
|
||||
// Consider this replacement
|
||||
maybeReplacement = replacement
|
||||
}
|
||||
|
||||
if (maybeReplacement) {
|
||||
for (let replacementCandidate of parseCandidate(designSystem, maybeReplacement)) {
|
||||
yield replacementCandidate
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// If we didn't find any replacement utilities, let's try to strip the
|
||||
// modifier and find a replacement then. If we do, we can try to re-add the
|
||||
|
|
@ -1326,6 +1365,7 @@ function bareValueUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
let designSystem = options.designSystem
|
||||
let utilities = designSystem.storage[PRE_COMPUTED_UTILITIES_KEY].get(options.signatureOptions)
|
||||
let signatures = designSystem.storage[UTILITY_SIGNATURE_KEY].get(options.signatureOptions)
|
||||
let hasSameSignature = designSystem.storage[COMPARE_CANDIDATES_KEY].get(options.signatureOptions)
|
||||
|
||||
let targetCandidateString = designSystem.printCandidate(candidate)
|
||||
|
||||
|
|
@ -1335,9 +1375,7 @@ function bareValueUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
|
||||
// Try a few options to find a suitable replacement utility
|
||||
for (let replacementCandidate of tryReplacements(targetSignature, candidate)) {
|
||||
let replacementString = designSystem.printCandidate(replacementCandidate)
|
||||
let replacementSignature = signatures.get(replacementString)
|
||||
if (replacementSignature !== targetSignature) {
|
||||
if (!hasSameSignature(candidate, replacementCandidate)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -1353,11 +1391,29 @@ function bareValueUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
// Find a corresponding utility for the same signature
|
||||
let replacements = utilities.get(targetSignature)
|
||||
|
||||
// Multiple utilities can map to the same signature. Not sure how to migrate
|
||||
// this one so let's just skip it for now.
|
||||
//
|
||||
// TODO: Do we just migrate to the first one?
|
||||
if (replacements.length > 1) return
|
||||
// Multiple utilities can map to the same signature.
|
||||
if (replacements.length > 1) {
|
||||
// Prefer positive values over negative values
|
||||
let maybeReplacement: string | undefined = undefined
|
||||
for (let replacement of replacements) {
|
||||
if (replacement[0] === '-') continue // Skip negative values
|
||||
|
||||
// If multiple non-negative replacements exists then we are unsure
|
||||
// what to do, so let's bail.
|
||||
if (maybeReplacement) return
|
||||
|
||||
// Consider this replacement
|
||||
maybeReplacement = replacement
|
||||
}
|
||||
|
||||
if (maybeReplacement) {
|
||||
for (let replacementCandidate of parseCandidate(designSystem, maybeReplacement)) {
|
||||
yield replacementCandidate
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// If we didn't find any replacement utilities, let's try to strip the
|
||||
// modifier and find a replacement then. If we do, we can try to re-add the
|
||||
|
|
@ -1395,31 +1451,47 @@ function bareValueUtilities(candidate: Candidate, options: InternalCanonicalizeO
|
|||
const DEPRECATION_MAP = new Map([
|
||||
['order-none', 'order-0'],
|
||||
['break-words', 'wrap-break-word'],
|
||||
['overflow-ellipsis', 'text-ellipsis'],
|
||||
])
|
||||
|
||||
const DEPRECATION_TRANSFORMATION_MAP = new Map([
|
||||
[/^(-)?start-(.*?)$/, '$1inset-s-$2'],
|
||||
[/^(-)?end-(.*?)$/, '$1inset-e-$2'],
|
||||
])
|
||||
|
||||
function* tryDeprecatedUtilities(candidate: string) {
|
||||
// Try static replacements
|
||||
let replacement = DEPRECATION_MAP.get(candidate)
|
||||
if (replacement) yield replacement
|
||||
|
||||
// Try dynamic replacements
|
||||
for (let [searchValue, replaceValue] of DEPRECATION_TRANSFORMATION_MAP) {
|
||||
let replacement = candidate.replace(searchValue, replaceValue)
|
||||
if (replacement === candidate) continue
|
||||
|
||||
yield replacement
|
||||
}
|
||||
}
|
||||
|
||||
function deprecatedUtilities(
|
||||
candidate: Candidate,
|
||||
options: InternalCanonicalizeOptions,
|
||||
): Candidate {
|
||||
let designSystem = options.designSystem
|
||||
let signatures = designSystem.storage[UTILITY_SIGNATURE_KEY].get(options.signatureOptions)
|
||||
let hasSameSignature = designSystem.storage[COMPARE_CANDIDATES_KEY].get(options.signatureOptions)
|
||||
|
||||
let targetCandidateString = printUnprefixedCandidate(designSystem, candidate)
|
||||
|
||||
let replacementString = DEPRECATION_MAP.get(targetCandidateString) ?? null
|
||||
if (replacementString === null) return candidate
|
||||
for (let replacementString of tryDeprecatedUtilities(targetCandidateString)) {
|
||||
if (!hasSameSignature(candidate, replacementString)) {
|
||||
continue
|
||||
}
|
||||
|
||||
let legacySignature = signatures.get(targetCandidateString)
|
||||
if (typeof legacySignature !== 'string') return candidate
|
||||
let [replacement] = parseCandidate(designSystem, replacementString)
|
||||
return replacement
|
||||
}
|
||||
|
||||
let replacementSignature = signatures.get(replacementString)
|
||||
if (typeof replacementSignature !== 'string') return candidate
|
||||
|
||||
// Not the same signature, not safe to migrate
|
||||
if (legacySignature !== replacementSignature) return candidate
|
||||
|
||||
let [replacement] = parseCandidate(designSystem, replacementString)
|
||||
return replacement
|
||||
return candidate
|
||||
}
|
||||
|
||||
// ----
|
||||
|
|
@ -2028,6 +2100,95 @@ function modernizeArbitraryValuesVariant(
|
|||
return result
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
function optimizeArbitraryValueExpressions(
|
||||
candidate: Candidate,
|
||||
options: InternalCanonicalizeOptions,
|
||||
): Candidate {
|
||||
if (candidate.kind !== 'functional' || candidate.value?.kind !== 'arbitrary') {
|
||||
return candidate
|
||||
}
|
||||
|
||||
let designSystem = options.designSystem
|
||||
let hasSameSignature = designSystem.storage[COMPARE_CANDIDATES_KEY].get(options.signatureOptions)
|
||||
|
||||
let valueAst = ValueParser.parse(candidate.value.value)
|
||||
|
||||
// Start by constant folding the value expression, when dealing with `calc(…)`
|
||||
if (valueAst.length === 1 && valueAst[0].kind === 'function' && valueAst[0].value === 'calc') {
|
||||
let [folded, foldedValueAst] = constantFoldDeclarationAst(valueAst)
|
||||
if (folded) {
|
||||
let replacement = cloneCandidate(candidate)
|
||||
replacement.value!.value = ValueParser.toCss(foldedValueAst)
|
||||
|
||||
if (hasSameSignature(candidate, replacement)) {
|
||||
candidate = replacement
|
||||
valueAst = foldedValueAst
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move `-` sign into the arbitrary value itself
|
||||
if (candidate.root[0] === '-') {
|
||||
// We're dealing with a `var(…)`, keep as-is
|
||||
if (valueAst.length === 1 && valueAst[0].kind === 'function' && valueAst[0].value === 'var') {
|
||||
return candidate
|
||||
}
|
||||
|
||||
// Move `* -1` inside, and try to constant fold to see if it's even worth
|
||||
// updating the candidate or not.
|
||||
let expressionAst = ValueParser.parse(`calc(${candidate.value!.value} * -1)`)
|
||||
let [folded, foldedExpressionAst] = constantFoldDeclarationAst(expressionAst)
|
||||
if (folded) {
|
||||
let replacement = cloneCandidate(candidate)
|
||||
|
||||
replacement.root = replacement.root.slice(1) // Drop the leading `-`
|
||||
replacement.value!.value = ValueParser.toCss(foldedExpressionAst)
|
||||
|
||||
if (hasSameSignature(candidate, replacement)) {
|
||||
candidate = replacement
|
||||
valueAst = foldedExpressionAst
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move `-` sign out of the arbitrary value
|
||||
if (valueAst.length === 1 && valueAst[0].kind === 'function' && valueAst[0].value === 'calc') {
|
||||
let calcArgs = valueAst[0].nodes
|
||||
|
||||
// `calc(arg * -1)` or `calc(-1 * arg)`
|
||||
if (
|
||||
calcArgs.length === 5 &&
|
||||
calcArgs[1].kind === 'separator' &&
|
||||
calcArgs[1].value === ' ' &&
|
||||
calcArgs[2].kind === 'word' &&
|
||||
calcArgs[2].value === '*' &&
|
||||
calcArgs[3].kind === 'separator' &&
|
||||
calcArgs[3].value === ' '
|
||||
) {
|
||||
let arg =
|
||||
calcArgs[4].kind === 'word' && calcArgs[4].value === '-1'
|
||||
? calcArgs[0]
|
||||
: calcArgs[0].kind === 'word' && calcArgs[0].value === '-1'
|
||||
? calcArgs[4]
|
||||
: null
|
||||
|
||||
if (arg) {
|
||||
let replacement = cloneCandidate(candidate)
|
||||
replacement.root = `-${candidate.root}`
|
||||
replacement.value!.value = ValueParser.toCss([arg])
|
||||
|
||||
if (hasSameSignature(candidate, replacement)) {
|
||||
candidate = replacement
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return candidate
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
// Optimize the modifier
|
||||
|
|
@ -2221,6 +2382,8 @@ function canonicalizeAst(designSystem: DesignSystem, ast: AstNode[], options: Si
|
|||
node.value = resolveVariablesInValue(node.value, designSystem)
|
||||
}
|
||||
|
||||
let valueAst = ValueParser.parse(node.value)
|
||||
|
||||
// Very basic `calc(…)` constant folding to handle the spacing scale
|
||||
// multiplier:
|
||||
//
|
||||
|
|
@ -2229,7 +2392,17 @@ function canonicalizeAst(designSystem: DesignSystem, ast: AstNode[], options: Si
|
|||
// → `calc(0.25rem * 4)` ← this is the case we will see
|
||||
// after inlining the variable
|
||||
// → `1rem`
|
||||
node.value = constantFoldDeclaration(node.value, rem)
|
||||
let [folded, foldedValueAst] = constantFoldDeclarationAst(valueAst, rem)
|
||||
|
||||
// Normalize `calc(…)` expressions such that arguments that are
|
||||
// associatively equivalent are rendered in the same way.
|
||||
//
|
||||
// `calc(var(--foo) * -1)` === `calc(-1 * var(--foo))`
|
||||
let [normalized, canonicalizedValueAst] = canonicalizeCalcExpressionsAst(foldedValueAst)
|
||||
|
||||
if (folded || normalized) {
|
||||
node.value = ValueParser.toCss(canonicalizedValueAst)
|
||||
}
|
||||
|
||||
// We will normalize the `node.value`, this is the same kind of logic
|
||||
// we use when printing arbitrary values. It will remove unnecessary
|
||||
|
|
|
|||
|
|
@ -24,9 +24,30 @@ it.each([
|
|||
['calc(3rem * 6)', '18rem'],
|
||||
['calc(5rem / 2)', '2.5rem'],
|
||||
|
||||
// Negating with units
|
||||
['calc(2rem * -1)', '-2rem'],
|
||||
['calc(-1 * 2rem)', '-2rem'],
|
||||
|
||||
// Nested partial evaluation
|
||||
['calc(calc(1 + 2) + 2rem)', 'calc(3 + 2rem)'],
|
||||
|
||||
// Nested multiplication with unknown values
|
||||
['calc(2 * calc(3 * var(--foo)))', 'calc(6 * var(--foo))'],
|
||||
['calc(calc(3 * var(--foo)) * 2)', 'calc(6 * var(--foo))'],
|
||||
['calc(2rem * calc(3 * var(--foo)))', 'calc(6rem * var(--foo))'],
|
||||
|
||||
// Nested addition with unknown values
|
||||
['calc(1rem + calc(2rem + var(--foo)))', 'calc(3rem + var(--foo))'],
|
||||
['calc(calc(2rem + var(--foo)) + 1rem)', 'calc(3rem + var(--foo))'],
|
||||
|
||||
// Nested multiplication can collapse away entirely
|
||||
['calc(-1 * calc(-1 * var(--foo)))', 'var(--foo)'],
|
||||
['calc(calc(-1 * var(--foo)) * -1)', 'var(--foo)'],
|
||||
['calc(-1 * calc(var(--foo) * -1))', 'var(--foo)'],
|
||||
['calc(-1 * (-1 * var(--foo)))', 'var(--foo)'],
|
||||
['calc(1 * var(--foo))', 'var(--foo)'],
|
||||
['calc(var(--foo) * 1)', 'var(--foo)'],
|
||||
|
||||
// Evaluation only handles two operands right now, this can change in the future
|
||||
['calc(1 + 2 + 3)', 'calc(1 + 2 + 3)'],
|
||||
])('should constant fold `%s` into `%s`', (input, expected) => {
|
||||
|
|
@ -40,6 +61,7 @@ it.each([
|
|||
['calc(3rem * 3dvw)'],
|
||||
['calc(3rem * 2dvh)'],
|
||||
['calc(5rem / 17px)'],
|
||||
['calc(2rem * calc(3px * var(--foo)))'],
|
||||
])('should not constant fold different units `%s`', (input) => {
|
||||
expect(constantFoldDeclaration(input)).toBe(input)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,10 +6,18 @@ import { walk, WalkAction } from './walk'
|
|||
// Assumption: We already assume that we receive somewhat valid `calc()`
|
||||
// expressions. So we will see `calc(1 + 1)` and not `calc(1+1)`
|
||||
export function constantFoldDeclaration(input: string, rem: number | null = null): string {
|
||||
let folded = false
|
||||
let valueAst = ValueParser.parse(input)
|
||||
let [folded, valueAst] = constantFoldDeclarationAst(ValueParser.parse(input), rem)
|
||||
|
||||
walk(valueAst, {
|
||||
return folded ? ValueParser.toCss(valueAst) : input
|
||||
}
|
||||
|
||||
export function constantFoldDeclarationAst(
|
||||
ast: ValueParser.ValueAstNode[],
|
||||
rem: number | null = null,
|
||||
): [folded: boolean, ast: ValueParser.ValueAstNode[]] {
|
||||
let folded = false
|
||||
|
||||
walk(ast, {
|
||||
exit(valueNode) {
|
||||
// Canonicalize dimensions to their simplest form. This includes:
|
||||
// - Convert `-0`, `+0`, `0.0`, … to `0`
|
||||
|
|
@ -40,10 +48,14 @@ export function constantFoldDeclaration(input: string, rem: number | null = null
|
|||
// { kind: 'word', value: '256' } 4
|
||||
// ]
|
||||
if (valueNode.nodes.length !== 5) return
|
||||
if (valueNode.nodes[2].kind !== 'word') return
|
||||
|
||||
let lhs = dimensions.get(valueNode.nodes[0].value)
|
||||
let lhsNode = valueNode.nodes[0]
|
||||
let operator = valueNode.nodes[2].value
|
||||
let rhs = dimensions.get(valueNode.nodes[4].value)
|
||||
let rhsNode = valueNode.nodes[4]
|
||||
|
||||
let lhs = lhsNode.kind === 'word' ? dimensions.get(lhsNode.value) : null
|
||||
let rhs = rhsNode.kind === 'word' ? dimensions.get(rhsNode.value) : null
|
||||
|
||||
// Nullify entire expression when multiplying by `0`, e.g.: `calc(0 * 100vw)` -> `0`
|
||||
//
|
||||
|
|
@ -57,6 +69,134 @@ export function constantFoldDeclaration(input: string, rem: number | null = null
|
|||
return WalkAction.ReplaceSkip(ValueParser.word('0'))
|
||||
}
|
||||
|
||||
if (operator === '*') {
|
||||
// Multiplying by `1` can always unwrap the other side, even when that
|
||||
// side is an expression like `var(--foo)` that we can't fully fold.
|
||||
if (lhs?.[0] === 1 && lhs?.[1] === null) {
|
||||
folded = true
|
||||
return WalkAction.ReplaceSkip(rhsNode)
|
||||
}
|
||||
|
||||
if (rhs?.[0] === 1 && rhs?.[1] === null) {
|
||||
folded = true
|
||||
return WalkAction.ReplaceSkip(lhsNode)
|
||||
}
|
||||
}
|
||||
|
||||
if (operator === '*' || operator === '+') {
|
||||
// If only one side is known, and the unknown side is itself another
|
||||
// binary expression with the same operator, try to combine the two
|
||||
// known parts and keep the unknown part in place.
|
||||
//
|
||||
// E.g.:
|
||||
//
|
||||
// - `calc(2rem * calc(3 * var(--foo)))` → `calc(6rem * var(--foo))`
|
||||
// - `calc(2rem + calc(3rem + var(--foo)))` → `calc(5rem + var(--foo))`
|
||||
//
|
||||
// At this point `lhs` and `rhs` are dimensions ([value, unit] |
|
||||
// null). The `null` one is the unknown node.
|
||||
let constant = lhs ?? rhs
|
||||
let nestedNode = lhs === null ? lhsNode : rhs === null ? rhsNode : null
|
||||
|
||||
if (
|
||||
constant !== null &&
|
||||
nestedNode !== null &&
|
||||
nestedNode.kind === 'function' &&
|
||||
(nestedNode.value === 'calc' || nestedNode.value === '') &&
|
||||
nestedNode.nodes.length === 5 &&
|
||||
nestedNode.nodes[2].kind === 'word' &&
|
||||
nestedNode.nodes[2].value === operator
|
||||
) {
|
||||
let nestedLhsNode = nestedNode.nodes[0]
|
||||
let nestedRhsNode = nestedNode.nodes[4]
|
||||
let nestedLhs =
|
||||
nestedLhsNode.kind === 'word' ? dimensions.get(nestedLhsNode.value) : null
|
||||
let nestedRhs =
|
||||
nestedRhsNode.kind === 'word' ? dimensions.get(nestedRhsNode.value) : null
|
||||
|
||||
let known = nestedLhs ?? nestedRhs
|
||||
let unknown =
|
||||
nestedLhs === null ? nestedLhsNode : nestedRhs === null ? nestedRhsNode : null
|
||||
|
||||
if (known !== null && unknown !== null) {
|
||||
// `*` requires both values being unitless, or one of them. Both
|
||||
// values having a unit is invalid.
|
||||
//
|
||||
// - `2 * 3` → valid
|
||||
// - `4rem * 5` → valid
|
||||
// - `6 * 7rem` → valid
|
||||
// - `8rem * 9rem` → invalid
|
||||
if (
|
||||
operator === '*' &&
|
||||
!(
|
||||
(constant[1] === null && known[1] === null) || // Both can be unitless
|
||||
(constant[1] === null && known[1] !== null) || // One of them can be unitless, but the other can't
|
||||
(constant[1] !== null && known[1] === null) // One of them can be unitless, but the other can't
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// `+` requires that the units are the same. Adding a unitless
|
||||
// value to a value with a unit is not allowed.
|
||||
//
|
||||
// - `2 + 3` → valid
|
||||
// - `4rem + 5` → invalid
|
||||
// - `6 + 7rem` → invalid
|
||||
// - `8rem + 9rem` → valid
|
||||
if (
|
||||
operator === '+' &&
|
||||
!(
|
||||
(constant[1] === known[1]) // Only same unit is allowed
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Re-associate nested expressions so we can still fold the known
|
||||
// part of `x op (y op z)` when `z` is unknown.
|
||||
//
|
||||
// Examples:
|
||||
// - `calc(2 * calc(3 * var(--foo)))` -> `calc(6 * var(--foo))`
|
||||
// - `calc(1rem + calc(2rem + var(--foo)))` -> `calc(3rem + var(--foo))`
|
||||
let combined: string
|
||||
switch (operator) {
|
||||
case '*': {
|
||||
combined = `${constant[0] * known[0]}${constant[1] ?? known[1] ?? ''}`
|
||||
break
|
||||
}
|
||||
case '+': {
|
||||
combined = `${constant[0] + known[0]}${constant[1] ?? known[1] ?? ''}`
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
folded = true
|
||||
|
||||
if (operator === '*' && combined === '1') {
|
||||
return WalkAction.ReplaceSkip(unknown)
|
||||
}
|
||||
|
||||
let replacement: ValueParser.ValueFunctionNode = {
|
||||
kind: 'function',
|
||||
value: valueNode.value,
|
||||
nodes: [
|
||||
ValueParser.word(combined),
|
||||
valueNode.nodes[1],
|
||||
valueNode.nodes[2],
|
||||
valueNode.nodes[3],
|
||||
unknown,
|
||||
],
|
||||
}
|
||||
|
||||
return WalkAction.ReplaceSkip(replacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We're not dealing with dimensions, so we can't fold this
|
||||
if (lhs === null || rhs === null) {
|
||||
return
|
||||
|
|
@ -70,7 +210,9 @@ export function constantFoldDeclaration(input: string, rem: number | null = null
|
|||
(lhs[1] !== null && rhs[1] === null) // Unit * Unitless, e.g.: `1rem * 2`
|
||||
) {
|
||||
folded = true
|
||||
return WalkAction.ReplaceSkip(ValueParser.word(`${lhs[0] * rhs[0]}${lhs[1] ?? ''}`))
|
||||
return WalkAction.ReplaceSkip(
|
||||
ValueParser.word(`${lhs[0] * rhs[0]}${lhs[1] ?? rhs[1] ?? ''}`),
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
@ -111,7 +253,7 @@ export function constantFoldDeclaration(input: string, rem: number | null = null
|
|||
},
|
||||
})
|
||||
|
||||
return folded ? ValueParser.toCss(valueAst) : input
|
||||
return [folded, ast]
|
||||
}
|
||||
|
||||
function canonicalizeDimension(input: string, rem: number | null = null): string | null {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function expand(input: string, options: SignatureFeatures): string {
|
|||
describe('expand declarations', () => {
|
||||
let options = SignatureFeatures.ExpandProperties
|
||||
|
||||
test('expand to 4 properties', () => {
|
||||
test('inset', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
inset: 10px;
|
||||
|
|
@ -71,7 +71,7 @@ describe('expand declarations', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
test('expand to 2 properties', () => {
|
||||
test('gap', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
gap: 10px;
|
||||
|
|
@ -95,6 +95,294 @@ describe('expand declarations', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
test('border-width', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.two {
|
||||
border-width: 1px 2px;
|
||||
}
|
||||
|
||||
.three {
|
||||
border-width: 1px 2px 3px;
|
||||
}
|
||||
|
||||
.four {
|
||||
border-width: 1px 2px 3px 4px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
}
|
||||
.two {
|
||||
border-top-width: 1px;
|
||||
border-right-width: 2px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 2px;
|
||||
}
|
||||
.three {
|
||||
border-top-width: 1px;
|
||||
border-right-width: 2px;
|
||||
border-bottom-width: 3px;
|
||||
border-left-width: 2px;
|
||||
}
|
||||
.four {
|
||||
border-top-width: 1px;
|
||||
border-right-width: 2px;
|
||||
border-bottom-width: 3px;
|
||||
border-left-width: 4px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('border-style', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.two {
|
||||
border-style: solid dashed;
|
||||
}
|
||||
|
||||
.three {
|
||||
border-style: solid dashed dotted;
|
||||
}
|
||||
|
||||
.four {
|
||||
border-style: solid dashed dotted double;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
border-top-style: solid;
|
||||
border-right-style: solid;
|
||||
border-bottom-style: solid;
|
||||
border-left-style: solid;
|
||||
}
|
||||
.two {
|
||||
border-top-style: solid;
|
||||
border-right-style: dashed;
|
||||
border-bottom-style: solid;
|
||||
border-left-style: dashed;
|
||||
}
|
||||
.three {
|
||||
border-top-style: solid;
|
||||
border-right-style: dashed;
|
||||
border-bottom-style: dotted;
|
||||
border-left-style: dashed;
|
||||
}
|
||||
.four {
|
||||
border-top-style: solid;
|
||||
border-right-style: dashed;
|
||||
border-bottom-style: dotted;
|
||||
border-left-style: double;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('border-color', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.two {
|
||||
border-color: red green;
|
||||
}
|
||||
|
||||
.three {
|
||||
border-color: red green blue;
|
||||
}
|
||||
|
||||
.four {
|
||||
border-color: red green blue black;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
border-top-color: red;
|
||||
border-right-color: red;
|
||||
border-bottom-color: red;
|
||||
border-left-color: red;
|
||||
}
|
||||
.two {
|
||||
border-top-color: red;
|
||||
border-right-color: green;
|
||||
border-bottom-color: red;
|
||||
border-left-color: green;
|
||||
}
|
||||
.three {
|
||||
border-top-color: red;
|
||||
border-right-color: green;
|
||||
border-bottom-color: blue;
|
||||
border-left-color: green;
|
||||
}
|
||||
.four {
|
||||
border-top-color: red;
|
||||
border-right-color: green;
|
||||
border-bottom-color: blue;
|
||||
border-left-color: black;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('scroll-margin', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
scroll-margin: 1px;
|
||||
}
|
||||
|
||||
.two {
|
||||
scroll-margin: 1px 2px;
|
||||
}
|
||||
|
||||
.three {
|
||||
scroll-margin: 1px 2px 3px;
|
||||
}
|
||||
|
||||
.four {
|
||||
scroll-margin: 1px 2px 3px 4px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
scroll-margin-top: 1px;
|
||||
scroll-margin-right: 1px;
|
||||
scroll-margin-bottom: 1px;
|
||||
scroll-margin-left: 1px;
|
||||
}
|
||||
.two {
|
||||
scroll-margin-top: 1px;
|
||||
scroll-margin-right: 2px;
|
||||
scroll-margin-bottom: 1px;
|
||||
scroll-margin-left: 2px;
|
||||
}
|
||||
.three {
|
||||
scroll-margin-top: 1px;
|
||||
scroll-margin-right: 2px;
|
||||
scroll-margin-bottom: 3px;
|
||||
scroll-margin-left: 2px;
|
||||
}
|
||||
.four {
|
||||
scroll-margin-top: 1px;
|
||||
scroll-margin-right: 2px;
|
||||
scroll-margin-bottom: 3px;
|
||||
scroll-margin-left: 4px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('scroll-padding', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
scroll-padding: 1px;
|
||||
}
|
||||
|
||||
.two {
|
||||
scroll-padding: 1px 2px;
|
||||
}
|
||||
|
||||
.three {
|
||||
scroll-padding: 1px 2px 3px;
|
||||
}
|
||||
|
||||
.four {
|
||||
scroll-padding: 1px 2px 3px 4px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
scroll-padding-top: 1px;
|
||||
scroll-padding-right: 1px;
|
||||
scroll-padding-bottom: 1px;
|
||||
scroll-padding-left: 1px;
|
||||
}
|
||||
.two {
|
||||
scroll-padding-top: 1px;
|
||||
scroll-padding-right: 2px;
|
||||
scroll-padding-bottom: 1px;
|
||||
scroll-padding-left: 2px;
|
||||
}
|
||||
.three {
|
||||
scroll-padding-top: 1px;
|
||||
scroll-padding-right: 2px;
|
||||
scroll-padding-bottom: 3px;
|
||||
scroll-padding-left: 2px;
|
||||
}
|
||||
.four {
|
||||
scroll-padding-top: 1px;
|
||||
scroll-padding-right: 2px;
|
||||
scroll-padding-bottom: 3px;
|
||||
scroll-padding-left: 4px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('overflow', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
.two {
|
||||
overflow: hidden visible;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
overflow-x: clip;
|
||||
overflow-y: clip;
|
||||
}
|
||||
.two {
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('overscroll-behavior', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.two {
|
||||
overscroll-behavior: auto contain;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".one {
|
||||
overscroll-behavior-x: none;
|
||||
overscroll-behavior-y: none;
|
||||
}
|
||||
.two {
|
||||
overscroll-behavior-x: auto;
|
||||
overscroll-behavior-y: contain;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('expansion with `!important`', () => {
|
||||
let input = css`
|
||||
.one {
|
||||
|
|
@ -147,6 +435,22 @@ describe('expand declarations', () => {
|
|||
describe('expand logical properties', () => {
|
||||
let options = SignatureFeatures.ExpandProperties | SignatureFeatures.LogicalToPhysical
|
||||
|
||||
test('margin-inline', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
margin-inline: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
margin-left: 10px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('margin-block', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
|
|
@ -162,4 +466,164 @@ describe('expand logical properties', () => {
|
|||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('padding-inline', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
padding-inline: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
padding-left: 10px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('padding-block', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
padding-block: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('scroll-margin-inline', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
scroll-margin-inline: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
scroll-margin-left: 10px;
|
||||
scroll-margin-right: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('scroll-margin-block', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
scroll-margin-block: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
scroll-margin-top: 10px;
|
||||
scroll-margin-bottom: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('scroll-padding-inline', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
scroll-padding-inline: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
scroll-padding-left: 10px;
|
||||
scroll-padding-right: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('scroll-padding-block', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
scroll-padding-block: 10px 20px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
scroll-padding-top: 10px;
|
||||
scroll-padding-bottom: 20px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('border-inline-width', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
border-inline-width: 1px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('border-block-width', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
border-block-width: 1px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
border-bottom-width: 1px;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('border-inline-style', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
border-inline-style: 1px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
border-left-style: 1px;
|
||||
border-right-style: 1px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('border-block-style', () => {
|
||||
let input = css`
|
||||
.example {
|
||||
border-block-style: 1px;
|
||||
}
|
||||
`
|
||||
|
||||
expect(expand(input, options)).toMatchInlineSnapshot(`
|
||||
".example {
|
||||
border-bottom-style: 1px;
|
||||
border-top-style: 1px;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -35,7 +35,32 @@ let VARIADIC_EXPANSION_MAP: Record<string, Record<number, [prop: string, index:
|
|||
inset: createBareQuad(),
|
||||
margin: createPrefixedQuad('margin'),
|
||||
padding: createPrefixedQuad('padding'),
|
||||
'scroll-margin': createPrefixedQuad('scroll-margin'),
|
||||
'scroll-padding': createPrefixedQuad('scroll-padding'),
|
||||
'border-width': createPrefixedQuad(
|
||||
'border',
|
||||
'top-width',
|
||||
'right-width',
|
||||
'bottom-width',
|
||||
'left-width',
|
||||
),
|
||||
'border-style': createPrefixedQuad(
|
||||
'border',
|
||||
'top-style',
|
||||
'right-style',
|
||||
'bottom-style',
|
||||
'left-style',
|
||||
),
|
||||
'border-color': createPrefixedQuad(
|
||||
'border',
|
||||
'top-color',
|
||||
'right-color',
|
||||
'bottom-color',
|
||||
'left-color',
|
||||
),
|
||||
gap: createPair('row-gap', 'column-gap'),
|
||||
overflow: createPair('overflow-x', 'overflow-y'),
|
||||
'overscroll-behavior': createPair('overscroll-behavior-x', 'overscroll-behavior-y'),
|
||||
}
|
||||
|
||||
// Depending on the length of the value, map to different properties
|
||||
|
|
@ -49,6 +74,10 @@ let VARIADIC_LOGICAL_EXPANSION_MAP: Record<
|
|||
'margin-inline': createPair('margin-left', 'margin-right'),
|
||||
'padding-block': createPair('padding-top', 'padding-bottom'),
|
||||
'padding-inline': createPair('padding-left', 'padding-right'),
|
||||
'scroll-margin-block': createPair('scroll-margin-top', 'scroll-margin-bottom'),
|
||||
'scroll-margin-inline': createPair('scroll-margin-left', 'scroll-margin-right'),
|
||||
'scroll-padding-block': createPair('scroll-padding-top', 'scroll-padding-bottom'),
|
||||
'scroll-padding-inline': createPair('scroll-padding-left', 'scroll-padding-right'),
|
||||
}
|
||||
|
||||
// The entire value is mapped to each property
|
||||
|
|
|
|||
|
|
@ -1501,6 +1501,14 @@ describe('Parsing theme values from CSS', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/19786
|
||||
test('out-of-range escaped CSS variable candidates do not crash the build', async () => {
|
||||
// Shouldn't crash
|
||||
await run([
|
||||
String.raw`--Coding-Projects-CharacterMapper-Master-Workspace\d8819554-4725-4235-9d22-2d0ed572e924`,
|
||||
])
|
||||
})
|
||||
|
||||
test('`@keyframes` in `@theme` are hoisted', async () => {
|
||||
expect(
|
||||
await compileCss(
|
||||
|
|
|
|||
|
|
@ -5776,27 +5776,27 @@ test('rotate-x', async () => {
|
|||
|
||||
.-rotate-x-\\(--var\\) {
|
||||
--tw-rotate-x: rotateX(calc(var(--var) * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.-rotate-x-45 {
|
||||
--tw-rotate-x: rotateX(calc(45deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-x-\\(--var\\) {
|
||||
--tw-rotate-x: rotateX(var(--var));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-x-45 {
|
||||
--tw-rotate-x: rotateX(45deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-x-\\[123deg\\] {
|
||||
--tw-rotate-x: rotateX(123deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
@property --tw-rotate-x {
|
||||
|
|
@ -5862,32 +5862,32 @@ test('rotate-y', async () => {
|
|||
|
||||
.-rotate-y-\\(--var\\) {
|
||||
--tw-rotate-y: rotateY(calc(var(--var) * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.-rotate-y-45 {
|
||||
--tw-rotate-y: rotateY(calc(45deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.-rotate-y-\\[123deg\\] {
|
||||
--tw-rotate-y: rotateY(calc(123deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-y-\\(--var\\) {
|
||||
--tw-rotate-y: rotateY(var(--var));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-y-45 {
|
||||
--tw-rotate-y: rotateY(45deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-y-\\[123deg\\] {
|
||||
--tw-rotate-y: rotateY(123deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
@property --tw-rotate-x {
|
||||
|
|
@ -5953,32 +5953,32 @@ test('rotate-z', async () => {
|
|||
|
||||
.-rotate-z-\\(--var\\) {
|
||||
--tw-rotate-z: rotateZ(calc(var(--var) * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.-rotate-z-45 {
|
||||
--tw-rotate-z: rotateZ(calc(45deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.-rotate-z-\\[123deg\\] {
|
||||
--tw-rotate-z: rotateZ(calc(123deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-z-\\(--var\\) {
|
||||
--tw-rotate-z: rotateZ(var(--var));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-z-45 {
|
||||
--tw-rotate-z: rotateZ(45deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.rotate-z-\\[123deg\\] {
|
||||
--tw-rotate-z: rotateZ(123deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
@property --tw-rotate-x {
|
||||
|
|
@ -6036,19 +6036,19 @@ test('skew', async () => {
|
|||
.-skew-6 {
|
||||
--tw-skew-x: skewX(calc(6deg * -1));
|
||||
--tw-skew-y: skewY(calc(6deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.skew-6 {
|
||||
--tw-skew-x: skewX(6deg);
|
||||
--tw-skew-y: skewY(6deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.skew-\\[123deg\\] {
|
||||
--tw-skew-x: skewX(123deg);
|
||||
--tw-skew-y: skewY(123deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
@property --tw-rotate-x {
|
||||
|
|
@ -6104,17 +6104,17 @@ test('skew-x', async () => {
|
|||
|
||||
.-skew-x-6 {
|
||||
--tw-skew-x: skewX(calc(6deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.skew-x-6 {
|
||||
--tw-skew-x: skewX(6deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.skew-x-\\[123deg\\] {
|
||||
--tw-skew-x: skewX(123deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
@property --tw-rotate-x {
|
||||
|
|
@ -6170,17 +6170,17 @@ test('skew-y', async () => {
|
|||
|
||||
.-skew-y-6 {
|
||||
--tw-skew-y: skewY(calc(6deg * -1));
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.skew-y-6 {
|
||||
--tw-skew-y: skewY(6deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.skew-y-\\[123deg\\] {
|
||||
--tw-skew-y: skewY(123deg);
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
@property --tw-rotate-x {
|
||||
|
|
@ -6563,19 +6563,19 @@ test('transform', async () => {
|
|||
}
|
||||
|
||||
.transform {
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.transform-\\[scaleZ\\(2\\)_rotateY\\(45deg\\)\\] {
|
||||
transform: scaleZ(2)rotateY(45deg);
|
||||
transform: scaleZ(2) rotateY(45deg);
|
||||
}
|
||||
|
||||
.transform-cpu {
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.transform-gpu {
|
||||
transform: translateZ(0) var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
transform: translateZ(0) var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
|
||||
}
|
||||
|
||||
.transform-none {
|
||||
|
|
@ -7087,32 +7087,32 @@ test('touch-pan', async () => {
|
|||
|
||||
.touch-pan-left {
|
||||
--tw-pan-x: pan-left;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
.touch-pan-right {
|
||||
--tw-pan-x: pan-right;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
.touch-pan-x {
|
||||
--tw-pan-x: pan-x;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
.touch-pan-down {
|
||||
--tw-pan-y: pan-down;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
.touch-pan-up {
|
||||
--tw-pan-y: pan-up;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
.touch-pan-y {
|
||||
--tw-pan-y: pan-y;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
@property --tw-pan-x {
|
||||
|
|
@ -7162,7 +7162,7 @@ test('touch-pinch-zoom', async () => {
|
|||
|
||||
.touch-pinch-zoom {
|
||||
--tw-pinch-zoom: pinch-zoom;
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
touch-action: var(--tw-pan-x, ) var(--tw-pan-y, ) var(--tw-pinch-zoom, );
|
||||
}
|
||||
|
||||
@property --tw-pan-x {
|
||||
|
|
@ -23050,73 +23050,73 @@ test('filter', async () => {
|
|||
|
||||
.blur-\\[4px\\] {
|
||||
--tw-blur: blur(4px);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.blur-none {
|
||||
--tw-blur: ;
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.blur-xl {
|
||||
--tw-blur: blur(var(--blur-xl));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.brightness-50 {
|
||||
--tw-brightness: brightness(50%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.brightness-\\[1\\.23\\] {
|
||||
--tw-brightness: brightness(1.23);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.contrast-50 {
|
||||
--tw-contrast: contrast(50%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.contrast-\\[1\\.23\\] {
|
||||
--tw-contrast: contrast(1.23);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow\\/25 {
|
||||
--tw-drop-shadow-alpha: 25%;
|
||||
--tw-drop-shadow-size: drop-shadow(0 1px 1px var(--tw-drop-shadow-color, oklab(0% 0 0 / .25)));
|
||||
--tw-drop-shadow: drop-shadow(var(--drop-shadow));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow {
|
||||
--tw-drop-shadow-size: drop-shadow(0 1px 1px var(--tw-drop-shadow-color, #0000000d));
|
||||
--tw-drop-shadow: drop-shadow(var(--drop-shadow));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow-\\[0_0_red\\] {
|
||||
--tw-drop-shadow-size: drop-shadow(0 0 var(--tw-drop-shadow-color, red));
|
||||
--tw-drop-shadow: var(--tw-drop-shadow-size);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow-multi {
|
||||
--tw-drop-shadow-size: drop-shadow(0 1px 1px var(--tw-drop-shadow-color, #0000000d)) drop-shadow(0 9px 7px var(--tw-drop-shadow-color, #0000001a));
|
||||
--tw-drop-shadow: drop-shadow(0 1px 1px #0000000d) drop-shadow(0 9px 7px #0000001a);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow-xl {
|
||||
--tw-drop-shadow-size: drop-shadow(0 9px 7px var(--tw-drop-shadow-color, #0000001a));
|
||||
--tw-drop-shadow: drop-shadow(var(--drop-shadow-xl));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow-none {
|
||||
--tw-drop-shadow: ;
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.drop-shadow-inherit {
|
||||
|
|
@ -23154,91 +23154,91 @@ test('filter', async () => {
|
|||
|
||||
.grayscale {
|
||||
--tw-grayscale: grayscale(100%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.grayscale-0 {
|
||||
--tw-grayscale: grayscale(0%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.grayscale-\\[var\\(--value\\)\\] {
|
||||
--tw-grayscale: grayscale(var(--value));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.-hue-rotate-15 {
|
||||
--tw-hue-rotate: hue-rotate(calc(15deg * -1));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.-hue-rotate-\\[45deg\\] {
|
||||
--tw-hue-rotate: hue-rotate(calc(45deg * -1));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.hue-rotate-15 {
|
||||
--tw-hue-rotate: hue-rotate(15deg);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.hue-rotate-\\[45deg\\] {
|
||||
--tw-hue-rotate: hue-rotate(45deg);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.invert {
|
||||
--tw-invert: invert(100%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.invert-0 {
|
||||
--tw-invert: invert(0%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.invert-\\[var\\(--value\\)\\] {
|
||||
--tw-invert: invert(var(--value));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.saturate-0 {
|
||||
--tw-saturate: saturate(0%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.saturate-\\[1\\.75\\] {
|
||||
--tw-saturate: saturate(1.75);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.saturate-\\[var\\(--value\\)\\] {
|
||||
--tw-saturate: saturate(var(--value));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.sepia {
|
||||
--tw-sepia: sepia(100%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.sepia-0 {
|
||||
--tw-sepia: sepia(0%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.sepia-\\[50\\%\\] {
|
||||
--tw-sepia: sepia(50%);
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.sepia-\\[var\\(--value\\)\\] {
|
||||
--tw-sepia: sepia(var(--value));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.filter {
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
.filter-\\[var\\(--value\\)\\] {
|
||||
|
|
@ -23431,7 +23431,7 @@ test('filter', async () => {
|
|||
|
||||
.blur-none {
|
||||
--tw-blur: blur(var(--blur-none));
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
||||
}
|
||||
|
||||
@property --tw-blur {
|
||||
|
|
@ -23570,187 +23570,187 @@ test('backdrop-filter', async () => {
|
|||
|
||||
.backdrop-blur-\\[4px\\] {
|
||||
--tw-backdrop-blur: blur(4px);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-blur-none {
|
||||
--tw-backdrop-blur: ;
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-blur-xl {
|
||||
--tw-backdrop-blur: blur(var(--blur-xl));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-brightness-50 {
|
||||
--tw-backdrop-brightness: brightness(50%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-brightness-\\[1\\.23\\] {
|
||||
--tw-backdrop-brightness: brightness(1.23);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-contrast-50 {
|
||||
--tw-backdrop-contrast: contrast(50%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-contrast-\\[1\\.23\\] {
|
||||
--tw-backdrop-contrast: contrast(1.23);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-grayscale {
|
||||
--tw-backdrop-grayscale: grayscale(100%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-grayscale-0 {
|
||||
--tw-backdrop-grayscale: grayscale(0%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-grayscale-\\[var\\(--value\\)\\] {
|
||||
--tw-backdrop-grayscale: grayscale(var(--value));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.-backdrop-hue-rotate-15 {
|
||||
--tw-backdrop-hue-rotate: hue-rotate(calc(15deg * -1));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.-backdrop-hue-rotate-\\[45deg\\] {
|
||||
--tw-backdrop-hue-rotate: hue-rotate(calc(45deg * -1));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-hue-rotate-15 {
|
||||
--tw-backdrop-hue-rotate: hue-rotate(15deg);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-hue-rotate-\\[45deg\\] {
|
||||
--tw-backdrop-hue-rotate: hue-rotate(45deg);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-invert {
|
||||
--tw-backdrop-invert: invert(100%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-invert-0 {
|
||||
--tw-backdrop-invert: invert(0%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-invert-\\[var\\(--value\\)\\] {
|
||||
--tw-backdrop-invert: invert(var(--value));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-opacity-1\\.25 {
|
||||
--tw-backdrop-opacity: opacity(1.25%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-opacity-2\\.5 {
|
||||
--tw-backdrop-opacity: opacity(2.5%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-opacity-3\\.75 {
|
||||
--tw-backdrop-opacity: opacity(3.75%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-opacity-50 {
|
||||
--tw-backdrop-opacity: opacity(50%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-opacity-71 {
|
||||
--tw-backdrop-opacity: opacity(71%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-opacity-\\[0\\.5\\] {
|
||||
--tw-backdrop-opacity: opacity(.5);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-saturate-0 {
|
||||
--tw-backdrop-saturate: saturate(0%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-saturate-\\[1\\.75\\] {
|
||||
--tw-backdrop-saturate: saturate(1.75);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-saturate-\\[var\\(--value\\)\\] {
|
||||
--tw-backdrop-saturate: saturate(var(--value));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-sepia {
|
||||
--tw-backdrop-sepia: sepia(100%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-sepia-0 {
|
||||
--tw-backdrop-sepia: sepia(0%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-sepia-\\[50\\%\\] {
|
||||
--tw-backdrop-sepia: sepia(50%);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-sepia-\\[var\\(--value\\)\\] {
|
||||
--tw-backdrop-sepia: sepia(var(--value));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-filter {
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
.backdrop-filter-\\[var\\(--value\\)\\] {
|
||||
|
|
@ -23914,8 +23914,8 @@ test('backdrop-filter', async () => {
|
|||
|
||||
.backdrop-blur-none {
|
||||
--tw-backdrop-blur: blur(var(--backdrop-blur-none));
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
||||
}
|
||||
|
||||
@property --tw-backdrop-blur {
|
||||
|
|
@ -24382,27 +24382,27 @@ test('contain', async () => {
|
|||
|
||||
.contain-inline-size {
|
||||
--tw-contain-size: inline-size;
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
}
|
||||
|
||||
.contain-layout {
|
||||
--tw-contain-layout: layout;
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
}
|
||||
|
||||
.contain-paint {
|
||||
--tw-contain-paint: paint;
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
}
|
||||
|
||||
.contain-size {
|
||||
--tw-contain-size: size;
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
}
|
||||
|
||||
.contain-style {
|
||||
--tw-contain-style: style;
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
contain: var(--tw-contain-size, ) var(--tw-contain-layout, ) var(--tw-contain-paint, ) var(--tw-contain-style, );
|
||||
}
|
||||
|
||||
.contain-\\[unset\\] {
|
||||
|
|
@ -24730,42 +24730,42 @@ test('font-variant-numeric', async () => {
|
|||
|
||||
.diagonal-fractions {
|
||||
--tw-numeric-fraction: diagonal-fractions;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.lining-nums {
|
||||
--tw-numeric-figure: lining-nums;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.oldstyle-nums {
|
||||
--tw-numeric-figure: oldstyle-nums;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.ordinal {
|
||||
--tw-ordinal: ordinal;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.proportional-nums {
|
||||
--tw-numeric-spacing: proportional-nums;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.slashed-zero {
|
||||
--tw-slashed-zero: slashed-zero;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.stacked-fractions {
|
||||
--tw-numeric-fraction: stacked-fractions;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.tabular-nums {
|
||||
--tw-numeric-spacing: tabular-nums;
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
|
||||
}
|
||||
|
||||
.normal-nums {
|
||||
|
|
@ -27137,37 +27137,37 @@ test('ring', async () => {
|
|||
}
|
||||
|
||||
.ring {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ring-0 {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ring-1 {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ring-2 {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ring-4 {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ring-\\[12px\\] {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(12px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(12px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ring-\\[length\\:var\\(--my-width\\)\\] {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(var(--my-width) + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(var(--my-width) + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
|
|
@ -27461,7 +27461,7 @@ test('ring', async () => {
|
|||
}
|
||||
|
||||
.ring {
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
|
|
@ -28031,32 +28031,32 @@ test('ring-offset', async () => {
|
|||
|
||||
.ring-offset-0 {
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
}
|
||||
|
||||
.ring-offset-1 {
|
||||
--tw-ring-offset-width: 1px;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
}
|
||||
|
||||
.ring-offset-2 {
|
||||
--tw-ring-offset-width: 2px;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
}
|
||||
|
||||
.ring-offset-4 {
|
||||
--tw-ring-offset-width: 4px;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
}
|
||||
|
||||
.ring-offset-\\[12px\\] {
|
||||
--tw-ring-offset-width: 12px;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
}
|
||||
|
||||
.ring-offset-\\[length\\:var\\(--my-width\\)\\] {
|
||||
--tw-ring-offset-width: var(--my-width);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
}
|
||||
|
||||
.ring-offset-\\[\\#0088cc\\] {
|
||||
|
|
|
|||
|
|
@ -3960,7 +3960,7 @@ export function createUtilities(theme: Theme) {
|
|||
])
|
||||
|
||||
colorUtility('placeholder', {
|
||||
themeKeys: ['--background-color', '--color'],
|
||||
themeKeys: ['--placeholder-color', '--color'],
|
||||
handle: (value) => [
|
||||
styleRule('&::placeholder', [decl('--tw-sort', 'placeholder-color'), decl('color', value)]),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -11,4 +11,14 @@ describe('unescape', () => {
|
|||
test('removes backslashes', () => {
|
||||
expect(unescape(String.raw`red-1\/2`)).toMatchInlineSnapshot(`"red-1/2"`)
|
||||
})
|
||||
|
||||
test('replaces out-of-range escaped code points', () => {
|
||||
expect(
|
||||
unescape(
|
||||
String.raw`--Coding-Projects-CharacterMapper-Master-Workspace\d8819554-4725-4235-9d22-2d0ed572e924`,
|
||||
),
|
||||
).toMatchInlineSnapshot(
|
||||
`"--Coding-Projects-CharacterMapper-Master-Workspace<63>54-4725-4235-9d22-2d0ed572e924"`,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -74,8 +74,24 @@ export function escape(value: string) {
|
|||
|
||||
export function unescape(escaped: string) {
|
||||
return escaped.replace(/\\([\dA-Fa-f]{1,6}[\t\n\f\r ]?|[\S\s])/g, (match) => {
|
||||
return match.length > 2
|
||||
? String.fromCodePoint(Number.parseInt(match.slice(1).trim(), 16))
|
||||
: match[1]
|
||||
if (match.length <= 2) {
|
||||
return match[1]
|
||||
}
|
||||
|
||||
let codePoint = Number.parseInt(match.slice(1).trim(), 16)
|
||||
|
||||
if (
|
||||
// Invalid codepoint: https://infra.spec.whatwg.org/#code-point
|
||||
codePoint === 0x0000 ||
|
||||
codePoint > 0x10ffff ||
|
||||
// Is surrogate: https://infra.spec.whatwg.org/#leading-surrogate
|
||||
// - A leading surrogate is a code point that is in the range U+D800 to U+DBFF, inclusive.
|
||||
// - A trailing surrogate is a code point that is in the range U+DC00 to U+DFFF, inclusive.
|
||||
(codePoint >= 0xd800 && codePoint <= 0xdfff)
|
||||
) {
|
||||
return '\uFFFD'
|
||||
}
|
||||
|
||||
return String.fromCodePoint(codePoint)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,7 +313,11 @@ test('placeholder-shown', async () => {
|
|||
test('autofill', async () => {
|
||||
expect(await run(['autofill:flex', 'group-autofill:flex', 'peer-autofill:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
".group-autofill\\:flex:is(:where(.group):autofill *), .peer-autofill\\:flex:is(:where(.peer):autofill ~ *), .autofill\\:flex:autofill {
|
||||
".group-autofill\\:flex:is(:where(.group):autofill *), .peer-autofill\\:flex:is(:where(.peer):autofill ~ *) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.autofill\\:flex:autofill {
|
||||
display: flex;
|
||||
}"
|
||||
`)
|
||||
|
|
@ -1475,7 +1479,15 @@ test('not', async () => {
|
|||
],
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
".not-first\\:flex:not(:first-child), .not-last\\:flex:not(:last-child), .not-only\\:flex:not(:only-child), .not-odd\\:flex:not(:nth-child(odd)), .not-even\\:flex:not(:nth-child(2n)), .not-first-of-type\\:flex:not(:first-of-type), .not-last-of-type\\:flex:not(:last-of-type), .not-only-of-type\\:flex:not(:only-of-type), .not-visited\\:flex:not(:visited), .not-target\\:flex:not(:target), .not-open\\:flex:not(:is([open], :popover-open, :open)), .not-default\\:flex:not(:default), .not-checked\\:flex:not(:checked), .not-indeterminate\\:flex:not(:indeterminate), .not-placeholder-shown\\:flex:not(:placeholder-shown), .not-autofill\\:flex:not(:autofill), .not-optional\\:flex:not(:optional), .not-required\\:flex:not(:required), .not-valid\\:flex:not(:valid), .not-invalid\\:flex:not(:invalid), .not-in-range\\:flex:not(:in-range), .not-out-of-range\\:flex:not(:out-of-range), .not-read-only\\:flex:not(:read-only), .not-empty\\:flex:not(:empty), .not-focus-within\\:flex:not(:focus-within), .not-hover\\:flex:not(:hover) {
|
||||
".not-first\\:flex:not(:first-child), .not-last\\:flex:not(:last-child), .not-only\\:flex:not(:only-child), .not-odd\\:flex:not(:nth-child(odd)), .not-even\\:flex:not(:nth-child(2n)), .not-first-of-type\\:flex:not(:first-of-type), .not-last-of-type\\:flex:not(:last-of-type), .not-only-of-type\\:flex:not(:only-of-type), .not-visited\\:flex:not(:visited), .not-target\\:flex:not(:target), .not-open\\:flex:not(:is([open], :popover-open, :open)), .not-default\\:flex:not(:default), .not-checked\\:flex:not(:checked), .not-indeterminate\\:flex:not(:indeterminate), .not-placeholder-shown\\:flex:not(:placeholder-shown) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.not-autofill\\:flex:not(:autofill) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.not-optional\\:flex:not(:optional), .not-required\\:flex:not(:required), .not-valid\\:flex:not(:valid), .not-invalid\\:flex:not(:invalid), .not-in-range\\:flex:not(:in-range), .not-out-of-range\\:flex:not(:out-of-range), .not-read-only\\:flex:not(:read-only), .not-empty\\:flex:not(:empty), .not-focus-within\\:flex:not(:focus-within), .not-hover\\:flex:not(:hover) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -2383,7 +2395,15 @@ test('variant order', async () => {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.first\\:flex:first-child, .last\\:flex:last-child, .only\\:flex:only-child, .odd\\:flex:nth-child(odd), .even\\:flex:nth-child(2n), .first-of-type\\:flex:first-of-type, .last-of-type\\:flex:last-of-type, .only-of-type\\:flex:only-of-type, .visited\\:flex:visited, .target\\:flex:target, .open\\:flex:is([open], :popover-open, :open), .default\\:flex:default, .checked\\:flex:checked, .indeterminate\\:flex:indeterminate, .placeholder-shown\\:flex:placeholder-shown, .autofill\\:flex:autofill, .optional\\:flex:optional, .required\\:flex:required, .valid\\:flex:valid, .invalid\\:flex:invalid, .in-range\\:flex:in-range, .out-of-range\\:flex:out-of-range, .read-only\\:flex:read-only, .empty\\:flex:empty, .focus-within\\:flex:focus-within {
|
||||
.first\\:flex:first-child, .last\\:flex:last-child, .only\\:flex:only-child, .odd\\:flex:nth-child(odd), .even\\:flex:nth-child(2n), .first-of-type\\:flex:first-of-type, .last-of-type\\:flex:last-of-type, .only-of-type\\:flex:only-of-type, .visited\\:flex:visited, .target\\:flex:target, .open\\:flex:is([open], :popover-open, :open), .default\\:flex:default, .checked\\:flex:checked, .indeterminate\\:flex:indeterminate, .placeholder-shown\\:flex:placeholder-shown {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.autofill\\:flex:autofill {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.optional\\:flex:optional, .required\\:flex:required, .valid\\:flex:valid, .invalid\\:flex:invalid, .in-range\\:flex:in-range, .out-of-range\\:flex:out-of-range, .read-only\\:flex:read-only, .empty\\:flex:empty, .focus-within\\:flex:focus-within {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
diff --git a/index.js b/index.js
|
||||
index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..398af238a439912d150b3573367873d2a9a311e3 100644
|
||||
index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..f28fd092644ccfb8aff2618b966cb5219a181a02 100644
|
||||
--- a/index.js
|
||||
+++ b/index.js
|
||||
@@ -1,41 +1,34 @@
|
||||
-const {createWrapper} = require('./wrapper');
|
||||
+const { createWrapper } = require('./wrapper')
|
||||
@@ -1,40 +1,32 @@
|
||||
const {createWrapper} = require('./wrapper');
|
||||
|
||||
-let name = `@parcel/watcher-${process.platform}-${process.arch}`;
|
||||
-if (process.platform === 'linux') {
|
||||
|
|
@ -15,6 +14,8 @@ index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..398af238a439912d150b3573367873d2
|
|||
- name += '-glibc';
|
||||
- }
|
||||
-}
|
||||
+// We need to take the `process.env.PLATFORM_LIBC` into account, and we also
|
||||
+// need static analysis, so we can't make use of the `parts.push(…)` approach.
|
||||
+function loadPackage() {
|
||||
+ if (process.platform === 'linux') {
|
||||
+ if (process.env.PLATFORM_LIBC === "musl") {
|
||||
|
|
@ -22,7 +23,8 @@ index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..398af238a439912d150b3573367873d2
|
|||
+ } else if (process.env.PLATFORM_LIBC === "glibc") {
|
||||
+ return require(`@parcel/watcher-${process.platform}-${process.arch}-glibc`)
|
||||
+ } else {
|
||||
+ let { MUSL, GLIBC, family, familySync } = require('detect-libc')
|
||||
+ let { MUSL, GLIBC, familySync } = require('detect-libc')
|
||||
+ let family = familySync()
|
||||
|
||||
-let binding;
|
||||
-try {
|
||||
|
|
@ -41,10 +43,6 @@ index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..398af238a439912d150b3573367873d2
|
|||
- }
|
||||
- }
|
||||
-}
|
||||
+ // Bun polyfills `detect-libc` in compiled binaries. We rely on
|
||||
+ // detect-libc@1.0.3 but the polyfilled version is 2.x. In detect-libc@2x
|
||||
+ // there is a `familySync` function that we can use instead.
|
||||
+ if (typeof familySync === 'function') family = familySync()
|
||||
|
||||
-function handleError(err) {
|
||||
- if (err?.code !== 'MODULE_NOT_FOUND') {
|
||||
|
|
@ -63,12 +61,7 @@ index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..398af238a439912d150b3573367873d2
|
|||
}
|
||||
|
||||
-const wrapper = createWrapper(binding);
|
||||
-exports.writeSnapshot = wrapper.writeSnapshot;
|
||||
-exports.getEventsSince = wrapper.getEventsSince;
|
||||
-exports.subscribe = wrapper.subscribe;
|
||||
-exports.unsubscribe = wrapper.unsubscribe;
|
||||
+const wrapper = createWrapper(loadPackage())
|
||||
+exports.writeSnapshot = wrapper.writeSnapshot
|
||||
+exports.getEventsSince = wrapper.getEventsSince
|
||||
+exports.subscribe = wrapper.subscribe
|
||||
+exports.unsubscribe = wrapper.unsubscribe
|
||||
+const wrapper = createWrapper(loadPackage());
|
||||
exports.writeSnapshot = wrapper.writeSnapshot;
|
||||
exports.getEventsSince = wrapper.getEventsSince;
|
||||
exports.subscribe = wrapper.subscribe;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
diff --git a/node/index.js b/node/index.js
|
||||
index 011d04b450687083e7a0ec9023c41ee79104831c..ef26db49d98c60b5b31f3601f6ad045f0b0e8f4f 100644
|
||||
index 6fe25aef457aa5448f9ee6204da1e253f5534800..742be0229b94450b631b6e069ffc372d2b35df47 100644
|
||||
--- a/node/index.js
|
||||
+++ b/node/index.js
|
||||
@@ -1,28 +1,41 @@
|
||||
@@ -1,25 +1,40 @@
|
||||
-let parts = [process.platform, process.arch];
|
||||
-if (process.platform === 'linux') {
|
||||
- const { MUSL, familySync } = require('detect-libc');
|
||||
|
|
@ -11,12 +11,8 @@ index 011d04b450687083e7a0ec9023c41ee79104831c..ef26db49d98c60b5b31f3601f6ad045f
|
|||
- parts.push('musl');
|
||||
- } else if (process.arch === 'arm') {
|
||||
- parts.push('gnueabihf');
|
||||
- } else {
|
||||
- parts.push('gnu');
|
||||
- }
|
||||
-} else if (process.platform === 'win32') {
|
||||
- parts.push('msvc');
|
||||
-}
|
||||
+// We need to take the `process.env.PLATFORM_LIBC` into account, and we also
|
||||
+// need static analysis, so we can't make use of the `parts.push(…)` approach.
|
||||
+function loadPackage() {
|
||||
+ if (process.platform === 'linux') {
|
||||
+ if (process.env.PLATFORM_LIBC === 'musl') {
|
||||
|
|
@ -28,19 +24,8 @@ index 011d04b450687083e7a0ec9023c41ee79104831c..ef26db49d98c60b5b31f3601f6ad045f
|
|||
+ return require(`lightningcss-${process.platform}-${process.arch}-gnu`)
|
||||
+ }
|
||||
+ } else {
|
||||
+ let { MUSL, GLIBC, family, familySync } = require('detect-libc')
|
||||
|
||||
-if (process.env.CSS_TRANSFORMER_WASM) {
|
||||
- module.exports = require(`../pkg`);
|
||||
-} else {
|
||||
- try {
|
||||
- module.exports = require(`lightningcss-${parts.join('-')}`);
|
||||
- } catch (err) {
|
||||
- module.exports = require(`../lightningcss.${parts.join('-')}.node`);
|
||||
+ // Bun polyfills `detect-libc` in compiled binaries. We rely on
|
||||
+ // detect-libc@1.0.3 but the polyfilled version is 2.x. In detect-libc@2x
|
||||
+ // there is a `familySync` function that we can use instead.
|
||||
+ if (typeof familySync === 'function') family = familySync()
|
||||
+ let { MUSL, GLIBC, familySync } = require('detect-libc')
|
||||
+ let family = familySync()
|
||||
+
|
||||
+ if (family === MUSL) {
|
||||
+ return require(`lightningcss-${process.platform}-${process.arch}-musl`)
|
||||
|
|
@ -56,15 +41,22 @@ index 011d04b450687083e7a0ec9023c41ee79104831c..ef26db49d98c60b5b31f3601f6ad045f
|
|||
+ }
|
||||
+ } else if (process.platform === 'win32') {
|
||||
+ return require(`lightningcss-${process.platform}-${process.arch}-msvc`)
|
||||
+ } else {
|
||||
} else {
|
||||
- parts.push('gnu');
|
||||
+ return require(`lightningcss-${process.platform}-${process.arch}`)
|
||||
}
|
||||
-} else if (process.platform === 'win32') {
|
||||
- parts.push('msvc');
|
||||
}
|
||||
|
||||
-module.exports.browserslistToTargets = require('./browserslistToTargets');
|
||||
-module.exports.composeVisitors = require('./composeVisitors');
|
||||
-module.exports.Features = require('./flags').Features;
|
||||
+module.exports = loadPackage()
|
||||
+module.exports.browserslistToTargets = require('./browserslistToTargets')
|
||||
+module.exports.composeVisitors = require('./composeVisitors')
|
||||
+module.exports.Features = require('./flags').Features
|
||||
|
||||
-let native;
|
||||
-try {
|
||||
- native = require(`lightningcss-${parts.join('-')}`);
|
||||
-} catch (err) {
|
||||
- native = require(`../lightningcss.${parts.join('-')}.node`);
|
||||
-}
|
||||
|
||||
+let native = loadPackage();
|
||||
module.exports.transform = wrap(native.transform);
|
||||
module.exports.transformStyleAttribute = wrap(native.transformStyleAttribute);
|
||||
module.exports.bundle = wrap(native.bundle);
|
||||
215
pnpm-lock.yaml
generated
215
pnpm-lock.yaml
generated
|
|
@ -10,29 +10,29 @@ catalogs:
|
|||
specifier: ^20.19.0
|
||||
version: 20.19.1
|
||||
lightningcss:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-darwin-arm64:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-darwin-x64:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-linux-arm64-gnu:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-linux-arm64-musl:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-linux-x64-gnu:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-linux-x64-musl:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
lightningcss-win32-x64-msvc:
|
||||
specifier: 1.31.1
|
||||
version: 1.31.1
|
||||
specifier: 1.32.0
|
||||
version: 1.32.0
|
||||
prettier:
|
||||
specifier: 3.8.1
|
||||
version: 3.8.1
|
||||
|
|
@ -45,11 +45,11 @@ catalogs:
|
|||
|
||||
patchedDependencies:
|
||||
'@parcel/watcher@2.5.1':
|
||||
hash: zs2vvlrje3h42xp5ed2v44fep4
|
||||
hash: p6xahr7zs4c5qsorj3exeppxhm
|
||||
path: patches/@parcel__watcher@2.5.1.patch
|
||||
lightningcss@1.31.1:
|
||||
hash: tzyxy3asfxcqc7ihrooumyi5fm
|
||||
path: patches/lightningcss@1.31.1.patch
|
||||
lightningcss@1.32.0:
|
||||
hash: mz3chiqe2jbihxa25xumd4ogum
|
||||
path: patches/lightningcss@1.32.0.patch
|
||||
|
||||
importers:
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ importers:
|
|||
version: 5.5.4
|
||||
vitest:
|
||||
specifier: ^4.0.18
|
||||
version: 4.0.18(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)
|
||||
version: 4.0.18(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)
|
||||
|
||||
crates/node:
|
||||
optionalDependencies:
|
||||
|
|
@ -211,7 +211,7 @@ importers:
|
|||
dependencies:
|
||||
'@parcel/watcher':
|
||||
specifier: ^2.5.1
|
||||
version: 2.5.1(patch_hash=zs2vvlrje3h42xp5ed2v44fep4)
|
||||
version: 2.5.1(patch_hash=p6xahr7zs4c5qsorj3exeppxhm)
|
||||
'@tailwindcss/node':
|
||||
specifier: workspace:*
|
||||
version: link:../@tailwindcss-node
|
||||
|
|
@ -244,7 +244,7 @@ importers:
|
|||
version: 2.6.1
|
||||
lightningcss:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1(patch_hash=tzyxy3asfxcqc7ihrooumyi5fm)
|
||||
version: 1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum)
|
||||
magic-string:
|
||||
specifier: ^0.30.21
|
||||
version: 0.30.21
|
||||
|
|
@ -342,25 +342,25 @@ importers:
|
|||
version: 1.3.9
|
||||
lightningcss-darwin-arm64:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
lightningcss-darwin-x64:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
lightningcss-linux-arm64-gnu:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
lightningcss-linux-arm64-musl:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
lightningcss-linux-x64-gnu:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
lightningcss-linux-x64-musl:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
lightningcss-win32-x64-msvc:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1
|
||||
version: 1.32.0
|
||||
|
||||
packages/@tailwindcss-upgrade:
|
||||
dependencies:
|
||||
|
|
@ -482,7 +482,7 @@ importers:
|
|||
version: 1.7.1
|
||||
lightningcss:
|
||||
specifier: 'catalog:'
|
||||
version: 1.31.1(patch_hash=tzyxy3asfxcqc7ihrooumyi5fm)
|
||||
version: 1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum)
|
||||
magic-string:
|
||||
specifier: ^0.30.21
|
||||
version: 0.30.21
|
||||
|
|
@ -3813,135 +3813,65 @@ packages:
|
|||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
lightningcss-android-arm64@1.32.0:
|
||||
resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
lightningcss-darwin-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-arm64@1.32.0:
|
||||
resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-x64@1.31.1:
|
||||
resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-x64@1.32.0:
|
||||
resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-freebsd-x64@1.31.1:
|
||||
resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lightningcss-freebsd-x64@1.32.0:
|
||||
resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.31.1:
|
||||
resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.32.0:
|
||||
resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.31.1:
|
||||
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.32.0:
|
||||
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-x64-msvc@1.31.1:
|
||||
resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-x64-msvc@1.32.0:
|
||||
resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss@1.31.1:
|
||||
resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
lightningcss@1.32.0:
|
||||
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
|
@ -6419,7 +6349,7 @@ snapshots:
|
|||
'@parcel/watcher-win32-ia32': 2.5.0
|
||||
'@parcel/watcher-win32-x64': 2.5.0
|
||||
|
||||
'@parcel/watcher@2.5.1(patch_hash=zs2vvlrje3h42xp5ed2v44fep4)':
|
||||
'@parcel/watcher@2.5.1(patch_hash=p6xahr7zs4c5qsorj3exeppxhm)':
|
||||
dependencies:
|
||||
detect-libc: 1.0.3
|
||||
is-glob: 4.0.3
|
||||
|
|
@ -6766,13 +6696,13 @@ snapshots:
|
|||
chai: 6.2.1
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vitest/mocker@4.0.18(vite@7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0))':
|
||||
'@vitest/mocker@4.0.18(vite@7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.0.18
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)
|
||||
vite: 7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)
|
||||
|
||||
'@vitest/pretty-format@4.0.18':
|
||||
dependencies:
|
||||
|
|
@ -8242,82 +8172,33 @@ snapshots:
|
|||
prelude-ls: 1.2.1
|
||||
type-check: 0.4.0
|
||||
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-android-arm64@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-arm64@1.31.1: {}
|
||||
lightningcss-darwin-arm64@1.32.0: {}
|
||||
|
||||
lightningcss-darwin-arm64@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-x64@1.31.1: {}
|
||||
|
||||
lightningcss-darwin-x64@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-freebsd-x64@1.31.1:
|
||||
optional: true
|
||||
lightningcss-darwin-x64@1.32.0: {}
|
||||
|
||||
lightningcss-freebsd-x64@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.31.1:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.31.1: {}
|
||||
lightningcss-linux-arm64-gnu@1.32.0: {}
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.32.0:
|
||||
optional: true
|
||||
lightningcss-linux-arm64-musl@1.32.0: {}
|
||||
|
||||
lightningcss-linux-arm64-musl@1.31.1: {}
|
||||
lightningcss-linux-x64-gnu@1.32.0: {}
|
||||
|
||||
lightningcss-linux-arm64-musl@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-gnu@1.31.1: {}
|
||||
|
||||
lightningcss-linux-x64-gnu@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-musl@1.31.1: {}
|
||||
|
||||
lightningcss-linux-x64-musl@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.31.1:
|
||||
optional: true
|
||||
lightningcss-linux-x64-musl@1.32.0: {}
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-x64-msvc@1.31.1: {}
|
||||
lightningcss-win32-x64-msvc@1.32.0: {}
|
||||
|
||||
lightningcss-win32-x64-msvc@1.32.0:
|
||||
optional: true
|
||||
|
||||
lightningcss@1.31.1(patch_hash=tzyxy3asfxcqc7ihrooumyi5fm):
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
lightningcss-android-arm64: 1.31.1
|
||||
lightningcss-darwin-arm64: 1.31.1
|
||||
lightningcss-darwin-x64: 1.31.1
|
||||
lightningcss-freebsd-x64: 1.31.1
|
||||
lightningcss-linux-arm-gnueabihf: 1.31.1
|
||||
lightningcss-linux-arm64-gnu: 1.31.1
|
||||
lightningcss-linux-arm64-musl: 1.31.1
|
||||
lightningcss-linux-x64-gnu: 1.31.1
|
||||
lightningcss-linux-x64-musl: 1.31.1
|
||||
lightningcss-win32-arm64-msvc: 1.31.1
|
||||
lightningcss-win32-x64-msvc: 1.31.1
|
||||
|
||||
lightningcss@1.32.0:
|
||||
lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum):
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
|
|
@ -9408,7 +9289,7 @@ snapshots:
|
|||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vite@7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0):
|
||||
vite@7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.0
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
|
|
@ -9420,7 +9301,7 @@ snapshots:
|
|||
'@types/node': 20.19.1
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.32.0
|
||||
lightningcss: 1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum)
|
||||
terser: 5.31.6
|
||||
tsx: 4.19.1
|
||||
yaml: 2.6.0
|
||||
|
|
@ -9428,7 +9309,7 @@ snapshots:
|
|||
vite@8.0.0(@types/node@20.19.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0):
|
||||
dependencies:
|
||||
'@oxc-project/runtime': 0.115.0
|
||||
lightningcss: 1.32.0
|
||||
lightningcss: 1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum)
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.8
|
||||
rolldown: 1.0.0-rc.9
|
||||
|
|
@ -9442,10 +9323,10 @@ snapshots:
|
|||
tsx: 4.19.1
|
||||
yaml: 2.6.0
|
||||
|
||||
vitest@4.0.18(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0):
|
||||
vitest@4.0.18(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.18
|
||||
'@vitest/mocker': 4.0.18(vite@7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0))
|
||||
'@vitest/mocker': 4.0.18(vite@7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0))
|
||||
'@vitest/pretty-format': 4.0.18
|
||||
'@vitest/runner': 4.0.18
|
||||
'@vitest/snapshot': 4.0.18
|
||||
|
|
@ -9462,7 +9343,7 @@ snapshots:
|
|||
tinyexec: 1.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vite: 7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)
|
||||
vite: 7.0.0(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.32.0(patch_hash=mz3chiqe2jbihxa25xumd4ogum))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.19.1
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ catalog:
|
|||
prettier: 3.8.1
|
||||
vite: ^8.0.0
|
||||
webpack: ^5
|
||||
lightningcss: 1.31.1
|
||||
lightningcss-darwin-arm64: 1.31.1
|
||||
lightningcss-darwin-x64: 1.31.1
|
||||
lightningcss-linux-arm64-gnu: 1.31.1
|
||||
lightningcss-linux-arm64-musl: 1.31.1
|
||||
lightningcss-linux-x64-gnu: 1.31.1
|
||||
lightningcss-linux-x64-musl: 1.31.1
|
||||
lightningcss-win32-x64-msvc: 1.31.1
|
||||
lightningcss: 1.32.0
|
||||
lightningcss-darwin-arm64: 1.32.0
|
||||
lightningcss-darwin-x64: 1.32.0
|
||||
lightningcss-linux-arm64-gnu: 1.32.0
|
||||
lightningcss-linux-arm64-musl: 1.32.0
|
||||
lightningcss-linux-x64-gnu: 1.32.0
|
||||
lightningcss-linux-x64-musl: 1.32.0
|
||||
lightningcss-win32-x64-msvc: 1.32.0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue