From 7e0465cb6be018506553eaeed5e4a519d1b72999 Mon Sep 17 00:00:00 2001 From: Jonathan Reinink Date: Tue, 28 Sep 2021 08:09:03 -0400 Subject: [PATCH 1/2] Add `[open]` variant Co-Authored-By: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Co-Authored-By: Sean Doyle <2575027+seanpdoyle@users.noreply.github.com> --- src/corePlugins.js | 47 ++++++++++++++++++++++++++-------------- src/util/pluginUtils.js | 22 +++++++++++++++++-- tests/variants.test.css | 16 ++++++++++++++ tests/variants.test.html | 4 ++++ 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index f3f04a638ed2..2ee4de22de88 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -10,6 +10,7 @@ import toColorValue from './util/toColorValue' import isPlainObject from './util/isPlainObject' import transformThemeValue from './util/transformThemeValue' import { + applyAttributeToMarker, applyPseudoToMarker, updateLastClasses, updateAllClasses, @@ -128,11 +129,11 @@ export default { pseudoClassVariants: ({ config, addVariant }) => { let pseudoVariants = [ // Positional - ['first', 'first-child'], - ['last', 'last-child'], - ['only', 'only-child'], - ['odd', 'nth-child(odd)'], - ['even', 'nth-child(even)'], + ['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', @@ -140,6 +141,7 @@ export default { // State 'visited', 'target', + ['open', '[open]'], // Forms 'default', @@ -167,19 +169,23 @@ export default { ] for (let variant of pseudoVariants) { - let [variantName, state] = Array.isArray(variant) ? variant : [variant, variant] + let [variantName, state] = Array.isArray(variant) ? variant : [variant, `:${variant}`] addVariant( variantName, - transformAllClasses((className, { withPseudo }) => { - return withPseudo(`${variantName}${config('separator')}${className}`, `:${state}`) + transformAllClasses((className, { withAttr, withPseudo }) => { + if (state.startsWith(':')) { + return withPseudo(`${variantName}${config('separator')}${className}`, state) + } else if (state.startsWith('[')) { + return withAttr(`${variantName}${config('separator')}${className}`, state) + } }) ) } let groupMarker = prefixSelector(config('prefix'), '.group') for (let variant of pseudoVariants) { - let [variantName, state] = Array.isArray(variant) ? variant : [variant, variant] + let [variantName, state] = Array.isArray(variant) ? variant : [variant, `:${variant}`] let groupVariantName = `group-${variantName}` addVariant( @@ -194,19 +200,28 @@ export default { return null } - return applyPseudoToMarker( - variantSelector, - groupMarker, - state, - (marker, selector) => `${marker} ${selector}` - ) + if (state.startsWith(':')) { + return applyPseudoToMarker( + variantSelector, + groupMarker, + state, + (marker, selector) => `${marker} ${selector}` + ) + } else if (state.startsWith('[')) { + return applyAttributeToMarker( + variantSelector, + groupMarker, + state, + (marker, selector) => `${marker} ${selector}` + ) + } }) ) } let peerMarker = prefixSelector(config('prefix'), '.peer') for (let variant of pseudoVariants) { - let [variantName, state] = Array.isArray(variant) ? variant : [variant, variant] + let [variantName, state] = Array.isArray(variant) ? variant : [variant, `:${variant}`] let peerVariantName = `peer-${variantName}` addVariant( diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js index 9fdbda93b381..d3146e40b285 100644 --- a/src/util/pluginUtils.js +++ b/src/util/pluginUtils.js @@ -18,8 +18,22 @@ import { lineWidth, } from './dataTypes' +export function applyAttributeToMarker(selector, marker, state, join) { + let markerIdx = selector.indexOf(marker + ':') + + if (markerIdx !== -1) { + let existingMarker = selector.slice(markerIdx, selector.indexOf(' ', markerIdx)) + + selector = selector.replace(existingMarker, '') + + return join(existingMarker.replace(marker + ':', `${marker}[${state.slice(1, -1)}]:`), selector) + } + + return join(`${marker}[${state.slice(1, -1)}]`, selector) +} + export function applyPseudoToMarker(selector, marker, state, join) { - let states = [state] + let states = [state.slice(1)] let markerIdx = selector.indexOf(marker + ':') @@ -40,8 +54,12 @@ export function updateAllClasses(selectors, updateClass) { let parser = selectorParser((selectors) => { selectors.walkClasses((sel) => { let updatedClass = updateClass(sel.value, { + withAttr(className, attr) { + sel.parent.insertAfter(sel, selectorParser.attribute({ attribute: attr.slice(1, -1) })) + return className + }, withPseudo(className, pseudo) { - sel.parent.insertAfter(sel, selectorParser.pseudo({ value: `${pseudo}` })) + sel.parent.insertAfter(sel, selectorParser.pseudo({ value: pseudo })) return className }, }) diff --git a/tests/variants.test.css b/tests/variants.test.css index 41e1b08f64e6..fb6d507f581f 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -127,6 +127,10 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.open\:bg-red-200[open] { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +} .default\:shadow-md:default { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -1px rgb(0 0 0 / 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -201,6 +205,10 @@ --tw-bg-opacity: 1; background-color: rgb(37 99 235 / var(--tw-bg-opacity)); } +.open\:hover\:bg-red-200[open]:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +} .focus\:shadow-md:focus { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -1px rgb(0 0 0 / 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -276,6 +284,10 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group[open] .group-open\:bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +} .group:default .group-default\:shadow-md { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -1px rgb(0 0 0 / 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -351,6 +363,10 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group[open]:focus .group-open\:group-focus\:bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +} .group:focus:hover .group-focus\:group-hover\:shadow-md { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -1px rgb(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/variants.test.html b/tests/variants.test.html index 70e1c1409c4d..da5c7b4eb140 100644 --- a/tests/variants.test.html +++ b/tests/variants.test.html @@ -22,6 +22,7 @@
+
@@ -50,6 +51,7 @@
+
@@ -128,6 +130,7 @@
+
@@ -137,6 +140,7 @@
+
From e10ca5776cacc730776ae8c678c9b2f7d6b54100 Mon Sep 17 00:00:00 2001 From: Jonathan Reinink Date: Tue, 28 Sep 2021 11:08:52 -0400 Subject: [PATCH 2/2] Add new `applyStateToMarker()` function This function replaces the existing `applyPseudoToMarker()` and `applyAttributeToMarker()` functions. Co-Authored-By: Robin Malfait <1834413+RobinMalfait@users.noreply.github.com> --- src/corePlugins.js | 26 ++++++++------------------ src/util/pluginUtils.js | 35 +++++++++-------------------------- tests/variants.test.css | 5 +++++ tests/variants.test.html | 1 + 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 2ee4de22de88..6d2dda708982 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -10,8 +10,7 @@ import toColorValue from './util/toColorValue' import isPlainObject from './util/isPlainObject' import transformThemeValue from './util/transformThemeValue' import { - applyAttributeToMarker, - applyPseudoToMarker, + applyStateToMarker, updateLastClasses, updateAllClasses, transformAllSelectors, @@ -200,21 +199,12 @@ export default { return null } - if (state.startsWith(':')) { - return applyPseudoToMarker( - variantSelector, - groupMarker, - state, - (marker, selector) => `${marker} ${selector}` - ) - } else if (state.startsWith('[')) { - return applyAttributeToMarker( - variantSelector, - groupMarker, - state, - (marker, selector) => `${marker} ${selector}` - ) - } + return applyStateToMarker( + variantSelector, + groupMarker, + state, + (marker, selector) => `${marker} ${selector}` + ) }) ) } @@ -236,7 +226,7 @@ export default { return null } - return applyPseudoToMarker(variantSelector, peerMarker, state, (marker, selector) => + return applyStateToMarker(variantSelector, peerMarker, state, (marker, selector) => selector.trim().startsWith('~') ? `${marker}${selector}` : `${marker} ~ ${selector}` ) }) diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js index d3146e40b285..4fa1bdf3ffe1 100644 --- a/src/util/pluginUtils.js +++ b/src/util/pluginUtils.js @@ -18,36 +18,19 @@ import { lineWidth, } from './dataTypes' -export function applyAttributeToMarker(selector, marker, state, join) { - let markerIdx = selector.indexOf(marker + ':') +export function applyStateToMarker(selector, marker, state, join) { + let markerIdx = selector.search(new RegExp(`${marker}[:[]`)) - if (markerIdx !== -1) { - let existingMarker = selector.slice(markerIdx, selector.indexOf(' ', markerIdx)) - - selector = selector.replace(existingMarker, '') - - return join(existingMarker.replace(marker + ':', `${marker}[${state.slice(1, -1)}]:`), selector) + if (markerIdx === -1) { + return join(marker + state, selector) } - return join(`${marker}[${state.slice(1, -1)}]`, selector) -} - -export function applyPseudoToMarker(selector, marker, state, join) { - let states = [state.slice(1)] - - let markerIdx = selector.indexOf(marker + ':') - - if (markerIdx !== -1) { - let existingMarker = selector.slice(markerIdx, selector.indexOf(' ', markerIdx)) - - states = states.concat( - selector.slice(markerIdx + marker.length + 1, existingMarker.length).split(':') - ) - - selector = selector.replace(existingMarker, '') - } + let markerSelector = selector.slice(markerIdx, selector.indexOf(' ', markerIdx)) - return join(`${[marker, ...states].join(':')}`, selector) + return join( + marker + state + markerSelector.slice(markerIdx + marker.length), + selector.replace(markerSelector, '') + ) } export function updateAllClasses(selectors, updateClass) { diff --git a/tests/variants.test.css b/tests/variants.test.css index fb6d507f581f..7bff0c6e072d 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -358,6 +358,11 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.group[open]:hover .group-open\:group-hover\:space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} .group:focus .group-focus\:shadow-md { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -1px rgb(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/variants.test.html b/tests/variants.test.html index da5c7b4eb140..335ce5375a80 100644 --- a/tests/variants.test.html +++ b/tests/variants.test.html @@ -141,6 +141,7 @@
+