diff --git a/src/plugins/backdropBlur.js b/src/plugins/backdropBlur.js index 256e16c23..9307a4232 100644 --- a/src/plugins/backdropBlur.js +++ b/src/plugins/backdropBlur.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-blur': (value) => { + 'backdrop-blur': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-blur': `blur(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropBrightness.js b/src/plugins/backdropBrightness.js index 9b2d9a2c7..05473f750 100644 --- a/src/plugins/backdropBrightness.js +++ b/src/plugins/backdropBrightness.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-brightness': (value) => { + 'backdrop-brightness': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-brightness': `brightness(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropContrast.js b/src/plugins/backdropContrast.js index 4b1f09cfb..e7b87f966 100644 --- a/src/plugins/backdropContrast.js +++ b/src/plugins/backdropContrast.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-contrast': (value) => { + 'backdrop-contrast': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-contrast': `contrast(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropFilter.js b/src/plugins/backdropFilter.js index a02f19a14..1a26651b1 100644 --- a/src/plugins/backdropFilter.js +++ b/src/plugins/backdropFilter.js @@ -1,8 +1,15 @@ -export default function () { - return function ({ config, addBase, addUtilities, variants }) { - if (config('mode') === 'jit') { - addBase({ - '*, ::before, ::after': { +import postcss from 'postcss' +import parseObjectStyles from '../util/parseObjectStyles' + +let baseRulesKey = Symbol() + +export function addBaseSelector(memory, selector) { + let baseRoot = memory.get(baseRulesKey) + + if (baseRoot.nodes.length === 0) { + baseRoot.append( + parseObjectStyles({ + [selector]: { '--tw-backdrop-blur': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-backdrop-brightness': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-backdrop-contrast': 'var(--tw-empty,/*!*/ /*!*/)', @@ -25,12 +32,35 @@ export default function () { ].join(' '), }, }) - addUtilities( + ) + } else { + baseRoot.nodes[0].selectors = [...baseRoot.nodes[0].selectors, selector] + } +} +export default function () { + return function ({ config, matchUtilities, addBase, addUtilities, variants, memory }) { + if (config('mode') === 'jit') { + let baseRoot = postcss.root() + memory.set(baseRulesKey, baseRoot) + addBase(baseRoot) + + matchUtilities( { - '.backdrop-filter': { 'backdrop-filter': 'var(--tw-backdrop-filter)' }, - '.backdrop-filter-none': { 'backdrop-filter': 'none' }, + 'backdrop-filter': (value, { selector }) => { + if (value !== 'none') { + addBaseSelector(memory, selector) + } + + return { + 'backdrop-filter': value, + } + }, }, - variants('backdropFilter') + { + values: { DEFAULT: 'var(--tw-backdrop-filter)', none: 'none' }, + variants: variants('backdropFilter'), + type: 'any', + } ) } else { addUtilities( diff --git a/src/plugins/backdropGrayscale.js b/src/plugins/backdropGrayscale.js index c3adc46d2..2666d6a64 100644 --- a/src/plugins/backdropGrayscale.js +++ b/src/plugins/backdropGrayscale.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-grayscale': (value) => { + 'backdrop-grayscale': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-grayscale': `grayscale(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropHueRotate.js b/src/plugins/backdropHueRotate.js index e40a22876..96358a747 100644 --- a/src/plugins/backdropHueRotate.js +++ b/src/plugins/backdropHueRotate.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-hue-rotate': (value) => { + 'backdrop-hue-rotate': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-hue-rotate': `hue-rotate(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropInvert.js b/src/plugins/backdropInvert.js index 46922c70b..824a5b44b 100644 --- a/src/plugins/backdropInvert.js +++ b/src/plugins/backdropInvert.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-invert': (value) => { + 'backdrop-invert': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-invert': `invert(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropOpacity.js b/src/plugins/backdropOpacity.js index d174c2bc3..432ac1c0f 100644 --- a/src/plugins/backdropOpacity.js +++ b/src/plugins/backdropOpacity.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-opacity': (value) => { + 'backdrop-opacity': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-opacity': `opacity(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropSaturate.js b/src/plugins/backdropSaturate.js index 6c96baa41..d00b8528b 100644 --- a/src/plugins/backdropSaturate.js +++ b/src/plugins/backdropSaturate.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-saturate': (value) => { + 'backdrop-saturate': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-saturate': `saturate(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/backdropSepia.js b/src/plugins/backdropSepia.js index c21fcda42..13a469c59 100644 --- a/src/plugins/backdropSepia.js +++ b/src/plugins/backdropSepia.js @@ -1,8 +1,14 @@ +import { addBaseSelector } from './backdropFilter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { + return function ({ config, matchUtilities, theme, variants, memory }) { matchUtilities( { - 'backdrop-sepia': (value) => { + 'backdrop-sepia': (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + return { '--tw-backdrop-sepia': `sepia(${value})`, ...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}), diff --git a/src/plugins/index.js b/src/plugins/index.js index 7fa4f7336..3ad3bd82b 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -147,6 +147,7 @@ export { default as invert } from './invert' export { default as saturate } from './saturate' export { default as sepia } from './sepia' +export { default as backdropFilter } from './backdropFilter' export { default as backdropBlur } from './backdropBlur' export { default as backdropBrightness } from './backdropBrightness' export { default as backdropContrast } from './backdropContrast' @@ -156,7 +157,6 @@ export { default as backdropInvert } from './backdropInvert' export { default as backdropOpacity } from './backdropOpacity' export { default as backdropSaturate } from './backdropSaturate' export { default as backdropSepia } from './backdropSepia' -export { default as backdropFilter } from './backdropFilter' export { default as transitionProperty } from './transitionProperty' export { default as transitionDelay } from './transitionDelay' diff --git a/tests/jit/backdrop-filter-utilities.test.js b/tests/jit/backdrop-filter-utilities.test.js new file mode 100644 index 000000000..25f395f00 --- /dev/null +++ b/tests/jit/backdrop-filter-utilities.test.js @@ -0,0 +1,230 @@ +import postcss from 'postcss' +import path from 'path' +import tailwind from '../../src/jit/index.js' + +function run(input, config = {}) { + const { currentTestName } = expect.getState() + + return postcss(tailwind(config)).process(input, { + from: `${path.resolve(__filename)}?test=${currentTestName}`, + }) +} + +test('without backdrop-filter class', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['backdropFilter', 'backdropBrightness', 'backdropContrast'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .backdrop-brightness-150, .backdrop-contrast-50 { + --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-opacity: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) + var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); + } + .backdrop-brightness-150 { + --tw-backdrop-brightness: brightness(1.5); + backdrop-filter: var(--tw-backdrop-filter); + } + .backdrop-contrast-50 { + --tw-backdrop-contrast: contrast(0.5); + backdrop-filter: var(--tw-backdrop-filter); + } + `) + }) +}) + +test('with backdrop-filter class', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '', + }, + ], + corePlugins: ['backdropFilter', 'backdropBrightness', 'backdropContrast'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .backdrop-filter, .backdrop-brightness-150, .backdrop-contrast-50 { + --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-opacity: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) + var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); + } + .backdrop-filter { + backdrop-filter: var(--tw-backdrop-filter); + } + .backdrop-brightness-150 { + --tw-backdrop-brightness: brightness(1.5); + backdrop-filter: var(--tw-backdrop-filter); + } + .backdrop-contrast-50 { + --tw-backdrop-contrast: contrast(0.5); + backdrop-filter: var(--tw-backdrop-filter); + } + `) + }) +}) + +test('with backdrop-filter-none class', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '', + }, + ], + corePlugins: ['backdropFilter', 'backdropBrightness', 'backdropContrast'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .backdrop-brightness-150, .backdrop-contrast-50 { + --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-opacity: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) + var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); + } + .backdrop-filter-none { + backdrop-filter: none; + } + .backdrop-brightness-150 { + --tw-backdrop-brightness: brightness(1.5); + backdrop-filter: var(--tw-backdrop-filter); + } + .backdrop-contrast-50 { + --tw-backdrop-contrast: contrast(0.5); + backdrop-filter: var(--tw-backdrop-filter); + } + `) + }) +}) + +test('with variants', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '', + }, + ], + corePlugins: ['backdropFilter', 'backdropBrightness', 'backdropContrast'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .backdrop-brightness-100, .hover\\:backdrop-brightness-150, .backdrop-contrast-50, .lg\\:backdrop-contrast-100 { + --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-opacity: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) + var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); + } + .backdrop-brightness-100 { + --tw-backdrop-brightness: brightness(1); + backdrop-filter: var(--tw-backdrop-filter); + } + .backdrop-contrast-50 { + --tw-backdrop-contrast: contrast(0.5); + backdrop-filter: var(--tw-backdrop-filter); + } + .hover\\:backdrop-brightness-150:hover { + --tw-backdrop-brightness: brightness(1.5); + backdrop-filter: var(--tw-backdrop-filter); + } + @media (min-width: 1024px) { + .lg\\:backdrop-contrast-100 { + --tw-backdrop-contrast: contrast(1); + backdrop-filter: var(--tw-backdrop-filter); + } + } + `) + }) +}) + +test('without any filter classes', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '', + }, + ], + corePlugins: ['filter', 'brightness', 'contrast'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) diff --git a/tests/jit/basic-usage.test.css b/tests/jit/basic-usage.test.css index 8b570b69e..d104ab12c 100644 --- a/tests/jit/basic-usage.test.css +++ b/tests/jit/basic-usage.test.css @@ -54,9 +54,16 @@ --tw-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -*, -::before, -::after { +.backdrop-filter, +.backdrop-blur-lg, +.backdrop-brightness-50, +.backdrop-contrast-0, +.backdrop-grayscale, +.backdrop-hue-rotate-90, +.backdrop-invert, +.backdrop-opacity-75, +.backdrop-saturate-150, +.backdrop-sepia { --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -768,6 +775,12 @@ --tw-sepia: sepia(100%); filter: var(--tw-filter); } +.backdrop-filter { + backdrop-filter: var(--tw-backdrop-filter); +} +.backdrop-filter-none { + backdrop-filter: none; +} .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); backdrop-filter: var(--tw-backdrop-filter); @@ -804,12 +817,6 @@ --tw-backdrop-sepia: sepia(100%); backdrop-filter: var(--tw-backdrop-filter); } -.backdrop-filter { - backdrop-filter: var(--tw-backdrop-filter); -} -.backdrop-filter-none { - backdrop-filter: none; -} .transition { transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;