Skip to content

Commit

Permalink
Move important selector to the front when @apply-ing selector-mod…
Browse files Browse the repository at this point in the history
…ifying variants in custom utilities (#8313)

* Fix generated utilities using `@apply` with important selectors

* Update changelog
  • Loading branch information
thecrypticace authored May 9, 2022
1 parent be51739 commit b49dc7c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove default `[hidden]` style in preflight ([#8248](https://github.com/tailwindlabs/tailwindcss/pull/8248))
- Only check selectors containing base apply candidates for circular dependencies ([#8222](https://github.com/tailwindlabs/tailwindcss/pull/8222))
- Rewrite default class extractor ([#8204](https://github.com/tailwindlabs/tailwindcss/pull/8204))
- Move `important` selector to the front when `@apply`-ing selector-modifying variants in custom utilities ([#8313](https://github.com/tailwindlabs/tailwindcss/pull/8313))

### Changed

Expand Down
22 changes: 21 additions & 1 deletion src/lib/expandApplyAtRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,27 @@ function processApply(root, context, localCache) {
return
}

rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate)
// Strip the important selector from the parent selector if at the beginning
let importantSelector =
typeof context.tailwindConfig.important === 'string'
? context.tailwindConfig.important
: null

// We only want to move the "important" selector if this is a Tailwind-generated utility
// We do *not* want to do this for user CSS that happens to be structured the same
let isGenerated = parent.raws.tailwind !== undefined

let parentSelector =
isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0
? parent.selector.slice(importantSelector.length)
: parent.selector

rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate)

// And then re-add it if it was removed
if (importantSelector && parentSelector !== parent.selector) {
rule.selector = `${importantSelector} ${rule.selector}`
}

rule.walkDecls((d) => {
d.important = meta.important || important
Expand Down
81 changes: 81 additions & 0 deletions tests/apply.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1467,3 +1467,84 @@ it('should apply using the updated user CSS when the source has changed', async
}
`)
})

it('apply + layer utilities + selector variants (like group) + important selector', async () => {
let config = {
important: '#myselector',
content: [{ raw: html`<div class="custom-utility"></div>` }],
plugins: [],
}

let input = css`
@tailwind utilities;
@layer utilities {
.custom-utility {
@apply font-normal group-hover:underline;
}
}
`

let result = await run(input, config)

expect(result.css).toMatchFormattedCss(css`
#myselector .custom-utility {
font-weight: 400;
}
#myselector .group:hover .custom-utility {
text-decoration-line: underline;
}
`)
})

it('apply + user CSS + selector variants (like group) + important selector (1)', async () => {
let config = {
important: '#myselector',
content: [{ raw: html`<div class="custom-utility"></div>` }],
plugins: [],
}

let input = css`
.custom-utility {
@apply font-normal group-hover:underline;
}
`

let result = await run(input, config)

expect(result.css).toMatchFormattedCss(css`
.custom-utility {
font-weight: 400;
}
.group:hover .custom-utility {
text-decoration-line: underline;
}
`)
})

it('apply + user CSS + selector variants (like group) + important selector (2)', async () => {
let config = {
important: '#myselector',
content: [{ raw: html`<div class="custom-utility"></div>` }],
plugins: [],
}

let input = css`
#myselector .custom-utility {
@apply font-normal group-hover:underline;
}
`

let result = await run(input, config)

expect(result.css).toMatchFormattedCss(css`
#myselector .custom-utility {
font-weight: 400;
}
.group:hover #myselector .custom-utility {
text-decoration-line: underline;
}
`)
})

0 comments on commit b49dc7c

Please sign in to comment.