From cd9d476ed54962fc6a84c2b4c8e3b168134ee2ff Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Wed, 26 May 2021 15:25:47 -0400 Subject: [PATCH 1/6] Add first-line, first-letter, and marker variants --- src/jit/corePlugins.js | 32 ++++++++++++++++++++++++++++++-- src/jit/lib/setupContextUtils.js | 2 +- tests/jit/variants.test.css | 23 +++++++++++++++++++++++ tests/jit/variants.test.html | 5 +++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/jit/corePlugins.js b/src/jit/corePlugins.js index f5fd232152db..34cf1f981939 100644 --- a/src/jit/corePlugins.js +++ b/src/jit/corePlugins.js @@ -11,7 +11,34 @@ import { } from '../util/pluginUtils' export default { - pseudoClassVariants: function ({ config, addVariant }) { + pseudoElementVariants: function ({ config, addVariant }) { + addVariant( + 'first-letter', + transformAllSelectors((selector) => { + return updateAllClasses(selector, (className, { withPseudo }) => { + return withPseudo(`first-letter${config('separator')}${className}`, '::first-letter') + }) + }) + ) + + addVariant( + 'first-line', + transformAllSelectors((selector) => { + return updateAllClasses(selector, (className, { withPseudo }) => { + return withPseudo(`first-line${config('separator')}${className}`, '::first-line') + }) + }) + ) + + addVariant( + 'marker', + transformAllSelectors((selector) => { + return updateAllClasses(selector, (className, { withPseudo }) => { + return withPseudo(`marker${config('separator')}${className}`, '::marker') + }) + }) + ) + addVariant( 'before', transformAllSelectors( @@ -55,7 +82,8 @@ export default { } ) ) - + }, + pseudoClassVariants: function ({ config, addVariant }) { let pseudoVariants = [ ['first', 'first-child'], ['last', 'last-child'], diff --git a/src/jit/lib/setupContextUtils.js b/src/jit/lib/setupContextUtils.js index 60a1899e2e9c..f6f4f19dfb5a 100644 --- a/src/jit/lib/setupContextUtils.js +++ b/src/jit/lib/setupContextUtils.js @@ -395,7 +395,7 @@ function resolvePlugins(context, tailwindDirectives, root) { // TODO: This is a workaround for backwards compatibility, since custom variants // were historically sorted before screen/stackable variants. - let beforeVariants = [corePlugins['pseudoClassVariants']] + let beforeVariants = [corePlugins['pseudoElementVariants'], corePlugins['pseudoClassVariants']] let afterVariants = [ corePlugins['directionVariants'], corePlugins['reducedMotionVariants'], diff --git a/tests/jit/variants.test.css b/tests/jit/variants.test.css index e85180730c0b..beaeddee4fe2 100644 --- a/tests/jit/variants.test.css +++ b/tests/jit/variants.test.css @@ -18,6 +18,29 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.first-letter\:text-2xl::first-letter { + font-size: 1.5rem; + line-height: 2rem; +} +.first-letter\:text-red-500::first-letter { + --tw-text-opacity: 1; + color: rgba(239, 68, 68, var(--tw-text-opacity)); +} +.first-line\:bg-yellow-300::first-line { + --tw-bg-opacity: 1; + background-color: rgba(252, 211, 77, var(--tw-bg-opacity)); +} +.first-line\:underline::first-line { + text-decoration: underline; +} +.marker\:text-lg::marker { + font-size: 1.125rem; + line-height: 1.75rem; +} +.marker\:text-red-500::marker { + --tw-text-opacity: 1; + color: rgba(239, 68, 68, var(--tw-text-opacity)); +} .before\:block::before { content: ''; display: block; diff --git a/tests/jit/variants.test.html b/tests/jit/variants.test.html index f45a22a18b9a..e3349b84535d 100644 --- a/tests/jit/variants.test.html +++ b/tests/jit/variants.test.html @@ -26,6 +26,11 @@
+
+
+
From ef27a9a69722d9cb68daf81083a79aedc7f4cfad Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Wed, 26 May 2021 15:27:08 -0400 Subject: [PATCH 2/6] Add selection variant Co-Authored-By: Eric Rodrigues Pires --- src/jit/corePlugins.js | 9 +++++++++ tests/jit/variants.test.css | 8 ++++++++ tests/jit/variants.test.html | 1 + 3 files changed, 18 insertions(+) diff --git a/src/jit/corePlugins.js b/src/jit/corePlugins.js index 34cf1f981939..3216aadb9a64 100644 --- a/src/jit/corePlugins.js +++ b/src/jit/corePlugins.js @@ -39,6 +39,15 @@ export default { }) ) + addVariant( + 'selection', + transformAllSelectors((selector) => { + return updateAllClasses(selector, (className, { withPseudo }) => { + return withPseudo(`selection${config('separator')}${className}`, '::selection') + }) + }) + ) + addVariant( 'before', transformAllSelectors( diff --git a/tests/jit/variants.test.css b/tests/jit/variants.test.css index beaeddee4fe2..b17ce1974b60 100644 --- a/tests/jit/variants.test.css +++ b/tests/jit/variants.test.css @@ -41,6 +41,14 @@ --tw-text-opacity: 1; color: rgba(239, 68, 68, var(--tw-text-opacity)); } +.selection\:bg-blue-500::selection { + --tw-bg-opacity: 1; + background-color: rgba(59, 130, 246, var(--tw-bg-opacity)); +} +.selection\:text-white::selection { + --tw-text-opacity: 1; + color: rgba(255, 255, 255, var(--tw-text-opacity)); +} .before\:block::before { content: ''; display: block; diff --git a/tests/jit/variants.test.html b/tests/jit/variants.test.html index e3349b84535d..0b359ff5857b 100644 --- a/tests/jit/variants.test.html +++ b/tests/jit/variants.test.html @@ -31,6 +31,7 @@
+
From 1b15932bf3f95423bf1931aa7dfcfee464b72f74 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Wed, 26 May 2021 15:52:11 -0400 Subject: [PATCH 3/6] Add remaining pseudo-class variants --- src/jit/corePlugins.js | 24 +++++- tests/jit/variants.test.css | 157 +++++++++++++++++++++++++++++++++-- tests/jit/variants.test.html | 51 +++++++++--- 3 files changed, 213 insertions(+), 19 deletions(-) diff --git a/src/jit/corePlugins.js b/src/jit/corePlugins.js index 3216aadb9a64..ffa59a962df1 100644 --- a/src/jit/corePlugins.js +++ b/src/jit/corePlugins.js @@ -94,14 +94,36 @@ export default { }, pseudoClassVariants: function ({ config, addVariant }) { let pseudoVariants = [ + // Positional ['first', 'first-child'], ['last', 'last-child'], + ['only', 'only-child'], ['odd', 'nth-child(odd)'], ['even', 'nth-child(even)'], + 'first-of-type', + 'last-of-type', + 'only-of-type', + + // State 'visited', + + // Forms + 'default', 'checked', - 'empty', + 'indeterminate', + 'placeholder-shown', + 'autofill', + 'required', + 'valid', + 'invalid', + 'in-range', + 'out-of-range', 'read-only', + + // Content + 'empty', + + // Interactive 'focus-within', 'hover', 'focus', diff --git a/tests/jit/variants.test.css b/tests/jit/variants.test.css index b17ce1974b60..8eb3f867892b 100644 --- a/tests/jit/variants.test.css +++ b/tests/jit/variants.test.css @@ -13,11 +13,6 @@ --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; } -.shadow-md { - --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} .first-letter\:text-2xl::first-letter { font-size: 1.5rem; line-height: 2rem; @@ -76,6 +71,11 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.only\:shadow-md:only-child { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .odd\:shadow-md:nth-child(odd) { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -86,17 +86,77 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.first-of-type\:shadow-md:first-of-type { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.last-of-type\:shadow-md:last-of-type { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.only-of-type\:shadow-md:only-of-type { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .visited\:shadow-md:visited { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.target\:shadow-md:target { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.default\:shadow-md:default { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .checked\:shadow-md:checked { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.empty\:shadow-md:empty { +.indeterminate\:shadow-md:indeterminate { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.placeholder-shown\:shadow-md:placeholder-shown { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.autofill\:shadow-md:autofill { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.required\:shadow-md:required { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.valid\:shadow-md:valid { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.invalid\:shadow-md:invalid { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.in-range\:shadow-md:in-range { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.out-of-range\:shadow-md:out-of-range { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); @@ -106,6 +166,11 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.empty\:shadow-md:empty { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .focus-within\:shadow-md:focus-within { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -151,6 +216,11 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group:only-child .group-only\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .group:nth-child(odd) .group-odd\:shadow-md { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -161,16 +231,91 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group:first-of-type .group-first-of-type\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:last-of-type .group-last-of-type\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:only-of-type .group-only-of-type\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .group:visited .group-visited\:shadow-md { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group:target .group-target\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:default .group-default\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .group:checked .group-checked\:shadow-md { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group:indeterminate .group-indeterminate\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:placeholder-shown .group-placeholder-shown\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:autofill .group-autofill\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:required .group-required\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:valid .group-valid\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:invalid .group-invalid\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:in-range .group-in-range\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:out-of-range .group-out-of-range\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:read-only .group-read-only\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} +.group:empty .group-empty\:shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); +} .group:focus-within .group-focus-within\:shadow-md { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), diff --git a/tests/jit/variants.test.html b/tests/jit/variants.test.html index 0b359ff5857b..2439699af3c6 100644 --- a/tests/jit/variants.test.html +++ b/tests/jit/variants.test.html @@ -9,21 +9,34 @@ -
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
@@ -36,20 +49,34 @@
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
From 3a1f19e4fd590c88a23dcc1dd2230ca2f551f7dd Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Wed, 26 May 2021 16:28:50 -0400 Subject: [PATCH 4/6] Add target pseudo-class Co-Authored-By: Peter Neupauer --- src/jit/corePlugins.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jit/corePlugins.js b/src/jit/corePlugins.js index ffa59a962df1..2a49f381775f 100644 --- a/src/jit/corePlugins.js +++ b/src/jit/corePlugins.js @@ -106,6 +106,7 @@ export default { // State 'visited', + 'target', // Forms 'default', From 7ae608a5765a4d3e0acb33a8eccc6dddcb5bfc1d Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 27 May 2021 16:48:28 +0200 Subject: [PATCH 5/6] add test for parallel variants --- tests/jit/parallel-variants.test.js | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tests/jit/parallel-variants.test.js diff --git a/tests/jit/parallel-variants.test.js b/tests/jit/parallel-variants.test.js new file mode 100644 index 000000000000..aa658d44edcd --- /dev/null +++ b/tests/jit/parallel-variants.test.js @@ -0,0 +1,70 @@ +import postcss from 'postcss' +import path from 'path' +import tailwind from '../../src/jit/index.js' +import { transformAllSelectors, updateAllClasses } from '../../src/util/pluginUtils.js' + +function run(input, config = {}) { + const { currentTestName } = expect.getState() + + return postcss(tailwind(config)).process(input, { + from: `${path.resolve(__filename)}?test=${currentTestName}`, + }) +} + +test('basic parallel variants', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + theme: {}, + plugins: [ + function test({ addVariant, config }) { + addVariant('test', [ + transformAllSelectors((selector) => { + let variantSelector = updateAllClasses(selector, (className) => { + return `test${config('separator')}${className}` + }) + + return `${variantSelector} *::test` + }), + transformAllSelectors((selector) => { + return updateAllClasses(selector, (className, { withPseudo }) => { + return withPseudo(`test${config('separator')}${className}`, '::test') + }) + }), + ]) + }, + ], + } + + let css = `@tailwind utilities` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .font-normal { + font-weight: 400; + } + .test\\:font-bold *::test { + font-weight: 700; + } + .test\\:font-medium *::test { + font-weight: 500; + } + .hover\\:test\\:font-black:hover *::test { + font-weight: 900; + } + .test\\:font-bold::test { + font-weight: 700; + } + .test\\:font-medium::test { + font-weight: 500; + } + .hover\\:test\\:font-black:hover::test { + font-weight: 900; + } + `) + }) +}) From b0128bfe0a3798365278da4000795dc229bbd8bf Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 27 May 2021 16:48:46 +0200 Subject: [PATCH 6/6] implement parallel variants --- src/jit/corePlugins.js | 28 ++++++++++++----- src/jit/lib/generateRules.js | 53 +++++++++++++++++--------------- src/jit/lib/setupContextUtils.js | 28 ++++++++++++----- tests/jit/variants.test.css | 16 ++++++++++ 4 files changed, 85 insertions(+), 40 deletions(-) diff --git a/src/jit/corePlugins.js b/src/jit/corePlugins.js index 2a49f381775f..abc108a4e618 100644 --- a/src/jit/corePlugins.js +++ b/src/jit/corePlugins.js @@ -30,23 +30,35 @@ export default { }) ) - addVariant( - 'marker', + addVariant('marker', [ + transformAllSelectors((selector) => { + let variantSelector = updateAllClasses(selector, (className) => { + return `marker${config('separator')}${className}` + }) + + return `${variantSelector} *::marker` + }), transformAllSelectors((selector) => { return updateAllClasses(selector, (className, { withPseudo }) => { return withPseudo(`marker${config('separator')}${className}`, '::marker') }) - }) - ) + }), + ]) - addVariant( - 'selection', + addVariant('selection', [ + transformAllSelectors((selector) => { + let variantSelector = updateAllClasses(selector, (className) => { + return `selection${config('separator')}${className}` + }) + + return `${variantSelector} *::selection` + }), transformAllSelectors((selector) => { return updateAllClasses(selector, (className, { withPseudo }) => { return withPseudo(`selection${config('separator')}${className}`, '::selection') }) - }) - ) + }), + ]) addVariant( 'before', diff --git a/src/jit/lib/generateRules.js b/src/jit/lib/generateRules.js index 916a64181e57..7670d064777e 100644 --- a/src/jit/lib/generateRules.js +++ b/src/jit/lib/generateRules.js @@ -100,7 +100,7 @@ function applyVariant(variant, matches, context) { } if (context.variantMap.has(variant)) { - let [variantSort, applyThisVariant] = context.variantMap.get(variant) + let variantFunctionTuples = context.variantMap.get(variant) let result = [] for (let [{ sort, layer, options }, rule] of matches) { @@ -112,36 +112,39 @@ function applyVariant(variant, matches, context) { let container = postcss.root() container.append(rule.clone()) - function modifySelectors(modifierFunction) { - container.each((rule) => { - if (rule.type !== 'rule') { - return - } - - rule.selectors = rule.selectors.map((selector) => { - return modifierFunction({ - get className() { - return getClassNameFromSelector(selector) - }, - selector, + for (let [variantSort, variantFunction] of variantFunctionTuples) { + let clone = container.clone() + function modifySelectors(modifierFunction) { + clone.each((rule) => { + if (rule.type !== 'rule') { + return + } + + rule.selectors = rule.selectors.map((selector) => { + return modifierFunction({ + get className() { + return getClassNameFromSelector(selector) + }, + selector, + }) }) }) + return clone + } + + let ruleWithVariant = variantFunction({ + container: clone, + separator: context.tailwindConfig.separator, + modifySelectors, }) - return container - } - let ruleWithVariant = applyThisVariant({ - container, - separator: context.tailwindConfig.separator, - modifySelectors, - }) + if (ruleWithVariant === null) { + continue + } - if (ruleWithVariant === null) { - continue + let withOffset = [{ sort: variantSort | sort, layer, options }, clone.nodes[0]] + result.push(withOffset) } - - let withOffset = [{ sort: variantSort | sort, layer, options }, container.nodes[0]] - result.push(withOffset) } return result diff --git a/src/jit/lib/setupContextUtils.js b/src/jit/lib/setupContextUtils.js index f6f4f19dfb5a..a6e0e2abb827 100644 --- a/src/jit/lib/setupContextUtils.js +++ b/src/jit/lib/setupContextUtils.js @@ -13,6 +13,7 @@ import isPlainObject from '../../util/isPlainObject' import escapeClassName from '../../util/escapeClassName' import nameClass from '../../util/nameClass' import { coerceValue } from '../../util/pluginUtils' +import bigSign from '../../util/bigSign' import corePlugins from '../corePlugins' import * as sharedState from './sharedState' import { env } from './sharedState' @@ -152,9 +153,11 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs } return { - addVariant(variantName, applyThisVariant, options = {}) { + addVariant(variantName, variantFunctions, options = {}) { + variantFunctions = [].concat(variantFunctions) + insertInto(variantList, variantName, options) - variantMap.set(variantName, applyThisVariant) + variantMap.set(variantName, variantFunctions) }, postcss, prefix: applyConfiguredPrefix, @@ -445,17 +448,28 @@ function registerPlugins(plugins, context) { } reservedBits += 3n - context.variantOrder = variantList.reduce( - (map, variant, i) => map.set(variant, (1n << BigInt(i)) << reservedBits), - new Map() + + let offset = 0 + context.variantOrder = new Map( + variantList + .map((variant, i) => { + let variantFunctions = variantMap.get(variant).length + let bits = (1n << BigInt(i + offset)) << reservedBits + offset += variantFunctions - 1 + return [variant, bits] + }) + .sort(([, a], [, z]) => bigSign(a - z)) ) context.minimumScreen = [...context.variantOrder.values()].shift() // Build variantMap - for (let [variantName, variantFunction] of variantMap.entries()) { + for (let [variantName, variantFunctions] of variantMap.entries()) { let sort = context.variantOrder.get(variantName) - context.variantMap.set(variantName, [sort, variantFunction]) + context.variantMap.set( + variantName, + variantFunctions.map((variantFunction, idx) => [sort << BigInt(idx), variantFunction]) + ) } } diff --git a/tests/jit/variants.test.css b/tests/jit/variants.test.css index 8eb3f867892b..02e9b8a028ef 100644 --- a/tests/jit/variants.test.css +++ b/tests/jit/variants.test.css @@ -28,6 +28,14 @@ .first-line\:underline::first-line { text-decoration: underline; } +.marker\:text-lg *::marker { + font-size: 1.125rem; + line-height: 1.75rem; +} +.marker\:text-red-500 *::marker { + --tw-text-opacity: 1; + color: rgba(239, 68, 68, var(--tw-text-opacity)); +} .marker\:text-lg::marker { font-size: 1.125rem; line-height: 1.75rem; @@ -36,6 +44,14 @@ --tw-text-opacity: 1; color: rgba(239, 68, 68, var(--tw-text-opacity)); } +.selection\:bg-blue-500 *::selection { + --tw-bg-opacity: 1; + background-color: rgba(59, 130, 246, var(--tw-bg-opacity)); +} +.selection\:text-white *::selection { + --tw-text-opacity: 1; + color: rgba(255, 255, 255, var(--tw-text-opacity)); +} .selection\:bg-blue-500::selection { --tw-bg-opacity: 1; background-color: rgba(59, 130, 246, var(--tw-bg-opacity));