Skip to content

Commit

Permalink
Add * variant for targeting direct children (#12551)
Browse files Browse the repository at this point in the history
* add `*` as child variant

* add `*` as allowed variant character

* update test to reflect Lightning CSS output

* add `childVariant` test

* Update changelog

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Gregor Kaczmarczyk <github@aggreggator.de>
  • Loading branch information
4 people authored and thecrypticace committed Dec 18, 2023
1 parent 7642e28 commit 47dbb4a
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `forced-colors` variant ([#11694](https://github.com/tailwindlabs/tailwindcss/pull/11694))
- Add `appearance-auto` utility ([#12404](https://github.com/tailwindlabs/tailwindcss/pull/12404))
- Add logical property values for `float` and `clear` utilities ([#12480](https://github.com/tailwindlabs/tailwindcss/pull/12480))
- Add `*` variant for targeting direct children ([#12551](https://github.com/tailwindlabs/tailwindcss/pull/12551))

### Changed

Expand Down
12 changes: 11 additions & 1 deletion oxide/crates/core/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ impl<'a> Extractor<'a> {
}

// Allowed first characters.
b'@' | b'!' | b'-' | b'<' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => {
b'@' | b'!' | b'-' | b'<' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' | b'*' => {
// TODO: A bunch of characters that we currently support but maybe we only want it behind
// a flag. E.g.: '<sm'
// | '<' | '>' | '$' | '^' | '_'
Expand Down Expand Up @@ -329,6 +329,7 @@ impl<'a> Extractor<'a> {
| b'!'
| b'@'
| b'%'
| b'*'
if prev != b']' =>
{
/* TODO: The `b'@'` is necessary for custom separators like _@, maybe we can handle this in a better way... */
Expand Down Expand Up @@ -508,6 +509,15 @@ mod test {
assert_eq!(candidates, vec!["hover:underline"]);
}

#[test]
fn it_can_parse_start_variants() {
let candidates = run("*:underline", false);
assert_eq!(candidates, vec!["*:underline"]);

let candidates = run("hover:*:underline", false);
assert_eq!(candidates, vec!["hover:*:underline"]);
}

#[test]
fn it_can_parse_simple_candidates_with_stacked_variants() {
let candidates = run("focus:hover:underline", false);
Expand Down
3 changes: 3 additions & 0 deletions src/corePlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import { normalize } from './util/dataTypes'
import { INTERNAL_FEATURES } from './lib/setupContextUtils'

export let variantPlugins = {
childVariant: ({ addVariant }) => {
addVariant('*', '& > *')
},
pseudoElementVariants: ({ addVariant }) => {
addVariant('first-letter', '&::first-letter')
addVariant('first-line', '&::first-line')
Expand Down
1 change: 1 addition & 0 deletions src/lib/setupContextUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ function resolvePlugins(context, root) {
// TODO: This is a workaround for backwards compatibility, since custom variants
// were historically sorted before screen/stackable variants.
let beforeVariants = [
variantPlugins['childVariant'],
variantPlugins['pseudoElementVariants'],
variantPlugins['pseudoClassVariants'],
variantPlugins['hasVariants'],
Expand Down
33 changes: 33 additions & 0 deletions tests/variants.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1201,4 +1201,37 @@ crosscheck(({ stable, oxide }) => {
}
`)
})

test('* is matched by the parser as the children variant', async () => {
let config = {
content: [
{
raw: html`
<div class="*:italic" />
<div class="*:hover:italic" />
<div class="hover:*:italic" />
<div class="data-[slot=label]:*:hover:italic" />
<div class="[&_p]:*:hover:italic" />
`,
},
],
corePlugins: { preflight: false },
}

let input = css`
@tailwind utilities;
`

let result = await run(input, config)

expect(result.css).toMatchFormattedCss(css`
.\*\:italic > *,
.\*\:hover\:italic:hover > *,
.hover\:\*\:italic > :hover,
.data-\[slot\=label\]\:\*\:hover\:italic:hover > [data-slot='label'],
.\[\&_p\]\:\*\:hover\:italic:hover > * p {
font-style: italic;
}
`)
})
})

0 comments on commit 47dbb4a

Please sign in to comment.