diff --git a/CHANGELOG.md b/CHANGELOG.md index 73b0620facdf..0f8dce96de86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Oxide] Enable relative content paths for the `oxide` engine ([#10621](https://github.com/tailwindlabs/tailwindcss/pull/10621)) - Mark `rtl` and `ltr` variants as stable and remove warnings ([#10764](https://github.com/tailwindlabs/tailwindcss/pull/10764)) - Use `inset` instead of `top`, `right`, `bottom`, and `left` properties ([#10765](https://github.com/tailwindlabs/tailwindcss/pull/10765)) +- Make `dark` and `rtl`/`ltr` variants insensitive to DOM order ([#10766](https://github.com/tailwindlabs/tailwindcss/pull/10766)) ## [3.2.7] - 2023-02-16 diff --git a/src/corePlugins.js b/src/corePlugins.js index 4a97713fabe6..717c9ec5c350 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -199,8 +199,8 @@ export let variantPlugins = { }, directionVariants: ({ addVariant }) => { - addVariant('ltr', '[dir="ltr"] &') - addVariant('rtl', '[dir="rtl"] &') + addVariant('ltr', ':is([dir="ltr"] &)') + addVariant('rtl', ':is([dir="rtl"] &)') }, reducedMotionVariants: ({ addVariant }) => { @@ -221,7 +221,7 @@ export let variantPlugins = { } if (mode === 'class') { - addVariant('dark', `${className} &`) + addVariant('dark', `:is(${className} &)`) } else if (mode === 'media') { addVariant('dark', '@media (prefers-color-scheme: dark)') } diff --git a/tests/apply.test.js b/tests/apply.test.js index cb5c6be068a6..14b84550a8a8 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -216,14 +216,14 @@ crosscheck(({ stable, oxide }) => { text-align: left; } } - .dark .apply-dark-variant { + :is(.dark .apply-dark-variant) { text-align: center; } - .dark .apply-dark-variant:hover { + :is(.dark .apply-dark-variant:hover) { text-align: right; } @media (min-width: 1024px) { - .dark .apply-dark-variant { + :is(.dark .apply-dark-variant) { text-align: left; } } @@ -513,14 +513,14 @@ crosscheck(({ stable, oxide }) => { text-align: left; } } - .dark .apply-dark-variant { + :is(.dark .apply-dark-variant) { text-align: center; } - .dark .apply-dark-variant:hover { + :is(.dark .apply-dark-variant:hover) { text-align: right; } @media (min-width: 1024px) { - .dark .apply-dark-variant { + :is(.dark .apply-dark-variant) { text-align: left; } } diff --git a/tests/custom-separator.test.js b/tests/custom-separator.test.js index 8e788c5519ff..adc1d55afd65 100644 --- a/tests/custom-separator.test.js +++ b/tests/custom-separator.test.js @@ -23,7 +23,7 @@ crosscheck(() => { .group:hover .group-hover_focus-within_text-left:focus-within { text-align: left; } - [dir='rtl'] .rtl_active_text-center:active { + :is([dir='rtl'] .rtl_active_text-center:active) { text-align: center; } @media (prefers-reduced-motion: no-preference) { @@ -31,7 +31,7 @@ crosscheck(() => { text-align: center; } } - .dark .dark_focus_text-left:focus { + :is(.dark .dark_focus_text-left:focus) { text-align: left; } @media (min-width: 768px) { diff --git a/tests/dark-mode.test.js b/tests/dark-mode.test.js index 2a1cbf43dd07..ce06496b2124 100644 --- a/tests/dark-mode.test.js +++ b/tests/dark-mode.test.js @@ -17,7 +17,7 @@ crosscheck(() => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} - .dark .dark\:font-bold { + :is(.dark .dark\:font-bold) { font-weight: 700; } `) @@ -40,7 +40,7 @@ crosscheck(() => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} - .test-dark .dark\:font-bold { + :is(.test-dark .dark\:font-bold) { font-weight: 700; } `) diff --git a/tests/important-boolean.test.js b/tests/important-boolean.test.js index a7524e1f8fc1..895ca053c901 100644 --- a/tests/important-boolean.test.js +++ b/tests/important-boolean.test.js @@ -138,7 +138,7 @@ crosscheck(() => { .group:hover .group-hover\:focus-within\:text-left:focus-within { text-align: left !important; } - [dir='rtl'] .rtl\:active\:text-center:active { + :is([dir='rtl'] .rtl\:active\:text-center:active) { text-align: center !important; } @media (prefers-reduced-motion: no-preference) { @@ -146,7 +146,7 @@ crosscheck(() => { text-align: center !important; } } - .dark .dark\:focus\:text-left:focus { + :is(.dark .dark\:focus\:text-left:focus) { text-align: left !important; } @media (min-width: 768px) { diff --git a/tests/important-selector.test.js b/tests/important-selector.test.js index cfa094342042..044037be1114 100644 --- a/tests/important-selector.test.js +++ b/tests/important-selector.test.js @@ -134,7 +134,7 @@ crosscheck(() => { #app .group:hover .group-hover\:focus-within\:text-left:focus-within { text-align: left; } - #app [dir='rtl'] .rtl\:active\:text-center:active { + #app :is([dir='rtl'] .rtl\:active\:text-center:active) { text-align: center; } @media (prefers-reduced-motion: no-preference) { @@ -142,7 +142,7 @@ crosscheck(() => { text-align: center; } } - #app .dark .dark\:focus\:text-left:focus { + #app :is(.dark .dark\:focus\:text-left:focus) { text-align: left; } @media (min-width: 768px) { diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index d6d74225d293..a421e3a0b374 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -303,7 +303,7 @@ crosscheck(({ stable, oxide }) => { } .drop-empty-rules:hover, .group:hover .apply-group, - .dark .apply-dark-mode { + :is(.dark .apply-dark-mode) { font-weight: 700; } .apply-with-existing:hover { @@ -338,7 +338,7 @@ crosscheck(({ stable, oxide }) => { .apply-order-b { margin: 1.5rem 1.25rem 1.25rem; } - .dark .group:hover .apply-dark-group-example-a { + :is(.dark .group:hover .apply-dark-group-example-a) { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } @@ -715,7 +715,7 @@ crosscheck(({ stable, oxide }) => { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } } - .dark .dark\:custom-util { + :is(.dark .dark\:custom-util) { background: #abcdef; } @media (min-width: 640px) { @@ -762,7 +762,7 @@ crosscheck(({ stable, oxide }) => { transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } - .dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active { + :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { background: #abcdef !important; } } @@ -849,7 +849,7 @@ crosscheck(({ stable, oxide }) => { } .drop-empty-rules:hover, .group:hover .apply-group, - .dark .apply-dark-mode { + :is(.dark .apply-dark-mode) { font-weight: 700; } .apply-with-existing:hover { @@ -883,7 +883,7 @@ crosscheck(({ stable, oxide }) => { .apply-order-b { margin: 1.5rem 1.25rem 1.25rem; } - .dark .group:hover .apply-dark-group-example-a { + :is(.dark .group:hover .apply-dark-group-example-a) { background-color: #22c55e; } @media (min-width: 640px) { @@ -1250,7 +1250,7 @@ crosscheck(({ stable, oxide }) => { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } } - .dark .dark\:custom-util { + :is(.dark .dark\:custom-util) { background: #abcdef; } @media (min-width: 640px) { @@ -1297,7 +1297,7 @@ crosscheck(({ stable, oxide }) => { transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } - .dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active { + :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { background: #abcdef !important; } } diff --git a/tests/prefix.test.js b/tests/prefix.test.js index e0139ad9a979..ea3d041ffeac 100644 --- a/tests/prefix.test.js +++ b/tests/prefix.test.js @@ -128,7 +128,7 @@ crosscheck(({ stable, oxide }) => { .custom-component { font-weight: 700; } - .tw-dark .tw-group:hover .custom-component { + :is(.tw-dark .tw-group:hover .custom-component) { font-weight: 400; } .tw--ml-4 { @@ -155,7 +155,7 @@ crosscheck(({ stable, oxide }) => { .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { text-align: left; } - [dir='rtl'] .rtl\:active\:tw-text-center:active { + :is([dir='rtl'] .rtl\:active\:tw-text-center:active) { text-align: center; } @media (prefers-reduced-motion: no-preference) { @@ -163,11 +163,11 @@ crosscheck(({ stable, oxide }) => { text-align: center; } } - .tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\] { + :is(.tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { --tw-bg-opacity: 1; background-color: rgb(255 0 0 / var(--tw-bg-opacity)); } - .tw-dark .dark\:focus\:tw-text-left:focus { + :is(.tw-dark .dark\:focus\:tw-text-left:focus) { text-align: left; } @media (min-width: 768px) { diff --git a/tests/variants.oxide.test.css b/tests/variants.oxide.test.css index db3a5283f1a1..c2a490f4a805 100644 --- a/tests/variants.oxide.test.css +++ b/tests/variants.oxide.test.css @@ -283,8 +283,8 @@ .peer:disabled ~ .peer-disabled\:shadow-md, .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:shadow-md, .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md:first-child, -[dir="ltr"] .ltr\:shadow-md, -[dir="rtl"] .rtl\:shadow-md { +:is([dir='ltr'] .ltr\:shadow-md), +:is([dir='rtl'] .rtl\:shadow-md) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -318,9 +318,9 @@ background-color: #fde047; } } -.dark .dark\:shadow-md, -.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md, -.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md { +:is(.dark .dark\:shadow-md), +:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md), +:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -361,7 +361,7 @@ animation: 1s linear infinite spin; } .lg\:shadow-md, - .dark .lg\:dark\:shadow-md { + :is(.dark .lg\:dark\:shadow-md) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); @@ -371,7 +371,7 @@ } @media (min-width: 1280px) { .xl\:shadow-md, - .dark .xl\:dark\:disabled\:shadow-md:disabled { + :is(.dark .xl\:dark\:disabled\:shadow-md:disabled) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); @@ -388,7 +388,7 @@ var(--tw-shadow); } @media (prefers-reduced-motion: no-preference) { - .dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within { + :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); @@ -407,4 +407,3 @@ background-color: #fde047; } } - diff --git a/tests/variants.test.css b/tests/variants.test.css index 7d0120d127a6..2f8181cf23c4 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -299,8 +299,8 @@ .peer:disabled ~ .peer-disabled\:shadow-md, .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:shadow-md, .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md:first-child, -[dir='ltr'] .ltr\:shadow-md, -[dir='rtl'] .rtl\:shadow-md { +:is([dir='ltr'] .ltr\:shadow-md), +:is([dir='rtl'] .rtl\:shadow-md) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -336,9 +336,9 @@ background-color: rgb(253 224 71 / var(--tw-bg-opacity)); } } -.dark .dark\:shadow-md, -.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md, -.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md { +:is(.dark .dark\:shadow-md), +:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md), +:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -380,7 +380,7 @@ animation: 1s linear infinite spin; } .lg\:shadow-md, - .dark .lg\:dark\:shadow-md { + :is(.dark .lg\:dark\:shadow-md) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); @@ -390,7 +390,7 @@ } @media (min-width: 1280px) { .xl\:shadow-md, - .dark .xl\:dark\:disabled\:shadow-md:disabled { + :is(.dark .xl\:dark\:disabled\:shadow-md:disabled) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); @@ -407,7 +407,7 @@ var(--tw-shadow); } @media (prefers-reduced-motion: no-preference) { - .dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within { + :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within) { --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); diff --git a/tests/variants.test.js b/tests/variants.test.js index a762745f082f..09c8ee538d08 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -1128,4 +1128,28 @@ crosscheck(({ stable, oxide }) => { } `) }) + + test('stacking dark and rtl variants', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + :is(.dark :is([dir='rtl'] .dark\:rtl\:italic)) { + font-style: italic; + } + `) + }) })