From 8f631d0d8ac9c26c0b6af89eb065deeebdde6915 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 1 Apr 2025 18:05:18 +0200 Subject: [PATCH] Prepare 4.1.0 release (#17483) --------- Co-authored-by: Adam Wathan --- CHANGELOG.md | 63 +- crates/node/npm/android-arm-eabi/package.json | 2 +- crates/node/npm/android-arm64/package.json | 2 +- crates/node/npm/darwin-arm64/package.json | 2 +- crates/node/npm/darwin-x64/package.json | 2 +- crates/node/npm/freebsd-x64/package.json | 2 +- .../node/npm/linux-arm-gnueabihf/package.json | 2 +- crates/node/npm/linux-arm64-gnu/package.json | 2 +- crates/node/npm/linux-arm64-musl/package.json | 2 +- crates/node/npm/linux-x64-gnu/package.json | 2 +- crates/node/npm/linux-x64-musl/package.json | 2 +- crates/node/npm/win32-arm64-msvc/package.json | 2 +- crates/node/npm/win32-x64-msvc/package.json | 2 +- crates/node/package.json | 2 +- packages/@tailwindcss-browser/package.json | 2 +- packages/@tailwindcss-cli/package.json | 2 +- packages/@tailwindcss-node/package.json | 2 +- packages/@tailwindcss-postcss/package.json | 2 +- packages/@tailwindcss-standalone/package.json | 2 +- packages/@tailwindcss-upgrade/package.json | 2 +- packages/@tailwindcss-vite/package.json | 2 +- packages/tailwindcss/package.json | 2 +- packages/tailwindcss/src/feature-flags.ts | 12 - packages/tailwindcss/src/index.ts | 21 +- packages/tailwindcss/src/utilities.ts | 1555 ++++++++--------- packages/tailwindcss/src/variants.ts | 39 +- 26 files changed, 829 insertions(+), 903 deletions(-) delete mode 100644 packages/tailwindcss/src/feature-flags.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index faf6c8cc4..380efc74f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,45 +7,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Nothing yet! + +## [4.1.0] - 2025-04-01 + ### Added -- _Experimental_: Add `details-content` variant ([#15319](https://github.com/tailwindlabs/tailwindcss/pull/15319)) -- _Experimental_: Add `inverted-colors` variant ([#11693](https://github.com/tailwindlabs/tailwindcss/pull/11693)) -- _Experimental_: Add `noscript` variant ([#11929](https://github.com/tailwindlabs/tailwindcss/pull/11929), [#17431](https://github.com/tailwindlabs/tailwindcss/pull/17431)) -- _Experimental_: Add `items-baseline-last` and `self-baseline-last` utilities ([#13888](https://github.com/tailwindlabs/tailwindcss/pull/13888), [#17476](https://github.com/tailwindlabs/tailwindcss/pull/17476)) -- _Experimental_: Add `pointer-none`, `pointer-coarse`, and `pointer-fine` variant ([#16946](https://github.com/tailwindlabs/tailwindcss/pull/16946)) -- _Experimental_: Add `any-pointer-none`, `any-pointer-coarse`, and `any-pointer-fine` variants ([#16941](https://github.com/tailwindlabs/tailwindcss/pull/16941)) -- _Experimental_: Add safe alignment utilities ([#14607](https://github.com/tailwindlabs/tailwindcss/pull/14607)) -- _Experimental_: Add `user-valid` and `user-invalid` variants ([#12370](https://github.com/tailwindlabs/tailwindcss/pull/12370)) -- _Experimental_: Add `wrap-anywhere`, `wrap-break-word`, and `wrap-normal` utilities ([#12128](https://github.com/tailwindlabs/tailwindcss/pull/12128)) -- _Experimental_: Add `@source inline(…)` ([#17147](https://github.com/tailwindlabs/tailwindcss/pull/17147)) -- _Experimental_: Add `@source not` ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) -- _Experimental_: Add `text-shadow-*` utilities ([#17389](https://github.com/tailwindlabs/tailwindcss/pull/17389)) -- _Experimental_: Add `mask-*` utilities ([#17134](https://github.com/tailwindlabs/tailwindcss/pull/17134)) -- Added new `bg-{top,bottom}-{left,right}` utilities ([#17378](https://github.com/tailwindlabs/tailwindcss/pull/17378)) -- Added new `bg-{position,size}-*` utilities for arbitrary values ([#17432](https://github.com/tailwindlabs/tailwindcss/pull/17432)) -- Added new `shadow-*/{alpha}`, `inset-shadow-*/{alpha}`, and `text-shadow-*/{alpha}` utilities to control shadow opacity ([#17398](https://github.com/tailwindlabs/tailwindcss/pull/17398)) -- Added new `object-{top,bottom}-{left,right}` utilities ([#17437](https://github.com/tailwindlabs/tailwindcss/pull/17437)) -- Added new `drop-shadow-{color}` utilities ([#17434](https://github.com/tailwindlabs/tailwindcss/pull/17434)) -- Added new `drop-shadow-*/{alpha}` utilities to control drop shadow opacity ([#17434](https://github.com/tailwindlabs/tailwindcss/pull/17434)) +- Add `details-content` variant ([#15319](https://github.com/tailwindlabs/tailwindcss/pull/15319)) +- Add `inverted-colors` variant ([#11693](https://github.com/tailwindlabs/tailwindcss/pull/11693)) +- Add `noscript` variant ([#11929](https://github.com/tailwindlabs/tailwindcss/pull/11929), [#17431](https://github.com/tailwindlabs/tailwindcss/pull/17431)) +- Add `items-baseline-last` and `self-baseline-last` utilities ([#13888](https://github.com/tailwindlabs/tailwindcss/pull/13888), [#17476](https://github.com/tailwindlabs/tailwindcss/pull/17476)) +- Add `pointer-none`, `pointer-coarse`, and `pointer-fine` variants ([#16946](https://github.com/tailwindlabs/tailwindcss/pull/16946)) +- Add `any-pointer-none`, `any-pointer-coarse`, and `any-pointer-fine` variants ([#16941](https://github.com/tailwindlabs/tailwindcss/pull/16941)) +- Add safe alignment utilities ([#14607](https://github.com/tailwindlabs/tailwindcss/pull/14607)) +- Add `user-valid` and `user-invalid` variants ([#12370](https://github.com/tailwindlabs/tailwindcss/pull/12370)) +- Add `wrap-anywhere`, `wrap-break-word`, and `wrap-normal` utilities ([#12128](https://github.com/tailwindlabs/tailwindcss/pull/12128)) +- Add `@source inline(…)` and `@source not inline(…)` ([#17147](https://github.com/tailwindlabs/tailwindcss/pull/17147)) +- Add `@source not "…"` ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) +- Add `text-shadow-*` utilities ([#17389](https://github.com/tailwindlabs/tailwindcss/pull/17389)) +- Add `mask-*` utilities ([#17134](https://github.com/tailwindlabs/tailwindcss/pull/17134)) +- Add `bg-{position,size}-*` utilities for arbitrary values ([#17432](https://github.com/tailwindlabs/tailwindcss/pull/17432)) +- Add `shadow-*/`, `inset-shadow-*/`, `drop-shadow-*/`, and `text-shadow-*/` utilities to control shadow opacity ([#17398](https://github.com/tailwindlabs/tailwindcss/pull/17398), [#17434](https://github.com/tailwindlabs/tailwindcss/pull/17434)) +- Add `drop-shadow-` utilities ([#17434](https://github.com/tailwindlabs/tailwindcss/pull/17434)) +- Improve compatibility with older versions of Safari and Firefox ([#17435](https://github.com/tailwindlabs/tailwindcss/pull/17435)) ### Fixed -- Fix symlink issues when resolving `@source` directives ([#17391](https://github.com/tailwindlabs/tailwindcss/pull/17391)) -- `@tailwindcss/cli` considers ignore rules in `--watch` mode ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) -- Fix negated `content` rules in legacy JavaScript configuration ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) -- Extract special `@("@")md:…` syntax in Razor files ([#17427](https://github.com/tailwindlabs/tailwindcss/pull/17427)) -- Disallow arbitrary values with top-level braces and semicolons as well as unbalanced parentheses and brackets ([#17361](https://github.com/tailwindlabs/tailwindcss/pull/17361)) -- Ensure the `--theme(…)` function still resolves to the CSS variables even when legacy JS plugins are enabled -- Extract used CSS variables from `.css` files ([#17433](https://github.com/tailwindlabs/tailwindcss/pull/17433), [#17467](https://github.com/tailwindlabs/tailwindcss/pull/17467)) -- Improve compatibility with Safari 15 ([#17435](https://github.com/tailwindlabs/tailwindcss/pull/17435)) +- Follow symlinks when resolving `@source` directives ([#17391](https://github.com/tailwindlabs/tailwindcss/pull/17391)) +- Don't scan ignored files for classes when changing an ignored file triggers a rebuild using `@tailwindcss/cli` ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) +- Support negated `content` rules in legacy JavaScript configuration ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) +- Interpret syntax like `@("@")md:…` as `@md:…` in Razor files ([#17427](https://github.com/tailwindlabs/tailwindcss/pull/17427)) +- Disallow top-level braces, top-level semicolons, and unbalanced parentheses and brackets in arbitrary values ([#17361](https://github.com/tailwindlabs/tailwindcss/pull/17361)) +- Ensure the `--theme(…)` function still resolves to the CSS variables when using legacy JS plugins ([#17458](https://github.com/tailwindlabs/tailwindcss/pull/17458)) +- Detect used theme variables in CSS module files ([#17433](https://github.com/tailwindlabs/tailwindcss/pull/17433), [#17467](https://github.com/tailwindlabs/tailwindcss/pull/17467)) ### Changed -- Ignore `node_modules` by default (but can be overridden by `@source not …` rules) ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) -- Order of `@source` rules matter if you want to negate previous `@source` rules ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) -- `@source` rules that include file extensions or point inside `node_modules/` no longer consider `.gitignore` rules ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) -- Deprecated `bg-{left,right}-{top,bottom}` utilities ([#17378](https://github.com/tailwindlabs/tailwindcss/pull/17378)) +- Ignore `node_modules` by default (can be overridden by `@source …` rules) ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) +- `@source` rules that include file extensions or point inside `node_modules/` folders no longer consider your `.gitignore` rules ([#17255](https://github.com/tailwindlabs/tailwindcss/pull/17255)) +- Deprecate `bg-{left,right}-{top,bottom}` in favor of `bg-{top,bottom}-{left,right}` utilities ([#17378](https://github.com/tailwindlabs/tailwindcss/pull/17378)) +- Deprecate `object-{left,right}-{top,bottom}` in favor of `object-{top,bottom}-{left,right}` utilities ([#17437](https://github.com/tailwindlabs/tailwindcss/pull/17437)) ## [4.0.17] - 2025-03-26 diff --git a/crates/node/npm/android-arm-eabi/package.json b/crates/node/npm/android-arm-eabi/package.json index b28770010..6f993cdda 100644 --- a/crates/node/npm/android-arm-eabi/package.json +++ b/crates/node/npm/android-arm-eabi/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-android-arm-eabi", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/android-arm64/package.json b/crates/node/npm/android-arm64/package.json index 45b7166a9..fe76839c4 100644 --- a/crates/node/npm/android-arm64/package.json +++ b/crates/node/npm/android-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-android-arm64", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/darwin-arm64/package.json b/crates/node/npm/darwin-arm64/package.json index 703908e47..1673115e2 100644 --- a/crates/node/npm/darwin-arm64/package.json +++ b/crates/node/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-darwin-arm64", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/darwin-x64/package.json b/crates/node/npm/darwin-x64/package.json index eb6220118..138f0da57 100644 --- a/crates/node/npm/darwin-x64/package.json +++ b/crates/node/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-darwin-x64", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/freebsd-x64/package.json b/crates/node/npm/freebsd-x64/package.json index 0a258b8b3..54358e29a 100644 --- a/crates/node/npm/freebsd-x64/package.json +++ b/crates/node/npm/freebsd-x64/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-freebsd-x64", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/linux-arm-gnueabihf/package.json b/crates/node/npm/linux-arm-gnueabihf/package.json index 7fa9a41c6..07378bcee 100644 --- a/crates/node/npm/linux-arm-gnueabihf/package.json +++ b/crates/node/npm/linux-arm-gnueabihf/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-linux-arm-gnueabihf", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/linux-arm64-gnu/package.json b/crates/node/npm/linux-arm64-gnu/package.json index 2556cc6a4..75da42307 100644 --- a/crates/node/npm/linux-arm64-gnu/package.json +++ b/crates/node/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-linux-arm64-gnu", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/linux-arm64-musl/package.json b/crates/node/npm/linux-arm64-musl/package.json index c7e681165..1cb7854aa 100644 --- a/crates/node/npm/linux-arm64-musl/package.json +++ b/crates/node/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-linux-arm64-musl", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/linux-x64-gnu/package.json b/crates/node/npm/linux-x64-gnu/package.json index 011faa843..a1e97f6ec 100644 --- a/crates/node/npm/linux-x64-gnu/package.json +++ b/crates/node/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-linux-x64-gnu", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/linux-x64-musl/package.json b/crates/node/npm/linux-x64-musl/package.json index 569f7b9cc..d3a82b5b1 100644 --- a/crates/node/npm/linux-x64-musl/package.json +++ b/crates/node/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-linux-x64-musl", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/win32-arm64-msvc/package.json b/crates/node/npm/win32-arm64-msvc/package.json index 1c50aa577..2e9443a51 100644 --- a/crates/node/npm/win32-arm64-msvc/package.json +++ b/crates/node/npm/win32-arm64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-win32-arm64-msvc", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/npm/win32-x64-msvc/package.json b/crates/node/npm/win32-x64-msvc/package.json index 0dca1554c..682154fc8 100644 --- a/crates/node/npm/win32-x64-msvc/package.json +++ b/crates/node/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide-win32-x64-msvc", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/crates/node/package.json b/crates/node/package.json index 9515f247e..44c3fb5ae 100644 --- a/crates/node/package.json +++ b/crates/node/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/oxide", - "version": "4.0.17", + "version": "4.1.0", "repository": { "type": "git", "url": "git+https://github.com/tailwindlabs/tailwindcss.git", diff --git a/packages/@tailwindcss-browser/package.json b/packages/@tailwindcss-browser/package.json index ea6b9571a..6c4cd6241 100644 --- a/packages/@tailwindcss-browser/package.json +++ b/packages/@tailwindcss-browser/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/browser", - "version": "4.0.17", + "version": "4.1.0", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "main": "./dist/index.global.js", diff --git a/packages/@tailwindcss-cli/package.json b/packages/@tailwindcss-cli/package.json index 3268fb39a..f3b37a542 100644 --- a/packages/@tailwindcss-cli/package.json +++ b/packages/@tailwindcss-cli/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/cli", - "version": "4.0.17", + "version": "4.1.0", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { diff --git a/packages/@tailwindcss-node/package.json b/packages/@tailwindcss-node/package.json index 81f4aa1b3..3ce08d10b 100644 --- a/packages/@tailwindcss-node/package.json +++ b/packages/@tailwindcss-node/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/node", - "version": "4.0.17", + "version": "4.1.0", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { diff --git a/packages/@tailwindcss-postcss/package.json b/packages/@tailwindcss-postcss/package.json index 7625f85b9..eaeb2fcd6 100644 --- a/packages/@tailwindcss-postcss/package.json +++ b/packages/@tailwindcss-postcss/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/postcss", - "version": "4.0.17", + "version": "4.1.0", "description": "PostCSS plugin for Tailwind CSS, a utility-first CSS framework for rapidly building custom user interfaces", "license": "MIT", "repository": { diff --git a/packages/@tailwindcss-standalone/package.json b/packages/@tailwindcss-standalone/package.json index 1d208043a..3844acc99 100644 --- a/packages/@tailwindcss-standalone/package.json +++ b/packages/@tailwindcss-standalone/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/standalone", - "version": "4.0.17", + "version": "4.1.0", "private": true, "description": "Standalone CLI for Tailwind CSS", "license": "MIT", diff --git a/packages/@tailwindcss-upgrade/package.json b/packages/@tailwindcss-upgrade/package.json index 8e06c1824..7bcac6139 100644 --- a/packages/@tailwindcss-upgrade/package.json +++ b/packages/@tailwindcss-upgrade/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/upgrade", - "version": "4.0.17", + "version": "4.1.0", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { diff --git a/packages/@tailwindcss-vite/package.json b/packages/@tailwindcss-vite/package.json index 8e3f62081..d2169fba7 100644 --- a/packages/@tailwindcss-vite/package.json +++ b/packages/@tailwindcss-vite/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/vite", - "version": "4.0.17", + "version": "4.1.0", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { diff --git a/packages/tailwindcss/package.json b/packages/tailwindcss/package.json index 008c50857..baf4b3c99 100644 --- a/packages/tailwindcss/package.json +++ b/packages/tailwindcss/package.json @@ -1,6 +1,6 @@ { "name": "tailwindcss", - "version": "4.0.17", + "version": "4.1.0", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { diff --git a/packages/tailwindcss/src/feature-flags.ts b/packages/tailwindcss/src/feature-flags.ts deleted file mode 100644 index d38f5b6b6..000000000 --- a/packages/tailwindcss/src/feature-flags.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const enableBaselineLast = process.env.FEATURES_ENV !== 'stable' -export const enableDetailsContent = process.env.FEATURES_ENV !== 'stable' -export const enableInvertedColors = process.env.FEATURES_ENV !== 'stable' -export const enablePointerVariants = process.env.FEATURES_ENV !== 'stable' -export const enableSafeAlignment = process.env.FEATURES_ENV !== 'stable' -export const enableScripting = process.env.FEATURES_ENV !== 'stable' -export const enableSourceInline = process.env.FEATURES_ENV !== 'stable' -export const enableSourceNot = process.env.FEATURES_ENV !== 'stable' -export const enableTextShadows = process.env.FEATURES_ENV !== 'stable' -export const enableUserValid = process.env.FEATURES_ENV !== 'stable' -export const enableWrapAnywhere = process.env.FEATURES_ENV !== 'stable' -export const enableMaskUtilities = process.env.FEATURES_ENV !== 'stable' diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 2aba5c50b..8d953782f 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -26,7 +26,6 @@ import { applyVariant, compileCandidates } from './compile' import { substituteFunctions } from './css-functions' import * as CSS from './css-parser' import { buildDesignSystem, type DesignSystem } from './design-system' -import { enableSourceInline, enableSourceNot } from './feature-flags' import { Theme, ThemeOptions } from './theme' import { createCssUtility } from './utilities' import { expand } from './utils/brace-expansion' @@ -230,18 +229,14 @@ async function parseCss( let inline = false let path = node.params - if (enableSourceNot) { - if (path[0] === 'n' && path.startsWith('not ')) { - not = true - path = path.slice(4) - } + if (path[0] === 'n' && path.startsWith('not ')) { + not = true + path = path.slice(4) } - if (enableSourceInline) { - if (path[0] === 'i' && path.startsWith('inline(')) { - inline = true - path = path.slice(7, -1) - } + if (path[0] === 'i' && path.startsWith('inline(')) { + inline = true + path = path.slice(7, -1) } if ( @@ -254,7 +249,7 @@ async function parseCss( let source = path.slice(1, -1) - if (enableSourceInline && inline) { + if (inline) { let destination = not ? ignoredCandidates : inlineCandidates let sources = segment(source, ' ') for (let source of sources) { @@ -266,7 +261,7 @@ async function parseCss( sources.push({ base: context.base as string, pattern: source, - negated: enableSourceNot ? not : false, + negated: not, }) } replaceWith([]) diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index b688fdd41..a4359c53a 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -12,13 +12,6 @@ import { } from './ast' import type { Candidate, CandidateModifier, NamedUtilityValue } from './candidate' import type { DesignSystem } from './design-system' -import { - enableBaselineLast, - enableMaskUtilities, - enableSafeAlignment, - enableTextShadows, - enableWrapAnywhere, -} from './feature-flags' import type { Theme, ThemeKey } from './theme' import { compareBreakpoints } from './utils/compare-breakpoints' import { DefaultMap } from './utils/default-map' @@ -1873,10 +1866,8 @@ export function createUtilities(theme: Theme) { staticUtility('place-content-center', [['place-content', 'center']]) staticUtility('place-content-start', [['place-content', 'start']]) staticUtility('place-content-end', [['place-content', 'end']]) - if (enableSafeAlignment) { - staticUtility('place-content-center-safe', [['place-content', 'safe center']]) - staticUtility('place-content-end-safe', [['place-content', 'safe end']]) - } + staticUtility('place-content-center-safe', [['place-content', 'safe center']]) + staticUtility('place-content-end-safe', [['place-content', 'safe end']]) staticUtility('place-content-between', [['place-content', 'space-between']]) staticUtility('place-content-around', [['place-content', 'space-around']]) staticUtility('place-content-evenly', [['place-content', 'space-evenly']]) @@ -1886,10 +1877,8 @@ export function createUtilities(theme: Theme) { staticUtility('place-items-center', [['place-items', 'center']]) staticUtility('place-items-start', [['place-items', 'start']]) staticUtility('place-items-end', [['place-items', 'end']]) - if (enableSafeAlignment) { - staticUtility('place-items-center-safe', [['place-items', 'safe center']]) - staticUtility('place-items-end-safe', [['place-items', 'safe end']]) - } + staticUtility('place-items-center-safe', [['place-items', 'safe center']]) + staticUtility('place-items-end-safe', [['place-items', 'safe end']]) staticUtility('place-items-baseline', [['place-items', 'baseline']]) staticUtility('place-items-stretch', [['place-items', 'stretch']]) @@ -1897,10 +1886,8 @@ export function createUtilities(theme: Theme) { staticUtility('content-center', [['align-content', 'center']]) staticUtility('content-start', [['align-content', 'flex-start']]) staticUtility('content-end', [['align-content', 'flex-end']]) - if (enableSafeAlignment) { - staticUtility('content-center-safe', [['align-content', 'safe center']]) - staticUtility('content-end-safe', [['align-content', 'safe flex-end']]) - } + staticUtility('content-center-safe', [['align-content', 'safe center']]) + staticUtility('content-end-safe', [['align-content', 'safe flex-end']]) staticUtility('content-between', [['align-content', 'space-between']]) staticUtility('content-around', [['align-content', 'space-around']]) staticUtility('content-evenly', [['align-content', 'space-evenly']]) @@ -1910,24 +1897,18 @@ export function createUtilities(theme: Theme) { staticUtility('items-center', [['align-items', 'center']]) staticUtility('items-start', [['align-items', 'flex-start']]) staticUtility('items-end', [['align-items', 'flex-end']]) - if (enableSafeAlignment) { - staticUtility('items-center-safe', [['align-items', 'safe center']]) - staticUtility('items-end-safe', [['align-items', 'safe flex-end']]) - } + staticUtility('items-center-safe', [['align-items', 'safe center']]) + staticUtility('items-end-safe', [['align-items', 'safe flex-end']]) staticUtility('items-baseline', [['align-items', 'baseline']]) - if (enableBaselineLast) { - staticUtility('items-baseline-last', [['align-items', 'last baseline']]) - } + staticUtility('items-baseline-last', [['align-items', 'last baseline']]) staticUtility('items-stretch', [['align-items', 'stretch']]) staticUtility('justify-normal', [['justify-content', 'normal']]) staticUtility('justify-center', [['justify-content', 'center']]) staticUtility('justify-start', [['justify-content', 'flex-start']]) staticUtility('justify-end', [['justify-content', 'flex-end']]) - if (enableSafeAlignment) { - staticUtility('justify-center-safe', [['justify-content', 'safe center']]) - staticUtility('justify-end-safe', [['justify-content', 'safe flex-end']]) - } + staticUtility('justify-center-safe', [['justify-content', 'safe center']]) + staticUtility('justify-end-safe', [['justify-content', 'safe flex-end']]) staticUtility('justify-between', [['justify-content', 'space-between']]) staticUtility('justify-around', [['justify-content', 'space-around']]) staticUtility('justify-evenly', [['justify-content', 'space-evenly']]) @@ -1938,10 +1919,8 @@ export function createUtilities(theme: Theme) { staticUtility('justify-items-center', [['justify-items', 'center']]) staticUtility('justify-items-start', [['justify-items', 'start']]) staticUtility('justify-items-end', [['justify-items', 'end']]) - if (enableSafeAlignment) { - staticUtility('justify-items-center-safe', [['justify-items', 'safe center']]) - staticUtility('justify-items-end-safe', [['justify-items', 'safe end']]) - } + staticUtility('justify-items-center-safe', [['justify-items', 'safe center']]) + staticUtility('justify-items-end-safe', [['justify-items', 'safe end']]) staticUtility('justify-items-stretch', [['justify-items', 'stretch']]) spacingUtility('gap', ['--gap', '--spacing'], (value) => [decl('gap', value)]) @@ -2022,34 +2001,26 @@ export function createUtilities(theme: Theme) { staticUtility('place-self-start', [['place-self', 'start']]) staticUtility('place-self-end', [['place-self', 'end']]) staticUtility('place-self-center', [['place-self', 'center']]) - if (enableSafeAlignment) { - staticUtility('place-self-end-safe', [['place-self', 'safe end']]) - staticUtility('place-self-center-safe', [['place-self', 'safe center']]) - } + staticUtility('place-self-end-safe', [['place-self', 'safe end']]) + staticUtility('place-self-center-safe', [['place-self', 'safe center']]) staticUtility('place-self-stretch', [['place-self', 'stretch']]) staticUtility('self-auto', [['align-self', 'auto']]) staticUtility('self-start', [['align-self', 'flex-start']]) staticUtility('self-end', [['align-self', 'flex-end']]) staticUtility('self-center', [['align-self', 'center']]) - if (enableSafeAlignment) { - staticUtility('self-end-safe', [['align-self', 'safe flex-end']]) - staticUtility('self-center-safe', [['align-self', 'safe center']]) - } + staticUtility('self-end-safe', [['align-self', 'safe flex-end']]) + staticUtility('self-center-safe', [['align-self', 'safe center']]) staticUtility('self-stretch', [['align-self', 'stretch']]) staticUtility('self-baseline', [['align-self', 'baseline']]) - if (enableBaselineLast) { - staticUtility('self-baseline-last', [['align-self', 'last baseline']]) - } + staticUtility('self-baseline-last', [['align-self', 'last baseline']]) staticUtility('justify-self-auto', [['justify-self', 'auto']]) staticUtility('justify-self-start', [['justify-self', 'flex-start']]) staticUtility('justify-self-end', [['justify-self', 'flex-end']]) staticUtility('justify-self-center', [['justify-self', 'center']]) - if (enableSafeAlignment) { - staticUtility('justify-self-end-safe', [['justify-self', 'safe flex-end']]) - staticUtility('justify-self-center-safe', [['justify-self', 'safe center']]) - } + staticUtility('justify-self-end-safe', [['justify-self', 'safe flex-end']]) + staticUtility('justify-self-center-safe', [['justify-self', 'safe center']]) staticUtility('justify-self-stretch', [['justify-self', 'stretch']]) for (let value of ['auto', 'hidden', 'clip', 'visible', 'scroll']) { @@ -2108,11 +2079,9 @@ export function createUtilities(theme: Theme) { staticUtility('break-all', [['word-break', 'break-all']]) staticUtility('break-keep', [['word-break', 'keep-all']]) - if (enableWrapAnywhere) { - staticUtility('wrap-anywhere', [['overflow-wrap', 'anywhere']]) - staticUtility('wrap-break-word', [['overflow-wrap', 'break-word']]) - staticUtility('wrap-normal', [['overflow-wrap', 'normal']]) - } + staticUtility('wrap-anywhere', [['overflow-wrap', 'anywhere']]) + staticUtility('wrap-break-word', [['overflow-wrap', 'break-word']]) + staticUtility('wrap-normal', [['overflow-wrap', 'normal']]) { // border-radius @@ -2827,508 +2796,501 @@ export function createUtilities(theme: Theme) { position: (value) => [gradientStopProperties(), decl('--tw-gradient-to-position', value)], }) - if (enableMaskUtilities) { - /** - * @css `mask-image` - */ + /** + * @css `mask-image` + */ - staticUtility('mask-none', [['mask-image', 'none']]) + staticUtility('mask-none', [['mask-image', 'none']]) - utilities.functional('mask', (candidate) => { + utilities.functional('mask', (candidate) => { + if (!candidate.value) return + if (candidate.modifier) return + if (candidate.value.kind !== 'arbitrary') return + + // Arbitrary values + let value: string | null = candidate.value.value + let type = + candidate.value.dataType ?? + inferDataType(value, ['image', 'percentage', 'position', 'bg-size', 'length', 'url']) + + switch (type) { + case 'percentage': + case 'position': { + if (candidate.modifier) return + return [decl('mask-position', value)] + } + case 'bg-size': + case 'length': + case 'size': { + return [decl('mask-size', value)] + } + case 'image': + case 'url': + default: { + return [decl('mask-image', value)] + } + } + }) + + /** + * @css `mask-composite` + */ + + staticUtility('mask-add', [['mask-composite', 'add']]) + staticUtility('mask-subtract', [['mask-composite', 'subtract']]) + staticUtility('mask-intersect', [['mask-composite', 'intersect']]) + staticUtility('mask-exclude', [['mask-composite', 'exclude']]) + + /** + * @css `mask-mode` + * + * Sets the "mode" of the mask given by mask-image + */ + + staticUtility('mask-alpha', [['mask-mode', 'alpha']]) + staticUtility('mask-luminance', [['mask-mode', 'luminance']]) + staticUtility('mask-match', [['mask-mode', 'match-source']]) + + /** + * @css `mask-type` + * + * Sets the "mode" of the current `` element + * Is overridden by `mask-mode` if used + */ + staticUtility('mask-type-alpha', [['mask-type', 'alpha']]) + staticUtility('mask-type-luminance', [['mask-type', 'luminance']]) + + /** + * @css `mask-size` + */ + + staticUtility('mask-auto', [['mask-size', 'auto']]) + staticUtility('mask-cover', [['mask-size', 'cover']]) + staticUtility('mask-contain', [['mask-size', 'contain']]) + functionalUtility('mask-size', { + handle(value) { + if (!value) return + return [decl('mask-size', value)] + }, + }) + + /** + * @css `mask-position` + */ + + staticUtility('mask-top', [['mask-position', 'top']]) + staticUtility('mask-top-left', [['mask-position', 'left top']]) + staticUtility('mask-top-right', [['mask-position', 'right top']]) + staticUtility('mask-bottom', [['mask-position', 'bottom']]) + staticUtility('mask-bottom-left', [['mask-position', 'left bottom']]) + staticUtility('mask-bottom-right', [['mask-position', 'right bottom']]) + staticUtility('mask-left', [['mask-position', 'left']]) + staticUtility('mask-right', [['mask-position', 'right']]) + staticUtility('mask-center', [['mask-position', 'center']]) + functionalUtility('mask-position', { + handle(value) { + if (!value) return + return [decl('mask-position', value)] + }, + }) + + /** + * @css `mask-repeat` + */ + + staticUtility('mask-repeat', [['mask-repeat', 'repeat']]) + staticUtility('mask-no-repeat', [['mask-repeat', 'no-repeat']]) + staticUtility('mask-repeat-x', [['mask-repeat', 'repeat-x']]) + staticUtility('mask-repeat-y', [['mask-repeat', 'repeat-y']]) + staticUtility('mask-repeat-round', [['mask-repeat', 'round']]) + staticUtility('mask-repeat-space', [['mask-repeat', 'space']]) + + /** + * @css `mask-clip` + */ + + staticUtility('mask-clip-border', [['mask-clip', 'border-box']]) + staticUtility('mask-clip-padding', [['mask-clip', 'padding-box']]) + staticUtility('mask-clip-content', [['mask-clip', 'content-box']]) + staticUtility('mask-clip-fill', [['mask-clip', 'fill-box']]) + staticUtility('mask-clip-stroke', [['mask-clip', 'stroke-box']]) + staticUtility('mask-clip-view', [['mask-clip', 'view-box']]) + staticUtility('mask-no-clip', [['mask-clip', 'no-clip']]) + + /** + * @css `mask-origin` + */ + + staticUtility('mask-origin-border', [['mask-origin', 'border-box']]) + staticUtility('mask-origin-padding', [['mask-origin', 'padding-box']]) + staticUtility('mask-origin-content', [['mask-origin', 'content-box']]) + staticUtility('mask-origin-fill', [['mask-origin', 'fill-box']]) + staticUtility('mask-origin-stroke', [['mask-origin', 'stroke-box']]) + staticUtility('mask-origin-view', [['mask-origin', 'view-box']]) + + /** + * @css `mask-image` gradients + */ + + let maskPropertiesGradient = () => + atRoot([ + property('--tw-mask-linear', 'linear-gradient(#fff, #fff)'), + property('--tw-mask-radial', 'linear-gradient(#fff, #fff)'), + property('--tw-mask-conic', 'linear-gradient(#fff, #fff)'), + ]) + + type MaskStopDescription = { + color: (value: string) => AstNode[] | undefined + position: (value: string) => AstNode[] | undefined + } + + function maskStopUtility(classRoot: string, desc: MaskStopDescription) { + utilities.functional(classRoot, (candidate) => { if (!candidate.value) return - if (candidate.modifier) return - if (candidate.value.kind !== 'arbitrary') return // Arbitrary values - let value: string | null = candidate.value.value - let type = - candidate.value.dataType ?? - inferDataType(value, ['image', 'percentage', 'position', 'bg-size', 'length', 'url']) + if (candidate.value.kind === 'arbitrary') { + let value: string | null = candidate.value.value + let type = + candidate.value.dataType ?? inferDataType(value, ['length', 'percentage', 'color']) - switch (type) { - case 'percentage': - case 'position': { - if (candidate.modifier) return - return [decl('mask-position', value)] + switch (type) { + case 'color': { + value = asColor(value, candidate.modifier, theme) + if (value === null) return + + return desc.color(value) + } + case 'percentage': { + if (candidate.modifier) return + if (!isPositiveInteger(value.slice(0, -1))) return + + return desc.position(value) + } + default: { + if (candidate.modifier) return + + return desc.position(value) + } } - case 'bg-size': - case 'length': - case 'size': { - return [decl('mask-size', value)] + } + + // Known values: Color Stops + { + let value = resolveThemeColor(candidate, theme, ['--background-color', '--color']) + if (value) { + return desc.color(value) } - case 'image': - case 'url': - default: { - return [decl('mask-image', value)] + } + + // Known values: Positions + { + if (candidate.modifier) return + + let type = inferDataType(candidate.value.value, ['number', 'percentage']) + if (!type) return + + switch (type) { + case 'number': { + let multiplier = theme.resolve(null, ['--spacing']) + if (!multiplier) return + if (!isValidSpacingMultiplier(candidate.value.value)) return + + return desc.position(`calc(${multiplier} * ${candidate.value.value})`) + } + + case 'percentage': { + if (!isPositiveInteger(candidate.value.value.slice(0, -1))) return + return desc.position(candidate.value.value) + } + + default: { + return + } } } }) - /** - * @css `mask-composite` - */ - - staticUtility('mask-add', [['mask-composite', 'add']]) - staticUtility('mask-subtract', [['mask-composite', 'subtract']]) - staticUtility('mask-intersect', [['mask-composite', 'intersect']]) - staticUtility('mask-exclude', [['mask-composite', 'exclude']]) - - /** - * @css `mask-mode` - * - * Sets the "mode" of the mask given by mask-image - */ - - staticUtility('mask-alpha', [['mask-mode', 'alpha']]) - staticUtility('mask-luminance', [['mask-mode', 'luminance']]) - staticUtility('mask-match', [['mask-mode', 'match-source']]) - - /** - * @css `mask-type` - * - * Sets the "mode" of the current `` element - * Is overridden by `mask-mode` if used - */ - staticUtility('mask-type-alpha', [['mask-type', 'alpha']]) - staticUtility('mask-type-luminance', [['mask-type', 'luminance']]) - - /** - * @css `mask-size` - */ - - staticUtility('mask-auto', [['mask-size', 'auto']]) - staticUtility('mask-cover', [['mask-size', 'cover']]) - staticUtility('mask-contain', [['mask-size', 'contain']]) - functionalUtility('mask-size', { - handle(value) { - if (!value) return - return [decl('mask-size', value)] - }, - }) - - /** - * @css `mask-position` - */ - - staticUtility('mask-top', [['mask-position', 'top']]) - staticUtility('mask-top-left', [['mask-position', 'left top']]) - staticUtility('mask-top-right', [['mask-position', 'right top']]) - staticUtility('mask-bottom', [['mask-position', 'bottom']]) - staticUtility('mask-bottom-left', [['mask-position', 'left bottom']]) - staticUtility('mask-bottom-right', [['mask-position', 'right bottom']]) - staticUtility('mask-left', [['mask-position', 'left']]) - staticUtility('mask-right', [['mask-position', 'right']]) - staticUtility('mask-center', [['mask-position', 'center']]) - functionalUtility('mask-position', { - handle(value) { - if (!value) return - return [decl('mask-position', value)] - }, - }) - - /** - * @css `mask-repeat` - */ - - staticUtility('mask-repeat', [['mask-repeat', 'repeat']]) - staticUtility('mask-no-repeat', [['mask-repeat', 'no-repeat']]) - staticUtility('mask-repeat-x', [['mask-repeat', 'repeat-x']]) - staticUtility('mask-repeat-y', [['mask-repeat', 'repeat-y']]) - staticUtility('mask-repeat-round', [['mask-repeat', 'round']]) - staticUtility('mask-repeat-space', [['mask-repeat', 'space']]) - - /** - * @css `mask-clip` - */ - - staticUtility('mask-clip-border', [['mask-clip', 'border-box']]) - staticUtility('mask-clip-padding', [['mask-clip', 'padding-box']]) - staticUtility('mask-clip-content', [['mask-clip', 'content-box']]) - staticUtility('mask-clip-fill', [['mask-clip', 'fill-box']]) - staticUtility('mask-clip-stroke', [['mask-clip', 'stroke-box']]) - staticUtility('mask-clip-view', [['mask-clip', 'view-box']]) - staticUtility('mask-no-clip', [['mask-clip', 'no-clip']]) - - /** - * @css `mask-origin` - */ - - staticUtility('mask-origin-border', [['mask-origin', 'border-box']]) - staticUtility('mask-origin-padding', [['mask-origin', 'padding-box']]) - staticUtility('mask-origin-content', [['mask-origin', 'content-box']]) - staticUtility('mask-origin-fill', [['mask-origin', 'fill-box']]) - staticUtility('mask-origin-stroke', [['mask-origin', 'stroke-box']]) - staticUtility('mask-origin-view', [['mask-origin', 'view-box']]) - - /** - * @css `mask-image` gradients - */ - - let maskPropertiesGradient = () => - atRoot([ - property('--tw-mask-linear', 'linear-gradient(#fff, #fff)'), - property('--tw-mask-radial', 'linear-gradient(#fff, #fff)'), - property('--tw-mask-conic', 'linear-gradient(#fff, #fff)'), - ]) - - type MaskStopDescription = { - color: (value: string) => AstNode[] | undefined - position: (value: string) => AstNode[] | undefined - } - - function maskStopUtility(classRoot: string, desc: MaskStopDescription) { - utilities.functional(classRoot, (candidate) => { - if (!candidate.value) return - - // Arbitrary values - if (candidate.value.kind === 'arbitrary') { - let value: string | null = candidate.value.value - let type = - candidate.value.dataType ?? inferDataType(value, ['length', 'percentage', 'color']) - - switch (type) { - case 'color': { - value = asColor(value, candidate.modifier, theme) - if (value === null) return - - return desc.color(value) - } - case 'percentage': { - if (candidate.modifier) return - if (!isPositiveInteger(value.slice(0, -1))) return - - return desc.position(value) - } - default: { - if (candidate.modifier) return - - return desc.position(value) - } - } - } - - // Known values: Color Stops - { - let value = resolveThemeColor(candidate, theme, ['--background-color', '--color']) - if (value) { - return desc.color(value) - } - } - - // Known values: Positions - { - if (candidate.modifier) return - - let type = inferDataType(candidate.value.value, ['number', 'percentage']) - if (!type) return - - switch (type) { - case 'number': { - let multiplier = theme.resolve(null, ['--spacing']) - if (!multiplier) return - if (!isValidSpacingMultiplier(candidate.value.value)) return - - return desc.position(`calc(${multiplier} * ${candidate.value.value})`) - } - - case 'percentage': { - if (!isPositiveInteger(candidate.value.value.slice(0, -1))) return - return desc.position(candidate.value.value) - } - - default: { - return - } - } - } - }) - - suggest(classRoot, () => [ - { - values: ['current', 'inherit', 'transparent'], - valueThemeKeys: ['--background-color', '--color'], - modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), - }, - { - values: Array.from({ length: 21 }, (_, index) => `${index * 5}%`), - valueThemeKeys: ['--gradient-color-stop-positions'], - }, - ]) - - suggest(classRoot, () => [ - // Percentages - { - values: Array.from({ length: 21 }, (_, index) => `${index * 5}%`), - }, - - // Spacing Scale - { - values: theme.get(['--spacing']) ? DEFAULT_SPACING_SUGGESTIONS : [], - }, - - // Colors - { - values: ['current', 'inherit', 'transparent'], - valueThemeKeys: ['--background-color', '--color'], - modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), - }, - ]) - } - - /** - * Edge masks - */ - - let maskPropertiesEdge = () => - atRoot([ - property('--tw-mask-left', 'linear-gradient(#fff, #fff)'), - property('--tw-mask-right', 'linear-gradient(#fff, #fff)'), - property('--tw-mask-bottom', 'linear-gradient(#fff, #fff)'), - property('--tw-mask-top', 'linear-gradient(#fff, #fff)'), - ]) - - type MaskEdge = 'top' | 'right' | 'bottom' | 'left' - type MaskStop = 'from' | 'to' - - function maskEdgeUtility(name: string, stop: MaskStop, edges: Record) { - maskStopUtility(name, { - color(value) { - let nodes: AstNode[] = [ - // Common @property declarations - maskPropertiesGradient(), - maskPropertiesEdge(), - - // Common properties to all edge utilities - decl( - 'mask-image', - 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)', - ), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear', - 'var(--tw-mask-left), var(--tw-mask-right), var(--tw-mask-bottom), var(--tw-mask-top)', - ), - ] - - for (let edge of ['top', 'right', 'bottom', 'left'] as const) { - if (!edges[edge]) continue - - nodes.push( - decl( - `--tw-mask-${edge}`, - `linear-gradient(to ${edge}, var(--tw-mask-${edge}-from-color) var(--tw-mask-${edge}-from-position), var(--tw-mask-${edge}-to-color) var(--tw-mask-${edge}-to-position))`, - ), - ) - - nodes.push( - atRoot([ - property(`--tw-mask-${edge}-from-position`, '0%'), - property(`--tw-mask-${edge}-to-position`, '100%'), - property(`--tw-mask-${edge}-from-color`, 'black'), - property(`--tw-mask-${edge}-to-color`, 'transparent'), - ]), - ) - - nodes.push(decl(`--tw-mask-${edge}-${stop}-color`, value)) - } - - return nodes - }, - position(value) { - let nodes: AstNode[] = [ - // Common @property declarations - maskPropertiesGradient(), - maskPropertiesEdge(), - - // Common properties to all edge utilities - decl( - 'mask-image', - 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)', - ), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear', - 'var(--tw-mask-left), var(--tw-mask-right), var(--tw-mask-bottom), var(--tw-mask-top)', - ), - ] - - for (let edge of ['top', 'right', 'bottom', 'left'] as const) { - if (!edges[edge]) continue - - nodes.push( - decl( - `--tw-mask-${edge}`, - `linear-gradient(to ${edge}, var(--tw-mask-${edge}-from-color) var(--tw-mask-${edge}-from-position), var(--tw-mask-${edge}-to-color) var(--tw-mask-${edge}-to-position))`, - ), - ) - - nodes.push( - atRoot([ - property(`--tw-mask-${edge}-from-position`, '0%'), - property(`--tw-mask-${edge}-to-position`, '100%'), - property(`--tw-mask-${edge}-from-color`, 'black'), - property(`--tw-mask-${edge}-to-color`, 'transparent'), - ]), - ) - - nodes.push(decl(`--tw-mask-${edge}-${stop}-position`, value)) - } - - return nodes - }, - }) - } - - maskEdgeUtility('mask-x-from', 'from', { top: false, right: true, bottom: false, left: true }) - maskEdgeUtility('mask-x-to', 'to', { top: false, right: true, bottom: false, left: true }) - maskEdgeUtility('mask-y-from', 'from', { top: true, right: false, bottom: true, left: false }) - maskEdgeUtility('mask-y-to', 'to', { top: true, right: false, bottom: true, left: false }) - maskEdgeUtility('mask-t-from', 'from', { top: true, right: false, bottom: false, left: false }) - maskEdgeUtility('mask-t-to', 'to', { top: true, right: false, bottom: false, left: false }) - maskEdgeUtility('mask-r-from', 'from', { top: false, right: true, bottom: false, left: false }) - maskEdgeUtility('mask-r-to', 'to', { top: false, right: true, bottom: false, left: false }) - maskEdgeUtility('mask-b-from', 'from', { top: false, right: false, bottom: true, left: false }) - maskEdgeUtility('mask-b-to', 'to', { top: false, right: false, bottom: true, left: false }) - maskEdgeUtility('mask-l-from', 'from', { top: false, right: false, bottom: false, left: true }) - maskEdgeUtility('mask-l-to', 'to', { top: false, right: false, bottom: false, left: true }) - - /** - * Linear Masks - */ - - let maskPropertiesLinear = () => - atRoot([ - property('--tw-mask-linear-position', '0deg'), - property('--tw-mask-linear-from-position', '0%'), - property('--tw-mask-linear-to-position', '100%'), - property('--tw-mask-linear-from-color', 'black'), - property('--tw-mask-linear-to-color', 'transparent'), - ]) - - functionalUtility('mask-linear', { - defaultValue: null, - supportsNegative: true, - supportsFractions: false, - handleBareValue(value) { - if (!isPositiveInteger(value.value)) return null - return `calc(1deg * ${value.value})` - }, - handleNegativeBareValue(value) { - if (!isPositiveInteger(value.value)) return null - return `calc(1deg * -${value.value})` - }, - handle: (value) => [ - maskPropertiesGradient(), - maskPropertiesLinear(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear', - `linear-gradient(var(--tw-mask-linear-stops, var(--tw-mask-linear-position)))`, - ), - decl('--tw-mask-linear-position', value), - ], - }) - - suggest('mask-linear', () => [ + suggest(classRoot, () => [ { - supportsNegative: true, - values: ['0', '1', '2', '3', '6', '12', '45', '90', '180'], + values: ['current', 'inherit', 'transparent'], + valueThemeKeys: ['--background-color', '--color'], + modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), + }, + { + values: Array.from({ length: 21 }, (_, index) => `${index * 5}%`), + valueThemeKeys: ['--gradient-color-stop-positions'], }, ]) - maskStopUtility('mask-linear-from', { - color: (value) => [ - maskPropertiesGradient(), - maskPropertiesLinear(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear-stops', - 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', - ), - decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), - decl('--tw-mask-linear-from-color', value), - ], - position: (value) => [ - maskPropertiesGradient(), - maskPropertiesLinear(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear-stops', - 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', - ), - decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), - decl('--tw-mask-linear-from-position', value), - ], + suggest(classRoot, () => [ + // Percentages + { + values: Array.from({ length: 21 }, (_, index) => `${index * 5}%`), + }, + + // Spacing Scale + { + values: theme.get(['--spacing']) ? DEFAULT_SPACING_SUGGESTIONS : [], + }, + + // Colors + { + values: ['current', 'inherit', 'transparent'], + valueThemeKeys: ['--background-color', '--color'], + modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), + }, + ]) + } + + /** + * Edge masks + */ + + let maskPropertiesEdge = () => + atRoot([ + property('--tw-mask-left', 'linear-gradient(#fff, #fff)'), + property('--tw-mask-right', 'linear-gradient(#fff, #fff)'), + property('--tw-mask-bottom', 'linear-gradient(#fff, #fff)'), + property('--tw-mask-top', 'linear-gradient(#fff, #fff)'), + ]) + + type MaskEdge = 'top' | 'right' | 'bottom' | 'left' + type MaskStop = 'from' | 'to' + + function maskEdgeUtility(name: string, stop: MaskStop, edges: Record) { + maskStopUtility(name, { + color(value) { + let nodes: AstNode[] = [ + // Common @property declarations + maskPropertiesGradient(), + maskPropertiesEdge(), + + // Common properties to all edge utilities + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear', + 'var(--tw-mask-left), var(--tw-mask-right), var(--tw-mask-bottom), var(--tw-mask-top)', + ), + ] + + for (let edge of ['top', 'right', 'bottom', 'left'] as const) { + if (!edges[edge]) continue + + nodes.push( + decl( + `--tw-mask-${edge}`, + `linear-gradient(to ${edge}, var(--tw-mask-${edge}-from-color) var(--tw-mask-${edge}-from-position), var(--tw-mask-${edge}-to-color) var(--tw-mask-${edge}-to-position))`, + ), + ) + + nodes.push( + atRoot([ + property(`--tw-mask-${edge}-from-position`, '0%'), + property(`--tw-mask-${edge}-to-position`, '100%'), + property(`--tw-mask-${edge}-from-color`, 'black'), + property(`--tw-mask-${edge}-to-color`, 'transparent'), + ]), + ) + + nodes.push(decl(`--tw-mask-${edge}-${stop}-color`, value)) + } + + return nodes + }, + position(value) { + let nodes: AstNode[] = [ + // Common @property declarations + maskPropertiesGradient(), + maskPropertiesEdge(), + + // Common properties to all edge utilities + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear', + 'var(--tw-mask-left), var(--tw-mask-right), var(--tw-mask-bottom), var(--tw-mask-top)', + ), + ] + + for (let edge of ['top', 'right', 'bottom', 'left'] as const) { + if (!edges[edge]) continue + + nodes.push( + decl( + `--tw-mask-${edge}`, + `linear-gradient(to ${edge}, var(--tw-mask-${edge}-from-color) var(--tw-mask-${edge}-from-position), var(--tw-mask-${edge}-to-color) var(--tw-mask-${edge}-to-position))`, + ), + ) + + nodes.push( + atRoot([ + property(`--tw-mask-${edge}-from-position`, '0%'), + property(`--tw-mask-${edge}-to-position`, '100%'), + property(`--tw-mask-${edge}-from-color`, 'black'), + property(`--tw-mask-${edge}-to-color`, 'transparent'), + ]), + ) + + nodes.push(decl(`--tw-mask-${edge}-${stop}-position`, value)) + } + + return nodes + }, }) + } - maskStopUtility('mask-linear-to', { - color: (value) => [ - maskPropertiesGradient(), - maskPropertiesLinear(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear-stops', - 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', - ), - decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), - decl('--tw-mask-linear-to-color', value), - ], - position: (value) => [ - maskPropertiesGradient(), - maskPropertiesLinear(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-linear-stops', - 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', - ), - decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), - decl('--tw-mask-linear-to-position', value), - ], - }) + maskEdgeUtility('mask-x-from', 'from', { top: false, right: true, bottom: false, left: true }) + maskEdgeUtility('mask-x-to', 'to', { top: false, right: true, bottom: false, left: true }) + maskEdgeUtility('mask-y-from', 'from', { top: true, right: false, bottom: true, left: false }) + maskEdgeUtility('mask-y-to', 'to', { top: true, right: false, bottom: true, left: false }) + maskEdgeUtility('mask-t-from', 'from', { top: true, right: false, bottom: false, left: false }) + maskEdgeUtility('mask-t-to', 'to', { top: true, right: false, bottom: false, left: false }) + maskEdgeUtility('mask-r-from', 'from', { top: false, right: true, bottom: false, left: false }) + maskEdgeUtility('mask-r-to', 'to', { top: false, right: true, bottom: false, left: false }) + maskEdgeUtility('mask-b-from', 'from', { top: false, right: false, bottom: true, left: false }) + maskEdgeUtility('mask-b-to', 'to', { top: false, right: false, bottom: true, left: false }) + maskEdgeUtility('mask-l-from', 'from', { top: false, right: false, bottom: false, left: true }) + maskEdgeUtility('mask-l-to', 'to', { top: false, right: false, bottom: false, left: true }) - /** - * Radial masks - */ + /** + * Linear Masks + */ - let maskPropertiesRadial = () => - atRoot([ - property('--tw-mask-radial-from-position', '0%'), - property('--tw-mask-radial-to-position', '100%'), - property('--tw-mask-radial-from-color', 'black'), - property('--tw-mask-radial-to-color', 'transparent'), - property('--tw-mask-radial-shape', 'ellipse'), - property('--tw-mask-radial-size', 'farthest-corner'), - property('--tw-mask-radial-position', 'center'), - ]) + let maskPropertiesLinear = () => + atRoot([ + property('--tw-mask-linear-position', '0deg'), + property('--tw-mask-linear-from-position', '0%'), + property('--tw-mask-linear-to-position', '100%'), + property('--tw-mask-linear-from-color', 'black'), + property('--tw-mask-linear-to-color', 'transparent'), + ]) - staticUtility('mask-circle', [['--tw-mask-radial-shape', 'circle']]) - staticUtility('mask-ellipse', [['--tw-mask-radial-shape', 'ellipse']]) - staticUtility('mask-radial-closest-side', [['--tw-mask-radial-size', 'closest-side']]) - staticUtility('mask-radial-farthest-side', [['--tw-mask-radial-size', 'farthest-side']]) - staticUtility('mask-radial-closest-corner', [['--tw-mask-radial-size', 'closest-corner']]) - staticUtility('mask-radial-farthest-corner', [['--tw-mask-radial-size', 'farthest-corner']]) - staticUtility('mask-radial-at-top', [['--tw-mask-radial-position', 'top']]) - staticUtility('mask-radial-at-top-left', [['--tw-mask-radial-position', 'top left']]) - staticUtility('mask-radial-at-top-right', [['--tw-mask-radial-position', 'top right']]) - staticUtility('mask-radial-at-bottom', [['--tw-mask-radial-position', 'bottom']]) - staticUtility('mask-radial-at-bottom-left', [['--tw-mask-radial-position', 'bottom left']]) - staticUtility('mask-radial-at-bottom-right', [['--tw-mask-radial-position', 'bottom right']]) - staticUtility('mask-radial-at-left', [['--tw-mask-radial-position', 'left']]) - staticUtility('mask-radial-at-right', [['--tw-mask-radial-position', 'right']]) - staticUtility('mask-radial-at-center', [['--tw-mask-radial-position', 'center']]) - functionalUtility('mask-radial-at', { - defaultValue: null, - supportsNegative: false, - supportsFractions: false, - handle: (value) => [decl('--tw-mask-radial-position', value)], - }) + functionalUtility('mask-linear', { + defaultValue: null, + supportsNegative: true, + supportsFractions: false, + handleBareValue(value) { + if (!isPositiveInteger(value.value)) return null + return `calc(1deg * ${value.value})` + }, + handleNegativeBareValue(value) { + if (!isPositiveInteger(value.value)) return null + return `calc(1deg * -${value.value})` + }, + handle: (value) => [ + maskPropertiesGradient(), + maskPropertiesLinear(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear', + `linear-gradient(var(--tw-mask-linear-stops, var(--tw-mask-linear-position)))`, + ), + decl('--tw-mask-linear-position', value), + ], + }) - /* + suggest('mask-linear', () => [ + { + supportsNegative: true, + values: ['0', '1', '2', '3', '6', '12', '45', '90', '180'], + }, + ]) + + maskStopUtility('mask-linear-from', { + color: (value) => [ + maskPropertiesGradient(), + maskPropertiesLinear(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear-stops', + 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', + ), + decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), + decl('--tw-mask-linear-from-color', value), + ], + position: (value) => [ + maskPropertiesGradient(), + maskPropertiesLinear(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear-stops', + 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', + ), + decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), + decl('--tw-mask-linear-from-position', value), + ], + }) + + maskStopUtility('mask-linear-to', { + color: (value) => [ + maskPropertiesGradient(), + maskPropertiesLinear(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear-stops', + 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', + ), + decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), + decl('--tw-mask-linear-to-color', value), + ], + position: (value) => [ + maskPropertiesGradient(), + maskPropertiesLinear(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-linear-stops', + 'var(--tw-mask-linear-position), var(--tw-mask-linear-from-color) var(--tw-mask-linear-from-position), var(--tw-mask-linear-to-color) var(--tw-mask-linear-to-position)', + ), + decl('--tw-mask-linear', 'linear-gradient(var(--tw-mask-linear-stops))'), + decl('--tw-mask-linear-to-position', value), + ], + }) + + /** + * Radial masks + */ + + let maskPropertiesRadial = () => + atRoot([ + property('--tw-mask-radial-from-position', '0%'), + property('--tw-mask-radial-to-position', '100%'), + property('--tw-mask-radial-from-color', 'black'), + property('--tw-mask-radial-to-color', 'transparent'), + property('--tw-mask-radial-shape', 'ellipse'), + property('--tw-mask-radial-size', 'farthest-corner'), + property('--tw-mask-radial-position', 'center'), + ]) + + staticUtility('mask-circle', [['--tw-mask-radial-shape', 'circle']]) + staticUtility('mask-ellipse', [['--tw-mask-radial-shape', 'ellipse']]) + staticUtility('mask-radial-closest-side', [['--tw-mask-radial-size', 'closest-side']]) + staticUtility('mask-radial-farthest-side', [['--tw-mask-radial-size', 'farthest-side']]) + staticUtility('mask-radial-closest-corner', [['--tw-mask-radial-size', 'closest-corner']]) + staticUtility('mask-radial-farthest-corner', [['--tw-mask-radial-size', 'farthest-corner']]) + staticUtility('mask-radial-at-top', [['--tw-mask-radial-position', 'top']]) + staticUtility('mask-radial-at-top-left', [['--tw-mask-radial-position', 'top left']]) + staticUtility('mask-radial-at-top-right', [['--tw-mask-radial-position', 'top right']]) + staticUtility('mask-radial-at-bottom', [['--tw-mask-radial-position', 'bottom']]) + staticUtility('mask-radial-at-bottom-left', [['--tw-mask-radial-position', 'bottom left']]) + staticUtility('mask-radial-at-bottom-right', [['--tw-mask-radial-position', 'bottom right']]) + staticUtility('mask-radial-at-left', [['--tw-mask-radial-position', 'left']]) + staticUtility('mask-radial-at-right', [['--tw-mask-radial-position', 'right']]) + staticUtility('mask-radial-at-center', [['--tw-mask-radial-position', 'center']]) + functionalUtility('mask-radial-at', { + defaultValue: null, + supportsNegative: false, + supportsFractions: false, + handle: (value) => [decl('--tw-mask-radial-position', value)], + }) + + /* This can be used to set just the size in conjunction with `mask-radial-from-*` et al, or can set the whole gradient if it's the only utility you use. @@ -3339,176 +3301,175 @@ export function createUtilities(theme: Theme) { This will produce nonsense though and break, which is fine: `mask-radial-[96px_at_top,black_40%,transparent_80%,black_90%] mask-radial-from-50%` */ - functionalUtility('mask-radial', { - defaultValue: null, - supportsNegative: false, - supportsFractions: false, - handle: (value) => [ - maskPropertiesGradient(), - maskPropertiesRadial(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-radial', - 'radial-gradient(var(--tw-mask-radial-stops, var(--tw-mask-radial-size)))', - ), - decl('--tw-mask-radial-size', value), - ], - }) + functionalUtility('mask-radial', { + defaultValue: null, + supportsNegative: false, + supportsFractions: false, + handle: (value) => [ + maskPropertiesGradient(), + maskPropertiesRadial(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-radial', + 'radial-gradient(var(--tw-mask-radial-stops, var(--tw-mask-radial-size)))', + ), + decl('--tw-mask-radial-size', value), + ], + }) - maskStopUtility('mask-radial-from', { - color: (value) => [ - maskPropertiesGradient(), - maskPropertiesRadial(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-radial-stops', - 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', - ), - decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), - decl('--tw-mask-radial-from-color', value), - ], - position: (value) => [ - maskPropertiesGradient(), - maskPropertiesRadial(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-radial-stops', - 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', - ), - decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), - decl('--tw-mask-radial-from-position', value), - ], - }) + maskStopUtility('mask-radial-from', { + color: (value) => [ + maskPropertiesGradient(), + maskPropertiesRadial(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-radial-stops', + 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', + ), + decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), + decl('--tw-mask-radial-from-color', value), + ], + position: (value) => [ + maskPropertiesGradient(), + maskPropertiesRadial(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-radial-stops', + 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', + ), + decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), + decl('--tw-mask-radial-from-position', value), + ], + }) - maskStopUtility('mask-radial-to', { - color: (value) => [ - maskPropertiesGradient(), - maskPropertiesRadial(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-radial-stops', - 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', - ), - decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), - decl('--tw-mask-radial-to-color', value), - ], - position: (value) => [ - maskPropertiesGradient(), - maskPropertiesRadial(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-radial-stops', - 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', - ), - decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), - decl('--tw-mask-radial-to-position', value), - ], - }) + maskStopUtility('mask-radial-to', { + color: (value) => [ + maskPropertiesGradient(), + maskPropertiesRadial(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-radial-stops', + 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', + ), + decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), + decl('--tw-mask-radial-to-color', value), + ], + position: (value) => [ + maskPropertiesGradient(), + maskPropertiesRadial(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-radial-stops', + 'var(--tw-mask-radial-shape) var(--tw-mask-radial-size) at var(--tw-mask-radial-position), var(--tw-mask-radial-from-color) var(--tw-mask-radial-from-position), var(--tw-mask-radial-to-color) var(--tw-mask-radial-to-position)', + ), + decl('--tw-mask-radial', 'radial-gradient(var(--tw-mask-radial-stops))'), + decl('--tw-mask-radial-to-position', value), + ], + }) - /** - * Conic masks - */ + /** + * Conic masks + */ - let maskPropertiesConic = () => - atRoot([ - property('--tw-mask-conic-position', '0deg'), - property('--tw-mask-conic-from-position', '0%'), - property('--tw-mask-conic-to-position', '100%'), - property('--tw-mask-conic-from-color', 'black'), - property('--tw-mask-conic-to-color', 'transparent'), - ]) - - functionalUtility('mask-conic', { - defaultValue: null, - supportsNegative: true, - supportsFractions: false, - handleBareValue(value) { - if (!isPositiveInteger(value.value)) return null - return `calc(1deg * ${value.value})` - }, - handleNegativeBareValue(value) { - if (!isPositiveInteger(value.value)) return null - return `calc(1deg * -${value.value})` - }, - handle: (value) => [ - maskPropertiesGradient(), - maskPropertiesConic(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-conic', - 'conic-gradient(var(--tw-mask-conic-stops, var(--tw-mask-conic-position)))', - ), - decl('--tw-mask-conic-position', value), - ], - }) - - suggest('mask-conic', () => [ - { - supportsNegative: true, - values: ['0', '1', '2', '3', '6', '12', '45', '90', '180'], - }, + let maskPropertiesConic = () => + atRoot([ + property('--tw-mask-conic-position', '0deg'), + property('--tw-mask-conic-from-position', '0%'), + property('--tw-mask-conic-to-position', '100%'), + property('--tw-mask-conic-from-color', 'black'), + property('--tw-mask-conic-to-color', 'transparent'), ]) - maskStopUtility('mask-conic-from', { - color: (value) => [ - maskPropertiesGradient(), - maskPropertiesConic(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-conic-stops', - 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', - ), - decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), - decl('--tw-mask-conic-from-color', value), - ], - position: (value) => [ - maskPropertiesGradient(), - maskPropertiesConic(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-conic-stops', - 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', - ), - decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), - decl('--tw-mask-conic-from-position', value), - ], - }) + functionalUtility('mask-conic', { + defaultValue: null, + supportsNegative: true, + supportsFractions: false, + handleBareValue(value) { + if (!isPositiveInteger(value.value)) return null + return `calc(1deg * ${value.value})` + }, + handleNegativeBareValue(value) { + if (!isPositiveInteger(value.value)) return null + return `calc(1deg * -${value.value})` + }, + handle: (value) => [ + maskPropertiesGradient(), + maskPropertiesConic(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-conic', + 'conic-gradient(var(--tw-mask-conic-stops, var(--tw-mask-conic-position)))', + ), + decl('--tw-mask-conic-position', value), + ], + }) - maskStopUtility('mask-conic-to', { - color: (value) => [ - maskPropertiesGradient(), - maskPropertiesConic(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-conic-stops', - 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', - ), - decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), - decl('--tw-mask-conic-to-color', value), - ], - position: (value) => [ - maskPropertiesGradient(), - maskPropertiesConic(), - decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), - decl('mask-composite', 'intersect'), - decl( - '--tw-mask-conic-stops', - 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', - ), - decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), - decl('--tw-mask-conic-to-position', value), - ], - }) - } + suggest('mask-conic', () => [ + { + supportsNegative: true, + values: ['0', '1', '2', '3', '6', '12', '45', '90', '180'], + }, + ]) + + maskStopUtility('mask-conic-from', { + color: (value) => [ + maskPropertiesGradient(), + maskPropertiesConic(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-conic-stops', + 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', + ), + decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), + decl('--tw-mask-conic-from-color', value), + ], + position: (value) => [ + maskPropertiesGradient(), + maskPropertiesConic(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-conic-stops', + 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', + ), + decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), + decl('--tw-mask-conic-from-position', value), + ], + }) + + maskStopUtility('mask-conic-to', { + color: (value) => [ + maskPropertiesGradient(), + maskPropertiesConic(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-conic-stops', + 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', + ), + decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), + decl('--tw-mask-conic-to-color', value), + ], + position: (value) => [ + maskPropertiesGradient(), + maskPropertiesConic(), + decl('mask-image', 'var(--tw-mask-linear), var(--tw-mask-radial), var(--tw-mask-conic)'), + decl('mask-composite', 'intersect'), + decl( + '--tw-mask-conic-stops', + 'from var(--tw-mask-conic-position), var(--tw-mask-conic-from-color) var(--tw-mask-conic-from-position), var(--tw-mask-conic-to-color) var(--tw-mask-conic-to-position)', + ), + decl('--tw-mask-conic', 'conic-gradient(var(--tw-mask-conic-stops))'), + decl('--tw-mask-conic-to-position', value), + ], + }) /** * @css `box-decoration-break` @@ -5084,86 +5045,61 @@ export function createUtilities(theme: Theme) { }, ]) - if (enableTextShadows) { - let textShadowProperties = () => { - return atRoot([ - property('--tw-text-shadow-color'), - property('--tw-text-shadow-alpha', '100%', ''), - ]) + let textShadowProperties = () => { + return atRoot([ + property('--tw-text-shadow-color'), + property('--tw-text-shadow-alpha', '100%', ''), + ]) + } + + staticUtility('text-shadow-initial', [ + textShadowProperties, + ['--tw-text-shadow-color', 'initial'], + ]) + + utilities.functional('text-shadow', (candidate) => { + let alpha: string | undefined + + if (candidate.modifier) { + if (candidate.modifier.kind === 'arbitrary') { + alpha = candidate.modifier.value + } else { + if (isPositiveInteger(candidate.modifier.value)) { + alpha = `${candidate.modifier.value}%` + } + } } - staticUtility('text-shadow-initial', [ - textShadowProperties, - ['--tw-text-shadow-color', 'initial'], - ]) + if (!candidate.value) { + let value = theme.get(['--text-shadow']) + if (value === null) return - utilities.functional('text-shadow', (candidate) => { - let alpha: string | undefined + return [ + textShadowProperties(), + decl('--tw-text-shadow-alpha', alpha), + ...alphaReplacedShadowProperties( + 'text-shadow', + value, + alpha, + (color) => `var(--tw-text-shadow-color, ${color})`, + ), + ] + } - if (candidate.modifier) { - if (candidate.modifier.kind === 'arbitrary') { - alpha = candidate.modifier.value - } else { - if (isPositiveInteger(candidate.modifier.value)) { - alpha = `${candidate.modifier.value}%` - } + if (candidate.value.kind === 'arbitrary') { + let value: string | null = candidate.value.value + let type = candidate.value.dataType ?? inferDataType(value, ['color']) + + switch (type) { + case 'color': { + value = asColor(value, candidate.modifier, theme) + if (value === null) return + return [ + textShadowProperties(), + decl('--tw-text-shadow-color', withAlpha(value, 'var(--tw-text-shadow-alpha)')), + ] } - } - - if (!candidate.value) { - let value = theme.get(['--text-shadow']) - if (value === null) return - - return [ - textShadowProperties(), - decl('--tw-text-shadow-alpha', alpha), - ...alphaReplacedShadowProperties( - 'text-shadow', - value, - alpha, - (color) => `var(--tw-text-shadow-color, ${color})`, - ), - ] - } - - if (candidate.value.kind === 'arbitrary') { - let value: string | null = candidate.value.value - let type = candidate.value.dataType ?? inferDataType(value, ['color']) - - switch (type) { - case 'color': { - value = asColor(value, candidate.modifier, theme) - if (value === null) return - return [ - textShadowProperties(), - decl('--tw-text-shadow-color', withAlpha(value, 'var(--tw-text-shadow-alpha)')), - ] - } - default: { - return [ - textShadowProperties(), - decl('--tw-text-shadow-alpha', alpha), - ...alphaReplacedShadowProperties( - 'text-shadow', - value, - alpha, - (color) => `var(--tw-text-shadow-color, ${color})`, - ), - ] - } - } - } - - switch (candidate.value.value) { - case 'none': - if (candidate.modifier) return - return [textShadowProperties(), decl('text-shadow', 'none')] - } - - // Shadow size - { - let value = theme.get([`--text-shadow-${candidate.value.value}`]) - if (value) { + default: { return [ textShadowProperties(), decl('--tw-text-shadow-alpha', alpha), @@ -5176,35 +5112,58 @@ export function createUtilities(theme: Theme) { ] } } + } - // Shadow color - { - let value = resolveThemeColor(candidate, theme, ['--text-shadow-color', '--color']) - if (value) { - return [ - textShadowProperties(), - decl('--tw-text-shadow-color', withAlpha(value, 'var(--tw-text-shadow-alpha)')), - ] - } + switch (candidate.value.value) { + case 'none': + if (candidate.modifier) return + return [textShadowProperties(), decl('text-shadow', 'none')] + } + + // Shadow size + { + let value = theme.get([`--text-shadow-${candidate.value.value}`]) + if (value) { + return [ + textShadowProperties(), + decl('--tw-text-shadow-alpha', alpha), + ...alphaReplacedShadowProperties( + 'text-shadow', + value, + alpha, + (color) => `var(--tw-text-shadow-color, ${color})`, + ), + ] } - }) + } - suggest('text-shadow', () => [ - { - values: ['current', 'inherit', 'transparent'], - valueThemeKeys: ['--text-shadow-color', '--color'], - modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), - }, - { - values: ['none'], - }, - { - valueThemeKeys: ['--text-shadow'], - modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), - hasDefaultValue: true, - }, - ]) - } + // Shadow color + { + let value = resolveThemeColor(candidate, theme, ['--text-shadow-color', '--color']) + if (value) { + return [ + textShadowProperties(), + decl('--tw-text-shadow-color', withAlpha(value, 'var(--tw-text-shadow-alpha)')), + ] + } + } + }) + + suggest('text-shadow', () => [ + { + values: ['current', 'inherit', 'transparent'], + valueThemeKeys: ['--text-shadow-color', '--color'], + modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), + }, + { + values: ['none'], + }, + { + valueThemeKeys: ['--text-shadow'], + modifiers: Array.from({ length: 21 }, (_, index) => `${index * 5}`), + hasDefaultValue: true, + }, + ]) { let cssBoxShadowValue = [ diff --git a/packages/tailwindcss/src/variants.ts b/packages/tailwindcss/src/variants.ts index 7d28b7a41..701f08c0b 100644 --- a/packages/tailwindcss/src/variants.ts +++ b/packages/tailwindcss/src/variants.ts @@ -12,13 +12,6 @@ import { type StyleRule, } from './ast' import { type Variant } from './candidate' -import { - enableDetailsContent, - enableInvertedColors, - enablePointerVariants, - enableScripting, - enableUserValid, -} from './feature-flags' import type { Theme } from './theme' import { compareBreakpoints } from './utils/compare-breakpoints' import { DefaultMap } from './utils/default-map' @@ -633,9 +626,7 @@ export function createVariants(theme: Theme): Variants { staticVariant('file', ['&::file-selector-button']) staticVariant('placeholder', ['&::placeholder']) staticVariant('backdrop', ['&::backdrop']) - if (enableDetailsContent) { - staticVariant('details-content', ['&::details-content']) - } + staticVariant('details-content', ['&::details-content']) { function contentProperties() { @@ -701,10 +692,8 @@ export function createVariants(theme: Theme): Variants { staticVariant('required', ['&:required']) staticVariant('valid', ['&:valid']) staticVariant('invalid', ['&:invalid']) - if (enableUserValid) { - staticVariant('user-valid', ['&:user-valid']) - staticVariant('user-invalid', ['&:user-invalid']) - } + staticVariant('user-valid', ['&:user-valid']) + staticVariant('user-invalid', ['&:user-invalid']) staticVariant('in-range', ['&:in-range']) staticVariant('out-of-range', ['&:out-of-range']) staticVariant('read-only', ['&:read-only']) @@ -1151,22 +1140,16 @@ export function createVariants(theme: Theme): Variants { staticVariant('forced-colors', ['@media (forced-colors: active)']) - if (enableInvertedColors) { - staticVariant('inverted-colors', ['@media (inverted-colors: inverted)']) - } + staticVariant('inverted-colors', ['@media (inverted-colors: inverted)']) - if (enablePointerVariants) { - staticVariant('pointer-none', ['@media (pointer: none)']) - staticVariant('pointer-coarse', ['@media (pointer: coarse)']) - staticVariant('pointer-fine', ['@media (pointer: fine)']) - staticVariant('any-pointer-none', ['@media (any-pointer: none)']) - staticVariant('any-pointer-coarse', ['@media (any-pointer: coarse)']) - staticVariant('any-pointer-fine', ['@media (any-pointer: fine)']) - } + staticVariant('pointer-none', ['@media (pointer: none)']) + staticVariant('pointer-coarse', ['@media (pointer: coarse)']) + staticVariant('pointer-fine', ['@media (pointer: fine)']) + staticVariant('any-pointer-none', ['@media (any-pointer: none)']) + staticVariant('any-pointer-coarse', ['@media (any-pointer: coarse)']) + staticVariant('any-pointer-fine', ['@media (any-pointer: fine)']) - if (enableScripting) { - staticVariant('noscript', ['@media (scripting: none)']) - } + staticVariant('noscript', ['@media (scripting: none)']) return variants }