From 7b6bc50931ea347929adfd0924fdcb4d3da74d85 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 9 Jan 2024 15:10:19 -0500 Subject: [PATCH] Split `:has` rules when using `experimental.optimizeUniversalDefaults` (#12736) * Split `:has` rules when using optimizeUniversalDefaults * Update changelog --- CHANGELOG.md | 1 + src/lib/resolveDefaultsAtRules.js | 6 ++- tests/resolve-defaults-at-rules.test.js | 55 +++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e0c8d8eafc2..7068723d50ef 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 - Ensure max specificity of `0,0,1` for button and input Preflight rules ([#12735](https://github.com/tailwindlabs/tailwindcss/pull/12735)) - Improve glob handling for folders with `(`, `)`, `[` or `]` in the file path ([#12715](https://github.com/tailwindlabs/tailwindcss/pull/12715)) +- Split `:has` rules when using `experimental.optimizeUniversalDefaults` ([#12736](https://github.com/tailwindlabs/tailwindcss/pull/12736)) ### Added diff --git a/src/lib/resolveDefaultsAtRules.js b/src/lib/resolveDefaultsAtRules.js index 389ea4bacac7..621cdaf6f765 100644 --- a/src/lib/resolveDefaultsAtRules.js +++ b/src/lib/resolveDefaultsAtRules.js @@ -104,8 +104,12 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) { // we consider them separately because merging the declarations into // a single rule will cause browsers that do not understand the // vendor prefix to throw out the whole rule + // Additionally if a selector contains `:has` we also consider + // it separately because FF only recently gained support for it let selectorGroupName = - selector.includes(':-') || selector.includes('::-') ? selector : '__DEFAULT__' + selector.includes(':-') || selector.includes('::-') || selector.includes(':has') + ? selector + : '__DEFAULT__' let selectors = selectorGroups.get(selectorGroupName) ?? new Set() selectorGroups.set(selectorGroupName, selectors) diff --git a/tests/resolve-defaults-at-rules.test.js b/tests/resolve-defaults-at-rules.test.js index 32bc25b6fb93..a00f4da7386e 100644 --- a/tests/resolve-defaults-at-rules.test.js +++ b/tests/resolve-defaults-at-rules.test.js @@ -842,3 +842,58 @@ test('no defaults and apply without @tailwind base', () => { `) }) }) + +test('optimize universal defaults groups :has separately', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [ + { raw: html`
` }, + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .ring-1 { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .has-\[\:checked\]\:ring-1:has(:checked) { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .ring-1 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .has-\[\:checked\]\:ring-1:has(:checked) { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +})