diff --git a/CHANGELOG.md b/CHANGELOG.md index 22473e86c292..c312cea05cc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `@tailwindcss/upgrade` tooling ([#14434](https://github.com/tailwindlabs/tailwindcss/pull/14434)) - Add CSS codemods for migrating `@tailwind` directives ([#14411](https://github.com/tailwindlabs/tailwindcss/pull/14411)) - Support `screens` in JS config files ([#14415](https://github.com/tailwindlabs/tailwindcss/pull/14415)) +- Add `bg-radial-*` and `bg-conic-*` utilities for radial and conic gradients ([#14467](https://github.com/tailwindlabs/tailwindcss/pull/14467)) ### Fixed diff --git a/packages/tailwindcss/src/property-order.ts b/packages/tailwindcss/src/property-order.ts index 78083342a0fb..b45baca1475b 100644 --- a/packages/tailwindcss/src/property-order.ts +++ b/packages/tailwindcss/src/property-order.ts @@ -216,6 +216,7 @@ export default [ '--tw-bg-opacity', 'background-image', + '--tw-gradient-position', '--tw-gradient-stops', '--tw-gradient-via-stops', '--tw-gradient-from', diff --git a/packages/tailwindcss/src/utilities.test.ts b/packages/tailwindcss/src/utilities.test.ts index 79af45227697..a95fb2cd37f9 100644 --- a/packages/tailwindcss/src/utilities.test.ts +++ b/packages/tailwindcss/src/utilities.test.ts @@ -9423,99 +9423,119 @@ test('bg', async () => { } .-bg-linear-\\[1\\.3rad\\] { - background-image: linear-gradient(calc(74.4845deg * -1), var(--tw-gradient-stops, )); + --tw-gradient-position: calc(74.4845deg * -1), ; + background-image: linear-gradient(var(--tw-gradient-stops, calc(74.4845deg * -1))); } .-bg-linear-\\[125deg\\] { - background-image: linear-gradient(calc(125deg * -1), var(--tw-gradient-stops, )); - } - - .bg-\\[image\\:--my-gradient\\] { - background-image: var(--my-gradient); - } - - .bg-\\[linear-gradient\\(to_bottom\\,red\\,blue\\)\\] { - background-image: linear-gradient(red, #00f); - } - - .bg-\\[url\\(\\/image\\.png\\)\\] { - background-image: url("/image.png"); - } - - .bg-\\[url\\:--my-url\\] { - background-image: var(--my-url); + --tw-gradient-position: calc(125deg * -1), ; + background-image: linear-gradient(var(--tw-gradient-stops, calc(125deg * -1))); } .bg-gradient-to-b { - background-image: linear-gradient(to bottom, var(--tw-gradient-stops, )); + --tw-gradient-position: to bottom, ; + background-image: linear-gradient(var(--tw-gradient-stops, to bottom)); } .bg-gradient-to-bl { - background-image: linear-gradient(to bottom left, var(--tw-gradient-stops, )); + --tw-gradient-position: to bottom left, ; + background-image: linear-gradient(var(--tw-gradient-stops, to bottom left)); } .bg-gradient-to-br { - background-image: linear-gradient(to bottom right, var(--tw-gradient-stops, )); + --tw-gradient-position: to bottom right, ; + background-image: linear-gradient(var(--tw-gradient-stops, to bottom right)); } .bg-gradient-to-l { - background-image: linear-gradient(to left, var(--tw-gradient-stops, )); + --tw-gradient-position: to left, ; + background-image: linear-gradient(var(--tw-gradient-stops, to left)); } .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops, )); + --tw-gradient-position: to right, ; + background-image: linear-gradient(var(--tw-gradient-stops, to right)); } .bg-gradient-to-t { - background-image: linear-gradient(to top, var(--tw-gradient-stops, )); + --tw-gradient-position: to top, ; + background-image: linear-gradient(var(--tw-gradient-stops, to top)); } .bg-gradient-to-tl { - background-image: linear-gradient(to top left, var(--tw-gradient-stops, )); + --tw-gradient-position: to top left, ; + background-image: linear-gradient(var(--tw-gradient-stops, to top left)); } .bg-gradient-to-tr { - background-image: linear-gradient(to top right, var(--tw-gradient-stops, )); + --tw-gradient-position: to top right, ; + background-image: linear-gradient(var(--tw-gradient-stops, to top right)); } .bg-linear-\\[1\\.3rad\\] { - background-image: linear-gradient(74.4845deg, var(--tw-gradient-stops, )); + --tw-gradient-position: 74.4845deg, ; + background-image: linear-gradient(var(--tw-gradient-stops, 74.4845deg)); } .bg-linear-\\[125deg\\] { - background-image: linear-gradient(125deg, var(--tw-gradient-stops, )); + --tw-gradient-position: 125deg, ; + background-image: linear-gradient(var(--tw-gradient-stops, 125deg)); } .bg-linear-\\[to_bottom\\], .bg-linear-to-b { - background-image: linear-gradient(to bottom, var(--tw-gradient-stops, )); + --tw-gradient-position: to bottom, ; + background-image: linear-gradient(var(--tw-gradient-stops, to bottom)); } .bg-linear-to-bl { - background-image: linear-gradient(to bottom left, var(--tw-gradient-stops, )); + --tw-gradient-position: to bottom left, ; + background-image: linear-gradient(var(--tw-gradient-stops, to bottom left)); } .bg-linear-to-br { - background-image: linear-gradient(to bottom right, var(--tw-gradient-stops, )); + --tw-gradient-position: to bottom right, ; + background-image: linear-gradient(var(--tw-gradient-stops, to bottom right)); } .bg-linear-to-l { - background-image: linear-gradient(to left, var(--tw-gradient-stops, )); + --tw-gradient-position: to left, ; + background-image: linear-gradient(var(--tw-gradient-stops, to left)); } .bg-linear-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops, )); + --tw-gradient-position: to right, ; + background-image: linear-gradient(var(--tw-gradient-stops, to right)); } .bg-linear-to-t { - background-image: linear-gradient(to top, var(--tw-gradient-stops, )); + --tw-gradient-position: to top, ; + background-image: linear-gradient(var(--tw-gradient-stops, to top)); } .bg-linear-to-tl { - background-image: linear-gradient(to top left, var(--tw-gradient-stops, )); + --tw-gradient-position: to top left, ; + background-image: linear-gradient(var(--tw-gradient-stops, to top left)); } .bg-linear-to-tr { - background-image: linear-gradient(to top right, var(--tw-gradient-stops, )); + --tw-gradient-position: to top right, ; + background-image: linear-gradient(var(--tw-gradient-stops, to top right)); + } + + .bg-\\[image\\:--my-gradient\\] { + background-image: var(--my-gradient); + } + + .bg-\\[linear-gradient\\(to_bottom\\,red\\,blue\\)\\] { + background-image: linear-gradient(red, #00f); + } + + .bg-\\[url\\(\\/image\\.png\\)\\] { + background-image: url("/image.png"); + } + + .bg-\\[url\\:--my-url\\] { + background-image: var(--my-url); } .bg-none { @@ -9804,62 +9824,62 @@ test('from', async () => { .from-\\[\\#0088cc\\] { --tw-gradient-from: #08c; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-\\[\\#0088cc\\]\\/50, .from-\\[\\#0088cc\\]\\/\\[0\\.5\\], .from-\\[\\#0088cc\\]\\/\\[50\\%\\] { --tw-gradient-from: #0088cc80; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-\\[--my-color\\] { --tw-gradient-from: var(--my-color); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-\\[--my-color\\]\\/50, .from-\\[--my-color\\]\\/\\[0\\.5\\], .from-\\[--my-color\\]\\/\\[50\\%\\] { --tw-gradient-from: color-mix(in srgb, var(--my-color) 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-\\[color\\:--my-color\\] { --tw-gradient-from: var(--my-color); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-\\[color\\:--my-color\\]\\/50, .from-\\[color\\:--my-color\\]\\/\\[0\\.5\\], .from-\\[color\\:--my-color\\]\\/\\[50\\%\\] { --tw-gradient-from: color-mix(in srgb, var(--my-color) 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-current { --tw-gradient-from: currentColor; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-current\\/50, .from-current\\/\\[0\\.5\\], .from-current\\/\\[50\\%\\] { --tw-gradient-from: color-mix(in srgb, currentColor 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-inherit { --tw-gradient-from: inherit; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-red-500 { --tw-gradient-from: var(--color-red-500, #ef4444); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-red-500\\/50, .from-red-500\\/\\[0\\.5\\], .from-red-500\\/\\[50\\%\\] { --tw-gradient-from: color-mix(in srgb, var(--color-red-500, #ef4444) 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-transparent { --tw-gradient-from: transparent; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .from-0\\% { @@ -9889,6 +9909,7 @@ test('from', async () => { @supports (-moz-orient: inline) { @layer base { *, :before, :after, ::backdrop { + --tw-gradient-position: initial; --tw-gradient-from: #0000; --tw-gradient-to: #0000; --tw-gradient-via: transparent; @@ -9901,6 +9922,11 @@ test('from', async () => { } } + @property --tw-gradient-position { + syntax: "*"; + inherits: false + } + @property --tw-gradient-from { syntax: ""; inherits: false; @@ -10031,73 +10057,73 @@ test('via', async () => { .via-\\[\\#0088cc\\] { --tw-gradient-via: #08c; - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-\\[\\#0088cc\\]\\/50, .via-\\[\\#0088cc\\]\\/\\[0\\.5\\], .via-\\[\\#0088cc\\]\\/\\[50\\%\\] { --tw-gradient-via: #0088cc80; - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-\\[--my-color\\] { --tw-gradient-via: var(--my-color); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-\\[--my-color\\]\\/50, .via-\\[--my-color\\]\\/\\[0\\.5\\], .via-\\[--my-color\\]\\/\\[50\\%\\] { --tw-gradient-via: color-mix(in srgb, var(--my-color) 50%, transparent); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-\\[color\\:--my-color\\] { --tw-gradient-via: var(--my-color); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-\\[color\\:--my-color\\]\\/50, .via-\\[color\\:--my-color\\]\\/\\[0\\.5\\], .via-\\[color\\:--my-color\\]\\/\\[50\\%\\] { --tw-gradient-via: color-mix(in srgb, var(--my-color) 50%, transparent); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-current { --tw-gradient-via: currentColor; - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-current\\/50, .via-current\\/\\[0\\.5\\], .via-current\\/\\[50\\%\\] { --tw-gradient-via: color-mix(in srgb, currentColor 50%, transparent); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-inherit { --tw-gradient-via: inherit; - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-red-500 { --tw-gradient-via: var(--color-red-500, #ef4444); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-red-500\\/50, .via-red-500\\/\\[0\\.5\\], .via-red-500\\/\\[50\\%\\] { --tw-gradient-via: color-mix(in srgb, var(--color-red-500, #ef4444) 50%, transparent); - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } .via-transparent { --tw-gradient-via: transparent; - --tw-gradient-via-stops: var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-via-stops: var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-via-stops); } @@ -10128,6 +10154,7 @@ test('via', async () => { @supports (-moz-orient: inline) { @layer base { *, :before, :after, ::backdrop { + --tw-gradient-position: initial; --tw-gradient-from: #0000; --tw-gradient-to: #0000; --tw-gradient-via: transparent; @@ -10140,6 +10167,11 @@ test('via', async () => { } } + @property --tw-gradient-position { + syntax: "*"; + inherits: false + } + @property --tw-gradient-from { syntax: ""; inherits: false; @@ -10270,62 +10302,62 @@ test('to', async () => { .to-\\[\\#0088cc\\] { --tw-gradient-to: #08c; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-\\[\\#0088cc\\]\\/50, .to-\\[\\#0088cc\\]\\/\\[0\\.5\\], .to-\\[\\#0088cc\\]\\/\\[50\\%\\] { --tw-gradient-to: #0088cc80; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-\\[--my-color\\] { --tw-gradient-to: var(--my-color); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-\\[--my-color\\]\\/50, .to-\\[--my-color\\]\\/\\[0\\.5\\], .to-\\[--my-color\\]\\/\\[50\\%\\] { --tw-gradient-to: color-mix(in srgb, var(--my-color) 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-\\[color\\:--my-color\\] { --tw-gradient-to: var(--my-color); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-\\[color\\:--my-color\\]\\/50, .to-\\[color\\:--my-color\\]\\/\\[0\\.5\\], .to-\\[color\\:--my-color\\]\\/\\[50\\%\\] { --tw-gradient-to: color-mix(in srgb, var(--my-color) 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-current { --tw-gradient-to: currentColor; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-current\\/50, .to-current\\/\\[0\\.5\\], .to-current\\/\\[50\\%\\] { --tw-gradient-to: color-mix(in srgb, currentColor 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-inherit { --tw-gradient-to: inherit; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-red-500 { --tw-gradient-to: var(--color-red-500, #ef4444); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-red-500\\/50, .to-red-500\\/\\[0\\.5\\], .to-red-500\\/\\[50\\%\\] { --tw-gradient-to: color-mix(in srgb, var(--color-red-500, #ef4444) 50%, transparent); - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-transparent { --tw-gradient-to: transparent; - --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position, ) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } .to-0\\% { @@ -10355,6 +10387,7 @@ test('to', async () => { @supports (-moz-orient: inline) { @layer base { *, :before, :after, ::backdrop { + --tw-gradient-position: initial; --tw-gradient-from: #0000; --tw-gradient-to: #0000; --tw-gradient-via: transparent; @@ -10367,6 +10400,11 @@ test('to', async () => { } } + @property --tw-gradient-position { + syntax: "*"; + inherits: false + } + @property --tw-gradient-from { syntax: ""; inherits: false; diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index 2ed3310e25f9..23766a3b0cd4 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -2507,11 +2507,13 @@ export function createUtilities(theme: Theme) { ['tl', 'top left'], ]) { staticUtility(`bg-gradient-to-${value}`, [ - ['background-image', `linear-gradient(to ${direction}, var(--tw-gradient-stops,))`], + ['--tw-gradient-position', `to ${direction},`], + ['background-image', `linear-gradient(var(--tw-gradient-stops, to ${direction}))`], ]) staticUtility(`bg-linear-to-${value}`, [ - ['background-image', `linear-gradient(to ${direction}, var(--tw-gradient-stops,))`], + ['--tw-gradient-position', `to ${direction},`], + ['background-image', `linear-gradient(var(--tw-gradient-stops, to ${direction}))`], ]) } @@ -2526,17 +2528,71 @@ export function createUtilities(theme: Theme) { case 'angle': { value = withNegative(value, candidate) - return [decl('background-image', `linear-gradient(${value}, var(--tw-gradient-stops,))`)] + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`), + ] } default: { if (candidate.negative) return - return [decl('background-image', `linear-gradient(${value}, var(--tw-gradient-stops,))`)] + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`), + ] } } } }) + utilities.functional('bg-conic', (candidate) => { + if (candidate.modifier) return + + if (!candidate.value) { + return [ + decl('--tw-gradient-position', `initial`), + decl('background-image', `conic-gradient(var(--tw-gradient-stops))`), + ] + } + + let value = candidate.value.value + + if (candidate.value.kind === 'arbitrary') { + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `conic-gradient(var(--tw-gradient-stops,${value}))`), + ] + } else { + if (!isPositiveInteger(value)) return + + value = withNegative(`${value}deg`, candidate) + + return [ + decl('--tw-gradient-position', `from ${value},`), + decl('background-image', `conic-gradient(var(--tw-gradient-stops,from ${value}))`), + ] + } + }) + + utilities.functional('bg-radial', (candidate) => { + if (candidate.modifier) return + + if (!candidate.value) { + return [ + decl('--tw-gradient-position', `initial`), + decl('background-image', `radial-gradient(var(--tw-gradient-stops))`), + ] + } + + if (candidate.value.kind === 'arbitrary') { + let value = candidate.value.value + return [ + decl('--tw-gradient-position', `${value},`), + decl('background-image', `radial-gradient(var(--tw-gradient-stops,${value}))`), + ] + } + }) + utilities.functional('bg', (candidate) => { if (candidate.negative || !candidate.value) return @@ -2613,6 +2669,7 @@ export function createUtilities(theme: Theme) { let gradientStopProperties = () => { return atRoot([ + property('--tw-gradient-position'), property('--tw-gradient-from', '#0000', ''), property('--tw-gradient-to', '#0000', ''), property('--tw-gradient-from', 'transparent', ''), @@ -2699,7 +2756,7 @@ export function createUtilities(theme: Theme) { decl('--tw-gradient-from', value), decl( '--tw-gradient-stops', - 'var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))', + 'var(--tw-gradient-via-stops, var(--tw-gradient-position,) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))', ), ], position: (value) => [gradientStopProperties(), decl('--tw-gradient-from-position', value)], @@ -2712,7 +2769,7 @@ export function createUtilities(theme: Theme) { decl('--tw-gradient-via', value), decl( '--tw-gradient-via-stops', - 'var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position)', + 'var(--tw-gradient-position,) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position)', ), decl('--tw-gradient-stops', 'var(--tw-gradient-via-stops)'), ], @@ -2725,7 +2782,7 @@ export function createUtilities(theme: Theme) { decl('--tw-gradient-to', value), decl( '--tw-gradient-stops', - 'var(--tw-gradient-via-stops, var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))', + 'var(--tw-gradient-via-stops, var(--tw-gradient-position,) var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))', ), ], position: (value) => [gradientStopProperties(), decl('--tw-gradient-to-position', value)], diff --git a/packages/tailwindcss/tests/ui.spec.ts b/packages/tailwindcss/tests/ui.spec.ts index c16b0f920a77..674538886d84 100644 --- a/packages/tailwindcss/tests/ui.spec.ts +++ b/packages/tailwindcss/tests/ui.spec.ts @@ -28,29 +28,39 @@ test('touch action', async ({ page }) => { }) for (let [classes, expected] of [ - ['from-red-500', 'linear-gradient(to right, rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)'], [ - 'via-red-500', + 'bg-linear-to-r from-red-500', + 'linear-gradient(to right, rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)', + ], + [ + 'bg-linear-to-r via-red-500', 'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(239, 68, 68) 50%, rgba(0, 0, 0, 0) 100%)', ], - ['to-red-500', 'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(239, 68, 68) 100%)'], [ - 'from-red-500 to-blue-500', + 'bg-linear-to-r to-red-500', + 'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(239, 68, 68) 100%)', + ], + [ + 'bg-linear-to-r from-red-500 to-blue-500', 'linear-gradient(to right, rgb(239, 68, 68) 0%, rgb(59, 130, 246) 100%)', ], [ - 'via-red-500 to-blue-500', + 'bg-linear-to-r via-red-500 to-blue-500', 'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(239, 68, 68) 50%, rgb(59, 130, 246) 100%)', ], [ - 'from-red-500 via-green-500 to-blue-500', + 'bg-linear-to-r from-red-500 via-green-500 to-blue-500', 'linear-gradient(to right, rgb(239, 68, 68) 0%, rgb(34, 197, 94) 50%, rgb(59, 130, 246) 100%)', ], + [ + 'bg-linear-[to_right,var(--color-red-500),var(--color-green-500),var(--color-blue-500)]', + 'linear-gradient(to right, rgb(239, 68, 68), rgb(34, 197, 94), rgb(59, 130, 246))', + ], ]) { test(`background gradient, "${classes}"`, async ({ page }) => { let { getPropertyValue } = await render( page, - html`
Hello world
`, + html`
Hello world
`, ) expect(await getPropertyValue('#x', 'background-image')).toEqual(expected) @@ -99,6 +109,52 @@ test('background gradient, going from 3 to 2', async ({ page }) => { ) }) +for (let [classes, expected] of [ + ['bg-conic from-red-500', 'conic-gradient(rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)'], + [ + 'bg-conic-45 from-red-500', + 'conic-gradient(from 45deg, rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)', + ], + [ + 'bg-conic-[from_45deg] from-red-500', + 'conic-gradient(from 45deg, rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)', + ], + [ + 'bg-conic-[from_45deg,var(--color-red-500),transparent]', + 'conic-gradient(from 45deg, rgb(239, 68, 68), rgba(0, 0, 0, 0))', + ], +]) { + test(`conic gradient, "${classes}"`, async ({ page }) => { + let { getPropertyValue } = await render( + page, + html`
Hello world
`, + ) + + expect(await getPropertyValue('#x', 'background-image')).toEqual(expected) + }) +} + +for (let [classes, expected] of [ + ['bg-radial from-red-500', 'radial-gradient(rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)'], + [ + 'bg-radial-[at_0%_0%] from-red-500', + 'radial-gradient(at 0% 0%, rgb(239, 68, 68) 0%, rgba(0, 0, 0, 0) 100%)', + ], + [ + 'bg-radial-[at_0%_0%,var(--color-red-500),transparent]', + 'radial-gradient(at 0% 0%, rgb(239, 68, 68), rgba(0, 0, 0, 0))', + ], +]) { + test(`radial gradient, "${classes}"`, async ({ page }) => { + let { getPropertyValue } = await render( + page, + html`
Hello world
`, + ) + + expect(await getPropertyValue('#x', 'background-image')).toEqual(expected) + }) +} + test("::backdrop can receive a border with just the 'border' utility", async ({ page }) => { let { getPropertyValue } = await render( page,