From debb014f8dd35ee101841e2a166cd51126d256e4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 14 Jun 2022 09:49:26 -0400 Subject: [PATCH 1/4] Refactor --- src/corePlugins.js | 20 +++++--------------- src/util/removeAlphaVariables.js | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 src/util/removeAlphaVariables.js diff --git a/src/corePlugins.js b/src/corePlugins.js index f1ad4a823d24..60e47ec056f8 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -77,21 +77,11 @@ export let variantPlugins = { [ 'visited', ({ container }) => { - let toRemove = ['--tw-text-opacity', '--tw-border-opacity', '--tw-bg-opacity'] - - container.walkDecls((decl) => { - if (toRemove.includes(decl.prop)) { - decl.remove() - - return - } - - for (const varName of toRemove) { - if (decl.value.includes(`/ var(${varName})`)) { - decl.value = decl.value.replace(`/ var(${varName})`, '') - } - } - }) + removeAlphaVariables(container, [ + '--tw-text-opacity', + '--tw-border-opacity', + '--tw-bg-opacity', + ]) return '&:visited' }, diff --git a/src/util/removeAlphaVariables.js b/src/util/removeAlphaVariables.js new file mode 100644 index 000000000000..76655bea2bbd --- /dev/null +++ b/src/util/removeAlphaVariables.js @@ -0,0 +1,24 @@ +/** + * This function removes any uses of CSS variables used as an alpha channel + * + * This is required for selectors like `:visited` which do not allow + * changes in opacity or external control using CSS variables. + * + * @param {import('postcss').Container} container + * @param {string[]} toRemove + */ +export function removeAlphaVariables(container, toRemove) { + container.walkDecls((decl) => { + if (toRemove.includes(decl.prop)) { + decl.remove() + + return + } + + for (let varName of toRemove) { + if (decl.value.includes(`/ var(${varName})`)) { + decl.value = decl.value.replace(`/ var(${varName})`, '') + } + } + }) +} From 946045c1ff047d281096d7f2ad23223790194b06 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 13 Jun 2022 14:05:32 -0400 Subject: [PATCH 2/4] Allow parallel variant fns to mutate the container --- src/lib/generateRules.js | 28 ++++++++++++------- tests/parallel-variants.test.js | 49 +++++++++++++++++++++++++++++++++ tests/variants.test.js | 3 +- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index c5f82d8c391c..fa790a455230 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -163,15 +163,17 @@ function applyVariant(variant, matches, context) { let container = postcss.root({ nodes: [rule.clone()] }) - for (let [variantSort, variantFunction] of variantFunctionTuples) { - let clone = container.clone() + for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples) { + let clone = containerFromArray ?? container.clone() let collectedFormats = [] - let originals = new Map() - function prepareBackup() { - if (originals.size > 0) return // Already prepared, chicken out - clone.walkRules((rule) => originals.set(rule, rule.selector)) + // Already prepared, chicken out + if (clone.raws.neededBackup) { + return + } + clone.raws.neededBackup = true + clone.walkRules((rule) => (rule.raws.originalSelector = rule.selector)) } function modifySelectors(modifierFunction) { @@ -231,6 +233,10 @@ function applyVariant(variant, matches, context) { // reserving additional X places for these 'unknown' variants in between. variantSort | BigInt(idx << ruleWithVariant.length), variantFunction, + + // If the clone has been modified we have to pass that back + // though so each rule can use the modified container + clone.clone(), ]) } continue @@ -244,13 +250,15 @@ function applyVariant(variant, matches, context) { continue } - // We filled the `originals`, therefore we assume that somebody touched + // We had to backup selectors, therefore we assume that somebody touched // `container` or `modifySelectors`. Let's see if they did, so that we // can restore the selectors, and collect the format strings. - if (originals.size > 0) { + if (clone.raws.neededBackup) { + delete clone.raws.neededBackup clone.walkRules((rule) => { - if (!originals.has(rule)) return - let before = originals.get(rule) + let before = rule.raws.originalSelector + if (!before) return + delete rule.raws.originalSelector if (before === rule.selector) return // No mutation happened let modified = rule.selector diff --git a/tests/parallel-variants.test.js b/tests/parallel-variants.test.js index f1be86832884..3ad7a084bda6 100644 --- a/tests/parallel-variants.test.js +++ b/tests/parallel-variants.test.js @@ -85,3 +85,52 @@ test('parallel variants can be generated using a function that returns parallel `) }) }) + +test('a function that returns parallel variants can modify the container', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', ({ container }) => { + container.walkDecls((decl) => { + decl.value = `calc(0 + ${decl.value})` + }) + + return ['& *::test', '&::test'] + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold *::test { + font-weight: calc(0 + 700); + } + .test\:font-medium *::test { + font-weight: calc(0 + 500); + } + .test\:font-bold::test { + font-weight: calc(0 + 700); + } + .test\:font-medium::test { + font-weight: calc(0 + 500); + } + .hover\:test\:font-black *:hover::test { + font-weight: calc(0 + 900); + } + .hover\:test\:font-black:hover::test { + font-weight: calc(0 + 900); + } + `) + }) +}) diff --git a/tests/variants.test.js b/tests/variants.test.js index d7ab82b81ada..06fc18456304 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -485,8 +485,7 @@ test('returning non-strings and non-selectors in addVariant', () => { addVariant('peer-aria-expanded-2', ({ modifySelectors, separator }) => { let nodes = modifySelectors( - ({ className }) => - `.peer[aria-expanded="false"] ~ .${e(`peer-aria-expanded${separator}${className}`)}` + ({ className }) => `.${e(`peer-aria-expanded-2${separator}${className}`)}` ) return [ From 82259c1ac8f14a8d38b50dfde48c1bbd1d5d1dc1 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 14 Jun 2022 09:57:03 -0400 Subject: [PATCH 3/4] Remove text color variable from marker pseudo class wip --- src/corePlugins.js | 15 ++++++++++++++- tests/variants.test.css | 6 ++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 60e47ec056f8..5781905db4b5 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -14,6 +14,7 @@ import { version as tailwindVersion } from '../package.json' import log from './util/log' import { normalizeScreens } from './util/normalizeScreens' import { formatBoxShadowValue, parseBoxShadowValue } from './util/parseBoxShadowValue' +import { removeAlphaVariables } from './util/removeAlphaVariables' import { flagEnabled } from './featureFlags' export let variantPlugins = { @@ -21,7 +22,19 @@ export let variantPlugins = { addVariant('first-letter', '&::first-letter') addVariant('first-line', '&::first-line') - addVariant('marker', ['& *::marker', '&::marker']) + addVariant('marker', [ + ({ container }) => { + removeAlphaVariables(container, ['--tw-text-opacity']) + + return '& *::marker' + }, + ({ container }) => { + removeAlphaVariables(container, ['--tw-text-opacity']) + + return '&::marker' + }, + ]) + addVariant('selection', ['& *::selection', '&::selection']) addVariant('file', '&::file-selector-button') diff --git a/tests/variants.test.css b/tests/variants.test.css index 535ffa23177e..56131baba1d8 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -112,16 +112,14 @@ line-height: 1.75rem; } .marker\:text-red-500 *::marker { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); + color: rgb(239 68 68); } .marker\:text-lg::marker { font-size: 1.125rem; line-height: 1.75rem; } .marker\:text-red-500::marker { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); + color: rgb(239 68 68); } .selection\:bg-blue-500 *::selection { --tw-bg-opacity: 1; From 4e856b10693fb1efeb0a037c26b51d4f4ab957b3 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 14 Jun 2022 09:59:08 -0400 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c4d88d42187..8ca9cd83b3b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix missing spaces around arithmetic operators ([#8615](https://github.com/tailwindlabs/tailwindcss/pull/8615)) - Detect alpha value in CSS `theme()` function when using quotes ([#8625](https://github.com/tailwindlabs/tailwindcss/pull/8625)) - Fix "Maximum call stack size exceeded" bug ([#8636](https://github.com/tailwindlabs/tailwindcss/pull/8636)) +- Allow functions returning parallel variants to mutate the container ([#8622](https://github.com/tailwindlabs/tailwindcss/pull/8622)) +- Remove text opacity CSS variables from `::marker` ([#8622](https://github.com/tailwindlabs/tailwindcss/pull/8622)) ## [3.1.2] - 2022-06-10