Remove text opacity CSS variables from ::marker (#8622)

* Refactor

* Allow parallel variant fns to mutate the container

* Remove text color variable from marker pseudo class

wip

* Update changelog
This commit is contained in:
Jordan Pittman 2022-06-14 10:09:09 -04:00 committed by GitHub
parent 22eaad17c3
commit 15dc5a3da9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 32 deletions

View File

@ -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

View File

@ -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')
@ -77,21 +90,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'
},

View File

@ -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

View File

@ -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})`, '')
}
}
})
}

View File

@ -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`<div
class="hover:test:font-black test:font-bold test:font-medium font-normal"
></div>`,
},
],
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);
}
`)
})
})

View File

@ -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;

View File

@ -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 [