diff --git a/CHANGELOG.md b/CHANGELOG.md index c30c0166b271..209022fba0c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Escape special characters in resolved content base paths ([#9650](https://github.com/tailwindlabs/tailwindcss/pull/9650)) - Don't reuse container for array returning variant functions ([#9644](https://github.com/tailwindlabs/tailwindcss/pull/9644)) +- Exclude non-relevant selectors when generating rules with the important modifier ([#9677](https://github.com/tailwindlabs/tailwindcss/issues/9677)) ## [3.2.1] - 2022-10-21 diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index f9fa374c186d..339440d00812 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -3,7 +3,7 @@ import selectorParser from 'postcss-selector-parser' import parseObjectStyles from '../util/parseObjectStyles' import isPlainObject from '../util/isPlainObject' import prefixSelector from '../util/prefixSelector' -import { updateAllClasses, getMatchingTypes } from '../util/pluginUtils' +import { updateAllClasses, filterSelectorsForClass, getMatchingTypes } from '../util/pluginUtils' import log from '../util/log' import * as sharedState from './sharedState' import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector' @@ -116,12 +116,15 @@ function applyImportant(matches, classCandidate) { for (let [meta, rule] of matches) { let container = postcss.root({ nodes: [rule.clone()] }) container.walkRules((r) => { - r.selector = updateAllClasses(r.selector, (className) => { - if (className === classCandidate) { - return `!${className}` + r.selector = updateAllClasses( + filterSelectorsForClass(r.selector, classCandidate), + (className) => { + if (className === classCandidate) { + return `!${className}` + } + return className } - return className - }) + ) r.walkDecls((d) => (d.important = true)) }) result.push([{ ...meta, important: true }, container.nodes[0]]) diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js index 6295bd2bfff2..5049b088e38e 100644 --- a/src/util/pluginUtils.js +++ b/src/util/pluginUtils.js @@ -37,6 +37,23 @@ export function updateAllClasses(selectors, updateClass) { return result } +export function filterSelectorsForClass(selectors, classCandidate) { + let parser = selectorParser((selectors) => { + selectors.each((sel) => { + const containsClass = sel.nodes.some( + (node) => node.type === 'class' && node.value === classCandidate + ) + if (!containsClass) { + sel.remove() + } + }) + }) + + let result = parser.processSync(selectors) + + return result +} + function resolveArbitraryValue(modifier, validate) { if (!isArbitraryValue(modifier)) { return undefined diff --git a/tests/important-modifier.test.js b/tests/important-modifier.test.js index e57c81340575..f6fd5f8224dc 100644 --- a/tests/important-modifier.test.js +++ b/tests/important-modifier.test.js @@ -13,12 +13,13 @@ test('important modifier', () => {
+
`, }, ], corePlugins: { preflight: false }, plugins: [ - function ({ theme, matchUtilities }) { + function ({ theme, matchUtilities, addComponents }) { matchUtilities( { 'custom-parent': (value) => { @@ -31,6 +32,13 @@ test('important modifier', () => { }, { values: theme('spacing') } ) + addComponents({ + '.btn': { + '&.disabled, &:disabled': { + color: 'gray', + }, + }, + }) }, ], } @@ -70,6 +78,13 @@ test('important modifier', () => { max-width: 1536px !important; } } + .btn.disabled, + .btn:disabled { + color: gray; + } + .btn.\!disabled { + color: gray !important; + } .\!font-bold { font-weight: 700 !important; }