From 51157717dad2000faf2eee0949299707eb15b23b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 28 Mar 2023 15:38:30 +0200 Subject: [PATCH] Add gradient color stop position utilities (#10886) * add gradient color stop positions * update tests to include gradient position color stop reset values * add dedicated color stop position tests * use `%` sign in the name of the uility * update changelog * ensure `length` values and css variables work --- CHANGELOG.md | 1 + oxide/crates/core/src/parser.rs | 25 ++-- src/corePlugins.js | 62 ++++++++- stubs/config.full.js | 23 ++++ tests/any-type.test.js | 42 +++--- tests/arbitrary-values.oxide.test.css | 32 +++-- tests/arbitrary-values.test.css | 32 +++-- tests/basic-usage.oxide.test.css | 16 ++- tests/basic-usage.test.css | 16 ++- tests/color-opacity-modifiers.test.js | 6 +- tests/kitchen-sink.test.js | 12 +- tests/plugins/gradientColorStops.test.js | 155 ++++++++++++++++++++--- tests/raw-content.oxide.test.css | 16 ++- tests/raw-content.test.css | 16 ++- 14 files changed, 359 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ab90376ad6..c12fe53ecae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `content-normal` and `content-stretch` utilities ([#10645](https://github.com/tailwindlabs/tailwindcss/pull/10645)) - Add `whitespace-break-spaces` utility ([#10729](https://github.com/tailwindlabs/tailwindcss/pull/10729)) - Add support for configuring default `font-variation-settings` for a `font-family` ([#10034](https://github.com/tailwindlabs/tailwindcss/pull/10034), [#10515](https://github.com/tailwindlabs/tailwindcss/pull/10515)) +- Add gradient color stop position utilities ([#10886](https://github.com/tailwindlabs/tailwindcss/pull/10886)) ### Fixed diff --git a/oxide/crates/core/src/parser.rs b/oxide/crates/core/src/parser.rs index 4bba1f947583..16831afffd41 100644 --- a/oxide/crates/core/src/parser.rs +++ b/oxide/crates/core/src/parser.rs @@ -43,14 +43,14 @@ impl<'a> Extractor<'a> { #[cfg(test)] pub fn unique_ord(input: &'a [u8], opts: ExtractorOptions) -> Vec<&'a [u8]> { - // This is an inefficient way to get an ordered, unique - // list as a Vec but it is only meant for testing. - let mut candidates = Self::all(input, opts); - let mut unique_list = FxHashSet::default(); - unique_list.reserve(candidates.len()); - candidates.retain(|c| unique_list.insert(*c)); + // This is an inefficient way to get an ordered, unique + // list as a Vec but it is only meant for testing. + let mut candidates = Self::all(input, opts); + let mut unique_list = FxHashSet::default(); + unique_list.reserve(candidates.len()); + candidates.retain(|c| unique_list.insert(*c)); - candidates + candidates } } @@ -319,7 +319,16 @@ impl<'a> Extractor<'a> { // Allowed characters in the candidate itself // None of these can come after a closing bracket `]` - b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'-' | b'_' | b'(' | b')' | b'!' | b'@' + b'a'..=b'z' + | b'A'..=b'Z' + | b'0'..=b'9' + | b'-' + | b'_' + | b'(' + | b')' + | b'!' + | b'@' + | b'%' if prev != b']' => { /* TODO: The `b'@'` is necessary for custom separators like _@, maybe we can handle this in a better way... */ diff --git a/src/corePlugins.js b/src/corePlugins.js index aacca3ab0af1..2c3b99283a5a 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1756,40 +1756,92 @@ export let corePlugins = { type: ['color', 'any'], } + let positionOptions = { + values: theme('gradientColorStopPositions'), + type: ['length', 'percentage'], + } + matchUtilities( { from: (value) => { let transparentToValue = transparentTo(value) return { - '--tw-gradient-from': toColorValue(value, 'from'), - '--tw-gradient-to': transparentToValue, + '--tw-gradient-from': `${toColorValue( + value, + 'from' + )} var(--tw-gradient-from-position)`, + '--tw-gradient-from-position': ' ', + '--tw-gradient-to': `${transparentToValue} var(--tw-gradient-from-position)`, + '--tw-gradient-to-position': ' ', '--tw-gradient-stops': `var(--tw-gradient-from), var(--tw-gradient-to)`, } }, }, options ) + + matchUtilities( + { + from: (value) => { + return { + '--tw-gradient-from-position': value, + } + }, + }, + positionOptions + ) + matchUtilities( { via: (value) => { let transparentToValue = transparentTo(value) return { - '--tw-gradient-to': transparentToValue, + '--tw-gradient-via-position': ' ', + '--tw-gradient-to': `${transparentToValue} var(--tw-gradient-to-position)`, + '--tw-gradient-to-position': ' ', '--tw-gradient-stops': `var(--tw-gradient-from), ${toColorValue( value, 'via' - )}, var(--tw-gradient-to)`, + )} var(--tw-gradient-via-position), var(--tw-gradient-to)`, } }, }, options ) + matchUtilities( - { to: (value) => ({ '--tw-gradient-to': toColorValue(value, 'to') }) }, + { + via: (value) => { + return { + '--tw-gradient-via-position': value, + } + }, + }, + positionOptions + ) + + matchUtilities( + { + to: (value) => ({ + '--tw-gradient-to': `${toColorValue(value, 'to')} var(--tw-gradient-to-position)`, + '--tw-gradient-to-position': ' ', + }), + }, options ) + + matchUtilities( + { + to: (value) => { + return { + '--tw-gradient-to-position': value, + } + }, + }, + positionOptions + ) } })(), diff --git a/stubs/config.full.js b/stubs/config.full.js index d3637bc9fad3..c32ccd3a0ea2 100644 --- a/stubs/config.full.js +++ b/stubs/config.full.js @@ -355,6 +355,29 @@ module.exports = { }, gap: ({ theme }) => theme('spacing'), gradientColorStops: ({ theme }) => theme('colors'), + gradientColorStopPositions: { + '0%': '0%', + '5%': '5%', + '10%': '10%', + '15%': '15%', + '20%': '20%', + '25%': '25%', + '30%': '30%', + '35%': '35%', + '40%': '40%', + '45%': '45%', + '50%': '50%', + '55%': '55%', + '60%': '60%', + '65%': '65%', + '70%': '70%', + '75%': '75%', + '80%': '80%', + '85%': '85%', + '90%': '90%', + '95%': '95%', + '100%': '100%', + }, grayscale: { 0: '0', DEFAULT: '100%', diff --git a/tests/any-type.test.js b/tests/any-type.test.js index 17b670386bbf..11b92c8977bc 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -185,7 +185,7 @@ crosscheck(({ stable, oxide }) => { ` return run(input, config).then((result) => { - let oxideExpected = css` + oxide.expect(result.css).toMatchFormattedCss(css` .inset-\[var\(--any-value\)\] { inset: var(--any-value); } @@ -499,16 +499,22 @@ crosscheck(({ stable, oxide }) => { background-color: var(--any-value); } .from-\[var\(--any-value\)\] { - --tw-gradient-from: var(--any-value); - --tw-gradient-to: #fff0; + --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-\[var\(--any-value\)\] { - --tw-gradient-to: #fff0; - --tw-gradient-stops: var(--tw-gradient-from), var(--any-value), var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), + var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); } .to-\[var\(--any-value\)\] { - --tw-gradient-to: var(--any-value); + --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .fill-\[var\(--any-value\)\] { fill: var(--any-value); @@ -732,8 +738,8 @@ crosscheck(({ stable, oxide }) => { --tw-content: var(--any-value); content: var(--tw-content); } - ` - let stableExpected = css` + `) + stable.expect(result.css).toMatchFormattedCss(css` .inset-\[var\(--any-value\)\] { inset: var(--any-value); } @@ -1056,16 +1062,22 @@ crosscheck(({ stable, oxide }) => { --tw-bg-opacity: var(--any-value); } .from-\[var\(--any-value\)\] { - --tw-gradient-from: var(--any-value); - --tw-gradient-to: #fff0; + --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-\[var\(--any-value\)\] { - --tw-gradient-to: #fff0; - --tw-gradient-stops: var(--tw-gradient-from), var(--any-value), var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), + var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); } .to-\[var\(--any-value\)\] { - --tw-gradient-to: var(--any-value); + --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .fill-\[var\(--any-value\)\] { fill: var(--any-value); @@ -1298,9 +1310,7 @@ crosscheck(({ stable, oxide }) => { --tw-content: var(--any-value); content: var(--tw-content); } - ` - oxide.expect(result.css).toMatchFormattedCss(oxideExpected) - stable.expect(result.css).toMatchFormattedCss(stableExpected) + `) }) }) test.todo('rewrite the any test to be easier to understand or break it up into multiple tests') diff --git a/tests/arbitrary-values.oxide.test.css b/tests/arbitrary-values.oxide.test.css index 4f3056ea9f21..fbf433b61a49 100644 --- a/tests/arbitrary-values.oxide.test.css +++ b/tests/arbitrary-values.oxide.test.css @@ -659,28 +659,40 @@ background-image: var(--url); } .from-\[\#da5b66\] { - --tw-gradient-from: #da5b66; - --tw-gradient-to: #da5b6600; + --tw-gradient-from: #da5b66 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #da5b6600 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .from-\[var\(--color\)\] { - --tw-gradient-from: var(--color); - --tw-gradient-to: #fff0; + --tw-gradient-from: var(--color) var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-\[\#da5b66\] { - --tw-gradient-to: #da5b6600; - --tw-gradient-stops: var(--tw-gradient-from), #da5b66, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #da5b6600 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #da5b66 var(--tw-gradient-via-position), + var(--tw-gradient-to); } .via-\[var\(--color\)\] { - --tw-gradient-to: #fff0; - --tw-gradient-stops: var(--tw-gradient-from), var(--color), var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), var(--color) var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-\[\#da5b66\] { - --tw-gradient-to: #da5b66; + --tw-gradient-to: #da5b66 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .to-\[var\(--color\)\] { - --tw-gradient-to: var(--color); + --tw-gradient-to: var(--color) var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .bg-\[length\:200px_100px\] { background-size: 200px 100px; diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index e1c624e2b876..927431210ab7 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -688,28 +688,40 @@ background-image: var(--url); } .from-\[\#da5b66\] { - --tw-gradient-from: #da5b66; - --tw-gradient-to: #da5b6600; + --tw-gradient-from: #da5b66 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #da5b6600 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .from-\[var\(--color\)\] { - --tw-gradient-from: var(--color); - --tw-gradient-to: #fff0; + --tw-gradient-from: var(--color) var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-\[\#da5b66\] { - --tw-gradient-to: #da5b6600; - --tw-gradient-stops: var(--tw-gradient-from), #da5b66, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #da5b6600 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #da5b66 var(--tw-gradient-via-position), + var(--tw-gradient-to); } .via-\[var\(--color\)\] { - --tw-gradient-to: #fff0; - --tw-gradient-stops: var(--tw-gradient-from), var(--color), var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), var(--color) var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-\[\#da5b66\] { - --tw-gradient-to: #da5b66; + --tw-gradient-to: #da5b66 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .to-\[var\(--color\)\] { - --tw-gradient-to: var(--color); + --tw-gradient-to: var(--color) var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .bg-\[length\:200px_100px\] { background-size: 200px 100px; diff --git a/tests/basic-usage.oxide.test.css b/tests/basic-usage.oxide.test.css index c5117b917944..e3207ab31885 100644 --- a/tests/basic-usage.oxide.test.css +++ b/tests/basic-usage.oxide.test.css @@ -607,16 +607,22 @@ background-image: linear-gradient(to right, var(--tw-gradient-stops)); } .from-red-300 { - --tw-gradient-from: #fca5a5; - --tw-gradient-to: #fca5a500; + --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fca5a500 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-purple-200 { - --tw-gradient-to: #e9d5ff00; - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-blue-400 { - --tw-gradient-to: #60a5fa; + --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .decoration-slice { -webkit-box-decoration-break: slice; diff --git a/tests/basic-usage.test.css b/tests/basic-usage.test.css index 55bdc2b3b9ab..aa4897913424 100644 --- a/tests/basic-usage.test.css +++ b/tests/basic-usage.test.css @@ -625,16 +625,22 @@ background-image: linear-gradient(to right, var(--tw-gradient-stops)); } .from-red-300 { - --tw-gradient-from: #fca5a5; - --tw-gradient-to: #fca5a500; + --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fca5a500 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-purple-200 { - --tw-gradient-to: #e9d5ff00; - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-blue-400 { - --tw-gradient-to: #60a5fa; + --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .decoration-slice { -webkit-box-decoration-break: slice; diff --git a/tests/color-opacity-modifiers.test.js b/tests/color-opacity-modifiers.test.js index e7d285740714..c517644df503 100644 --- a/tests/color-opacity-modifiers.test.js +++ b/tests/color-opacity-modifiers.test.js @@ -172,8 +172,10 @@ crosscheck(({ stable, oxide }) => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` .from-red-500\/50 { - --tw-gradient-from: #ef444480; - --tw-gradient-to: #ef444400; + --tw-gradient-from: #ef444480 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #ef444400 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .fill-red-500\/25 { diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index f5e30b4bbff7..4b43a6b0db42 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -527,8 +527,10 @@ crosscheck(({ stable, oxide }) => { background-image: url('/images/homepage-1.jpg'); } .from-foo { - --tw-gradient-from: #bada55; - --tw-gradient-to: #bada5500; + --tw-gradient-from: #bada55 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #bada5500 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .px-1 { @@ -1087,8 +1089,10 @@ crosscheck(({ stable, oxide }) => { background-image: url('/images/homepage-1.jpg'); } .from-foo { - --tw-gradient-from: #bada55; - --tw-gradient-to: #bada5500; + --tw-gradient-from: #bada55 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #bada5500 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .px-1 { diff --git a/tests/plugins/gradientColorStops.test.js b/tests/plugins/gradientColorStops.test.js index 6a26e2e33901..bf8e73cdb764 100644 --- a/tests/plugins/gradientColorStops.test.js +++ b/tests/plugins/gradientColorStops.test.js @@ -34,28 +34,40 @@ crosscheck(({ stable, oxide }) => { return run('@tailwind utilities', config).then((result) => { stable.expect(result.css).toMatchFormattedCss(css` .from-primary { - --tw-gradient-from: #1f1f1f; - --tw-gradient-to: #1f1f1f00; + --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .from-secondary { - --tw-gradient-from: #bf5540; - --tw-gradient-to: #bf554000; + --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #bf554000 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-primary { - --tw-gradient-to: #1f1f1f00; - --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), + var(--tw-gradient-to); } .via-secondary { - --tw-gradient-to: #bf554000; - --tw-gradient-stops: var(--tw-gradient-from), #bf5540, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-primary { - --tw-gradient-to: #1f1f1f; + --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .to-secondary { - --tw-gradient-to: #bf5540; + --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .text-primary { --tw-text-opacity: 1; @@ -71,28 +83,40 @@ crosscheck(({ stable, oxide }) => { `) oxide.expect(result.css).toMatchFormattedCss(css` .from-primary { - --tw-gradient-from: #1f1f1f; - --tw-gradient-to: #1f1f1f00; + --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .from-secondary { - --tw-gradient-from: #bf5540; - --tw-gradient-to: #bf554000; + --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #bf554000 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-primary { - --tw-gradient-to: #1f1f1f00; - --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), + var(--tw-gradient-to); } .via-secondary { - --tw-gradient-to: #bf554000; - --tw-gradient-stops: var(--tw-gradient-from), #bf5540, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-primary { - --tw-gradient-to: #1f1f1f; + --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .to-secondary { - --tw-gradient-to: #bf5540; + --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .text-primary { color: #1f1f1f; @@ -103,4 +127,95 @@ crosscheck(({ stable, oxide }) => { `) }) }) + + test('gradient color stop position', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + theme: {}, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + .from-\[--from-value\] { + --tw-gradient-from: var(--from-value) var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-red-500 { + --tw-gradient-from: #ef4444 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #ef444400 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-10\% { + --tw-gradient-from-position: 10%; + } + .from-\[11\%\] { + --tw-gradient-from-position: 11%; + } + .from-\[12px\] { + --tw-gradient-from-position: 12px; + } + .via-\[--via-value\] { + --tw-gradient-via-position: ; + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), + var(--via-value) var(--tw-gradient-via-position), var(--tw-gradient-to); + } + .via-pink-500 { + --tw-gradient-via-position: ; + --tw-gradient-to: #ec489900 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #ec4899 var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .via-20\% { + --tw-gradient-via-position: 20%; + } + .via-\[12\%\] { + --tw-gradient-via-position: 12%; + } + .via-\[123px\] { + --tw-gradient-via-position: 123px; + } + .to-\[--to-value\] { + --tw-gradient-to: var(--to-value) var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + } + .to-violet-400 { + --tw-gradient-to: #a78bfa var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + } + .to-30\% { + --tw-gradient-to-position: 30%; + } + .to-\[13\%\] { + --tw-gradient-to-position: 13%; + } + .to-\[14px\] { + --tw-gradient-to-position: 14px; + } + `) + }) + }) }) diff --git a/tests/raw-content.oxide.test.css b/tests/raw-content.oxide.test.css index f50f95e878cb..b34e47930a08 100644 --- a/tests/raw-content.oxide.test.css +++ b/tests/raw-content.oxide.test.css @@ -423,16 +423,22 @@ background-image: linear-gradient(to right, var(--tw-gradient-stops)); } .from-red-300 { - --tw-gradient-from: #fca5a5; - --tw-gradient-to: #fca5a500; + --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fca5a500 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-purple-200 { - --tw-gradient-to: #e9d5ff00; - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-blue-400 { - --tw-gradient-to: #60a5fa; + --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .decoration-slice { -webkit-box-decoration-break: slice; diff --git a/tests/raw-content.test.css b/tests/raw-content.test.css index 2978955898d8..5bee46672539 100644 --- a/tests/raw-content.test.css +++ b/tests/raw-content.test.css @@ -435,16 +435,22 @@ background-image: linear-gradient(to right, var(--tw-gradient-stops)); } .from-red-300 { - --tw-gradient-from: #fca5a5; - --tw-gradient-to: #fca5a500; + --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); + --tw-gradient-from-position: ; + --tw-gradient-to: #fca5a500 var(--tw-gradient-from-position); + --tw-gradient-to-position: ; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } .via-purple-200 { - --tw-gradient-to: #e9d5ff00; - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff, var(--tw-gradient-to); + --tw-gradient-via-position: ; + --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); + --tw-gradient-to-position: ; + --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), + var(--tw-gradient-to); } .to-blue-400 { - --tw-gradient-to: #60a5fa; + --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); + --tw-gradient-to-position: ; } .decoration-slice { -webkit-box-decoration-break: slice;