JIT: Add exhaustive pseudo-class and pseudo-element variant support (#4482)

* Add first-line, first-letter, and marker variants

* Add selection variant

Co-Authored-By: Eric Rodrigues Pires <eric@eric.dev.br>

* Add remaining pseudo-class variants

* Add target pseudo-class

Co-Authored-By: Peter Neupauer <peter@neupauer.sk>

* add test for parallel variants

* implement parallel variants

Co-authored-by: Eric Rodrigues Pires <eric@eric.dev.br>
Co-authored-by: Peter Neupauer <peter@neupauer.sk>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This commit is contained in:
Adam Wathan 2021-05-27 11:09:29 -04:00 committed by GitHub
parent 8cd60171e0
commit d1e9632064
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 438 additions and 54 deletions

View File

@ -11,7 +11,55 @@ 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) => {
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', [
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',
transformAllSelectors(
@ -55,16 +103,40 @@ 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',
'target',
// 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',

View File

@ -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
}
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,
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
if (ruleWithVariant === null) {
continue
}
let withOffset = [{ sort: variantSort | sort, layer, options }, clone.nodes[0]]
result.push(withOffset)
}
let ruleWithVariant = applyThisVariant({
container,
separator: context.tailwindConfig.separator,
modifySelectors,
})
if (ruleWithVariant === null) {
continue
}
let withOffset = [{ sort: variantSort | sort, layer, options }, container.nodes[0]]
result.push(withOffset)
}
return result

View File

@ -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,
@ -395,7 +398,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'],
@ -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])
)
}
}

View File

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

View File

@ -13,10 +13,52 @@
--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;
}
.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));
}
.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));
}
.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));
}
.selection\:text-white::selection {
--tw-text-opacity: 1;
color: rgba(255, 255, 255, var(--tw-text-opacity));
}
.before\:block::before {
content: '';
@ -45,6 +87,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),
@ -55,17 +102,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);
@ -75,6 +182,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),
@ -120,6 +232,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),
@ -130,16 +247,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),

View File

@ -9,41 +9,74 @@
</head>
<body>
<!-- Basic pseudo variants -->
<div class="shadow-md"></div>
<div class="first:shadow-md"></div>
<div class="last:shadow-md"></div>
<div class="only:shadow-md"></div>
<div class="even:shadow-md"></div>
<div class="odd:shadow-md"></div>
<div class="first-of-type:shadow-md"></div>
<div class="last-of-type:shadow-md"></div>
<div class="only-of-type:shadow-md"></div>
<div class="hover:shadow-md"></div>
<div class="focus:shadow-md"></div>
<div class="disabled:shadow-md"></div>
<div class="active:shadow-md"></div>
<div class="first:shadow-md"></div>
<div class="last:shadow-md"></div>
<div class="even:shadow-md"></div>
<div class="odd:shadow-md"></div>
<div class="target:shadow-md"></div>
<div class="visited:shadow-md"></div>
<div class="default:shadow-md"></div>
<div class="checked:shadow-md"></div>
<div class="indeterminate:shadow-md"></div>
<div class="placeholder-shown:shadow-md"></div>
<div class="autofill:shadow-md"></div>
<div class="focus-within:shadow-md"></div>
<div class="focus-visible:shadow-md"></div>
<div class="empty:shadow-md"></div>
<div class="required:shadow-md"></div>
<div class="valid:shadow-md"></div>
<div class="invalid:shadow-md"></div>
<div class="in-range:shadow-md"></div>
<div class="out-of-range:shadow-md"></div>
<div class="read-only:shadow-md"></div>
<div class="empty:shadow-md"></div>
<!-- Pseudo-element variants -->
<div class="first-letter:text-red-500 first-letter:text-2xl"></div>
<div class="first-line:underline first-line:bg-yellow-300"></div>
<ul>
<li class="marker:text-red-500 marker:text-lg"></li>
</ul>
<div class="selection:bg-blue-500 selection:text-white"></div>
<div class="before:block before:bg-red-500"></div>
<div class="after:flex after:uppercase"></div>
<!-- Group variants -->
<div class="group-first:shadow-md"></div>
<div class="group-last:shadow-md"></div>
<div class="group-only:shadow-md"></div>
<div class="group-even:shadow-md"></div>
<div class="group-odd:shadow-md"></div>
<div class="group-first-of-type:shadow-md"></div>
<div class="group-last-of-type:shadow-md"></div>
<div class="group-only-of-type:shadow-md"></div>
<div class="group-hover:shadow-md"></div>
<div class="group-focus:shadow-md"></div>
<div class="group-disabled:shadow-md"></div>
<div class="group-active:shadow-md"></div>
<div class="group-first:shadow-md"></div>
<div class="group-last:shadow-md"></div>
<div class="group-even:shadow-md"></div>
<div class="group-odd:shadow-md"></div>
<div class="group-odd:shadow-md"></div>
<div class="group-target:shadow-md"></div>
<div class="group-visited:shadow-md"></div>
<div class="group-default:shadow-md"></div>
<div class="group-checked:shadow-md"></div>
<div class="group-indeterminate:shadow-md"></div>
<div class="group-placeholder-shown:shadow-md"></div>
<div class="group-autofill:shadow-md"></div>
<div class="group-focus-within:shadow-md"></div>
<div class="group-focus-visible:shadow-md"></div>
<div class="group-focus-visible:shadow-md"></div>
<div class="group-required:shadow-md"></div>
<div class="group-valid:shadow-md"></div>
<div class="group-invalid:shadow-md"></div>
<div class="group-in-range:shadow-md"></div>
<div class="group-out-of-range:shadow-md"></div>
<div class="group-read-only:shadow-md"></div>
<div class="group-empty:shadow-md"></div>
<!-- Reduced motion variants -->
<div class="motion-safe:shadow-md"></div>