From 04d66b0f4787fabb080753a3d0ccde20e7bc11ca Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Thu, 24 Jun 2021 17:01:36 -0400 Subject: [PATCH] WIP Still gotta do shadows + backdrop filter --- src/jit/lib/collapseAdjacentRules.js | 4 + src/jit/lib/generateRules.js | 2 +- src/jit/lib/setupContextUtils.js | 5 +- src/plugins/blur.js | 52 ++++-- src/plugins/brightness.js | 52 ++++-- src/plugins/contrast.js | 48 +++-- src/plugins/dropShadow.js | 53 ++++-- src/plugins/filter.js | 49 ++++- src/plugins/grayscale.js | 52 ++++-- src/plugins/hueRotate.js | 52 ++++-- src/plugins/index.js | 4 +- src/plugins/invert.js | 52 ++++-- src/plugins/rotate.js | 13 +- src/plugins/saturate.js | 52 ++++-- src/plugins/scale.js | 19 +- src/plugins/sepia.js | 44 +++-- src/plugins/skew.js | 17 +- src/plugins/transform.js | 60 ++++-- src/plugins/translate.js | 17 +- src/util/createUtilityPlugin.js | 7 +- tests/jit/arbitrary-values.test.css | 69 ++++++- tests/jit/arbitrary-values.test.js | 1 + tests/jit/basic-usage.test.css | 66 +++++-- tests/jit/filter-utilities.test.js | 233 ++++++++++++++++++++++++ tests/jit/important-boolean.test.css | 14 ++ tests/jit/important-boolean.test.html | 1 + tests/jit/kitchen-sink.test.css | 11 -- tests/jit/prefix.test.css | 14 ++ tests/jit/prefix.test.html | 1 + tests/jit/raw-content.test.css | 65 +++---- tests/jit/relative-purge-paths.test.css | 81 ++++---- tests/jit/transform-utilities.test.js | 231 +++++++++++++++++++++++ tests/jit/variants.test.css | 11 -- 33 files changed, 1154 insertions(+), 298 deletions(-) create mode 100644 tests/jit/filter-utilities.test.js create mode 100644 tests/jit/transform-utilities.test.js diff --git a/src/jit/lib/collapseAdjacentRules.js b/src/jit/lib/collapseAdjacentRules.js index 8a7c5775c..a77049a1b 100644 --- a/src/jit/lib/collapseAdjacentRules.js +++ b/src/jit/lib/collapseAdjacentRules.js @@ -8,6 +8,10 @@ export default function collapseAdjacentRules() { return (root) => { let currentRule = null root.each((node) => { + if (node.nodes && node.nodes.length === 0) { + node.remove() + return + } if (!types.has(node.type)) { currentRule = null return diff --git a/src/jit/lib/generateRules.js b/src/jit/lib/generateRules.js index c510942b1..4b8b5d377 100644 --- a/src/jit/lib/generateRules.js +++ b/src/jit/lib/generateRules.js @@ -226,7 +226,7 @@ function* resolveMatches(candidate, context) { for (let [sort, plugin] of plugins) { if (typeof plugin === 'function') { - for (let ruleSet of [].concat(plugin(modifier))) { + for (let ruleSet of [].concat(plugin(modifier, { candidate }))) { let [rules, options] = parseRules(ruleSet, context.postCssNodeCache) for (let rule of rules) { matches.push([{ ...sort, options: { ...sort.options, ...options } }, rule]) diff --git a/src/jit/lib/setupContextUtils.js b/src/jit/lib/setupContextUtils.js index 8a41d0b3c..92d834dfa 100644 --- a/src/jit/lib/setupContextUtils.js +++ b/src/jit/lib/setupContextUtils.js @@ -151,6 +151,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs } return { + memory: context.memory, addVariant(variantName, variantFunctions, options = {}) { variantFunctions = [].concat(variantFunctions) @@ -264,7 +265,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs let prefixedIdentifier = prefixIdentifier(identifier, options) let rule = utilities[identifier] - function wrapped(modifier) { + function wrapped(modifier, { candidate }) { let { type = 'any' } = options type = [].concat(type) let [value, coercedType] = coerceValue(type, modifier, options.values, tailwindConfig) @@ -277,6 +278,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs let ruleSets = [] .concat( rule(value, { + selector: `.${escapeClassName(candidate)}`, includeRules(rules) { includedRules.push(...rules) }, @@ -497,6 +499,7 @@ export function createContext( changedContent: changedContent, variantMap: new Map(), stylesheetCache: null, + memory: new Map(), } let resolvedPlugins = resolvePlugins(context, tailwindDirectives, root) diff --git a/src/plugins/blur.js b/src/plugins/blur.js index f668d8f74..9cadb6bb5 100644 --- a/src/plugins/blur.js +++ b/src/plugins/blur.js @@ -1,19 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - blur: (value) => { - return { - '--tw-blur': `blur(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + blur: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-blur': `blur(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { - values: theme('blur'), - variants: variants('blur'), - type: 'any', - } - ) + { + values: theme('blur'), + variants: variants('blur'), + type: 'any', + } + ) + } else { + matchUtilities( + { + blur: (value) => { + return { + '--tw-blur': `blur(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('blur'), + variants: variants('blur'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/brightness.js b/src/plugins/brightness.js index b08b63d25..425d45d24 100644 --- a/src/plugins/brightness.js +++ b/src/plugins/brightness.js @@ -1,19 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - brightness: (value) => { - return { - '--tw-brightness': `brightness(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + brightness: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-brightness': `brightness(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { - values: theme('brightness'), - variants: variants('brightness'), - type: 'any', - } - ) + { + values: theme('brightness'), + variants: variants('brightness'), + type: 'any', + } + ) + } else { + matchUtilities( + { + brightness: (value) => { + return { + '--tw-brightness': `brightness(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('brightness'), + variants: variants('brightness'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/contrast.js b/src/plugins/contrast.js index 521eaf1a2..12bc38f2b 100644 --- a/src/plugins/contrast.js +++ b/src/plugins/contrast.js @@ -1,15 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - contrast: (value) => { - return { - '--tw-contrast': `contrast(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + contrast: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-contrast': `contrast(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { values: theme('contrast'), variants: variants('contrast'), type: 'any' } - ) + { + values: theme('contrast'), + variants: variants('contrast'), + type: 'any', + } + ) + } else { + matchUtilities( + { + contrast: (value) => { + return { + '--tw-contrast': `contrast(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('contrast'), + variants: variants('contrast'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/dropShadow.js b/src/plugins/dropShadow.js index 674464e98..acbdb5361 100644 --- a/src/plugins/dropShadow.js +++ b/src/plugins/dropShadow.js @@ -1,22 +1,45 @@ import _ from 'lodash' import nameClass from '../util/nameClass' +import { addBaseSelector } from './filter' export default function () { - return function ({ config, addUtilities, theme, variants }) { - const utilities = _.fromPairs( - _.map(theme('dropShadow'), (value, modifier) => { - return [ - nameClass('drop-shadow', modifier), - { - '--tw-drop-shadow': Array.isArray(value) - ? value.map((v) => `drop-shadow(${v})`).join(' ') - : `drop-shadow(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - }, - ] - }) - ) + return function ({ config, matchUtilities, addUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + 'drop-shadow': (value, { selector }) => { + addBaseSelector(memory, selector) - addUtilities(utilities, variants('dropShadow')) + return { + '--tw-drop-shadow': Array.isArray(value) + ? value.map((v) => `drop-shadow(${v})`).join(' ') + : `drop-shadow(${value})`, + filter: 'var(--tw-filter)', + } + }, + }, + { + values: theme('dropShadow'), + variants: variants('dropShadow'), + type: 'lookup', + } + ) + } else { + const utilities = _.fromPairs( + _.map(theme('dropShadow'), (value, modifier) => { + return [ + nameClass('drop-shadow', modifier), + { + '--tw-drop-shadow': Array.isArray(value) + ? value.map((v) => `drop-shadow(${v})`).join(' ') + : `drop-shadow(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + }, + ] + }) + ) + + addUtilities(utilities, variants('dropShadow')) + } } } diff --git a/src/plugins/filter.js b/src/plugins/filter.js index 017e5d560..53ab98a17 100644 --- a/src/plugins/filter.js +++ b/src/plugins/filter.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-blur': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-brightness': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-contrast': 'var(--tw-empty,/*!*/ /*!*/)', @@ -25,12 +32,36 @@ 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( { - '.filter': { filter: 'var(--tw-filter)' }, - '.filter-none': { filter: 'none' }, + filter: (value, { selector }) => { + if (value !== 'none') { + addBaseSelector(memory, selector) + } + + return { + filter: value, + } + }, }, - variants('filter') + { + values: { DEFAULT: 'var(--tw-filter)', none: 'none' }, + variants: variants('filter'), + type: 'any', + } ) } else { addUtilities( diff --git a/src/plugins/grayscale.js b/src/plugins/grayscale.js index 97bad401e..150f2bd5d 100644 --- a/src/plugins/grayscale.js +++ b/src/plugins/grayscale.js @@ -1,19 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - grayscale: (value) => { - return { - '--tw-grayscale': `grayscale(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + grayscale: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-grayscale': `grayscale(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { - values: theme('grayscale'), - variants: variants('grayscale'), - type: 'any', - } - ) + { + values: theme('grayscale'), + variants: variants('grayscale'), + type: 'any', + } + ) + } else { + matchUtilities( + { + grayscale: (value) => { + return { + '--tw-grayscale': `grayscale(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('grayscale'), + variants: variants('grayscale'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/hueRotate.js b/src/plugins/hueRotate.js index 8b9fa4115..ce9d90be4 100644 --- a/src/plugins/hueRotate.js +++ b/src/plugins/hueRotate.js @@ -1,19 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - 'hue-rotate': (value) => { - return { - '--tw-hue-rotate': `hue-rotate(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + 'hue-rotate': (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-hue-rotate': `hue-rotate(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { - values: theme('hueRotate'), - variants: variants('hueRotate'), - type: 'any', - } - ) + { + values: theme('hueRotate'), + variants: variants('hueRotate'), + type: 'any', + } + ) + } else { + matchUtilities( + { + 'hue-rotate': (value) => { + return { + '--tw-hue-rotate': `hue-rotate(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('hueRotate'), + variants: variants('hueRotate'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/index.js b/src/plugins/index.js index be8f4b284..7fa4f7336 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -34,11 +34,11 @@ export { default as tableLayout } from './tableLayout' export { default as borderCollapse } from './borderCollapse' export { default as transformOrigin } from './transformOrigin' +export { default as transform } from './transform' export { default as translate } from './translate' export { default as rotate } from './rotate' export { default as skew } from './skew' export { default as scale } from './scale' -export { default as transform } from './transform' export { default as animation } from './animation' @@ -136,6 +136,7 @@ export { default as ringOpacity } from './ringOpacity' export { default as ringOffsetWidth } from './ringOffsetWidth' export { default as ringOffsetColor } from './ringOffsetColor' +export { default as filter } from './filter' export { default as blur } from './blur' export { default as brightness } from './brightness' export { default as contrast } from './contrast' @@ -145,7 +146,6 @@ export { default as hueRotate } from './hueRotate' export { default as invert } from './invert' export { default as saturate } from './saturate' export { default as sepia } from './sepia' -export { default as filter } from './filter' export { default as backdropBlur } from './backdropBlur' export { default as backdropBrightness } from './backdropBrightness' diff --git a/src/plugins/invert.js b/src/plugins/invert.js index 4eb42a218..7962157cb 100644 --- a/src/plugins/invert.js +++ b/src/plugins/invert.js @@ -1,19 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - invert: (value) => { - return { - '--tw-invert': `invert(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + invert: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-invert': `invert(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { - values: theme('invert'), - variants: variants('invert'), - type: 'any', - } - ) + { + values: theme('invert'), + variants: variants('invert'), + type: 'any', + } + ) + } else { + matchUtilities( + { + invert: (value) => { + return { + '--tw-invert': `invert(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('invert'), + variants: variants('invert'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/rotate.js b/src/plugins/rotate.js index 0d7151254..c4e7f1557 100644 --- a/src/plugins/rotate.js +++ b/src/plugins/rotate.js @@ -1,11 +1,18 @@ +import { addBaseSelector } from './transform' import createUtilityPlugin from '../util/createUtilityPlugin' export default function () { return function ({ config, ...rest }) { if (config('mode') === 'jit') { - return createUtilityPlugin('rotate', [ - ['rotate', ['--tw-rotate', ['transform', 'var(--tw-transform)']]], - ])({ config, ...rest }) + return createUtilityPlugin( + 'rotate', + [['rotate', ['--tw-rotate', ['transform', 'var(--tw-transform)']]]], + { + lolback(_value, { selector }) { + addBaseSelector(rest.memory, selector) + }, + } + )({ config, ...rest }) } else { return createUtilityPlugin('rotate', [['rotate', ['--tw-rotate']]])({ config, ...rest }) } diff --git a/src/plugins/saturate.js b/src/plugins/saturate.js index 192dad7ad..3dd5f9bd7 100644 --- a/src/plugins/saturate.js +++ b/src/plugins/saturate.js @@ -1,19 +1,41 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - saturate: (value) => { - return { - '--tw-saturate': `saturate(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + saturate: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-saturate': `saturate(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { - values: theme('saturate'), - variants: variants('saturate'), - type: 'any', - } - ) + { + values: theme('saturate'), + variants: variants('saturate'), + type: 'any', + } + ) + } else { + matchUtilities( + { + saturate: (value) => { + return { + '--tw-saturate': `saturate(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { + values: theme('saturate'), + variants: variants('saturate'), + type: 'any', + } + ) + } } } diff --git a/src/plugins/scale.js b/src/plugins/scale.js index 6637039d7..addef4fc8 100644 --- a/src/plugins/scale.js +++ b/src/plugins/scale.js @@ -1,15 +1,24 @@ +import { addBaseSelector } from './transform' import createUtilityPlugin from '../util/createUtilityPlugin' export default function () { return function ({ config, ...rest }) { if (config('mode') === 'jit') { - return createUtilityPlugin('scale', [ - ['scale', ['--tw-scale-x', '--tw-scale-y', ['transform', 'var(--tw-transform)']]], + return createUtilityPlugin( + 'scale', [ - ['scale-x', ['--tw-scale-x', ['transform', 'var(--tw-transform)']]], - ['scale-y', ['--tw-scale-y', ['transform', 'var(--tw-transform)']]], + ['scale', ['--tw-scale-x', '--tw-scale-y', ['transform', 'var(--tw-transform)']]], + [ + ['scale-x', ['--tw-scale-x', ['transform', 'var(--tw-transform)']]], + ['scale-y', ['--tw-scale-y', ['transform', 'var(--tw-transform)']]], + ], ], - ])({ config, ...rest }) + { + lolback(_value, { selector }) { + addBaseSelector(rest.memory, selector) + }, + } + )({ config, ...rest }) } else { return createUtilityPlugin('scale', [ ['scale', ['--tw-scale-x', '--tw-scale-y']], diff --git a/src/plugins/sepia.js b/src/plugins/sepia.js index 0d73697e0..88f47a4f2 100644 --- a/src/plugins/sepia.js +++ b/src/plugins/sepia.js @@ -1,15 +1,37 @@ +import { addBaseSelector } from './filter' + export default function () { - return function ({ config, matchUtilities, theme, variants }) { - matchUtilities( - { - sepia: (value) => { - return { - '--tw-sepia': `sepia(${value})`, - ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), - } + return function ({ config, matchUtilities, theme, variants, memory }) { + if (config('mode') === 'jit') { + matchUtilities( + { + sepia: (value, { selector }) => { + addBaseSelector(memory, selector) + + return { + '--tw-sepia': `sepia(${value})`, + filter: 'var(--tw-filter)', + } + }, }, - }, - { values: theme('sepia'), variants: variants('sepia'), type: 'any' } - ) + { + values: theme('sepia'), + variants: variants('sepia'), + type: 'any', + } + ) + } else { + matchUtilities( + { + sepia: (value) => { + return { + '--tw-sepia': `sepia(${value})`, + ...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}), + } + }, + }, + { values: theme('sepia'), variants: variants('sepia'), type: 'any' } + ) + } } } diff --git a/src/plugins/skew.js b/src/plugins/skew.js index 5ad20446f..f48418c7b 100644 --- a/src/plugins/skew.js +++ b/src/plugins/skew.js @@ -1,14 +1,23 @@ +import { addBaseSelector } from './transform' import createUtilityPlugin from '../util/createUtilityPlugin' export default function () { return function ({ config, ...rest }) { if (config('mode') === 'jit') { - return createUtilityPlugin('skew', [ + return createUtilityPlugin( + 'skew', [ - ['skew-x', ['--tw-skew-x', ['transform', 'var(--tw-transform)']]], - ['skew-y', ['--tw-skew-y', ['transform', 'var(--tw-transform)']]], + [ + ['skew-x', ['--tw-skew-x', ['transform', 'var(--tw-transform)']]], + ['skew-y', ['--tw-skew-y', ['transform', 'var(--tw-transform)']]], + ], ], - ])({ config, ...rest }) + { + lolback(_value, { selector }) { + addBaseSelector(rest.memory, selector) + }, + } + )({ config, ...rest }) } else { return createUtilityPlugin('skew', [ [ diff --git a/src/plugins/transform.js b/src/plugins/transform.js index 0cd2c46b5..5c0c1c4b2 100644 --- a/src/plugins/transform.js +++ b/src/plugins/transform.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-translate-x': '0', '--tw-translate-y': '0', '--tw-rotate': '0', @@ -21,13 +28,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( { - '.transform': { - transform: 'var(--tw-transform)', + transform: (value, { selector }) => { + if (value !== 'none') { + addBaseSelector(memory, selector) + } + + return { + transform: value, + } }, - '.transform-cpu': { - '--tw-transform': [ + }, + { + values: { + DEFAULT: 'var(--tw-transform)', + cpu: [ 'translateX(var(--tw-translate-x))', 'translateY(var(--tw-translate-y))', 'rotate(var(--tw-rotate))', @@ -36,9 +65,7 @@ export default function () { 'scaleX(var(--tw-scale-x))', 'scaleY(var(--tw-scale-y))', ].join(' '), - }, - '.transform-gpu': { - '--tw-transform': [ + gpu: [ 'translate3d(var(--tw-translate-x), var(--tw-translate-y), 0)', 'rotate(var(--tw-rotate))', 'skewX(var(--tw-skew-x))', @@ -46,10 +73,11 @@ export default function () { 'scaleX(var(--tw-scale-x))', 'scaleY(var(--tw-scale-y))', ].join(' '), + none: 'none', }, - '.transform-none': { transform: 'none' }, - }, - variants('transform') + variants: variants('transform'), + type: 'any', + } ) } else { addUtilities( diff --git a/src/plugins/translate.js b/src/plugins/translate.js index 9d81ac312..1076d9794 100644 --- a/src/plugins/translate.js +++ b/src/plugins/translate.js @@ -1,14 +1,23 @@ +import { addBaseSelector } from './transform' import createUtilityPlugin from '../util/createUtilityPlugin' export default function () { return function ({ config, ...rest }) { if (config('mode') === 'jit') { - return createUtilityPlugin('translate', [ + return createUtilityPlugin( + 'translate', [ - ['translate-x', ['--tw-translate-x', ['transform', 'var(--tw-transform)']]], - ['translate-y', ['--tw-translate-y', ['transform', 'var(--tw-transform)']]], + [ + ['translate-x', ['--tw-translate-x', ['transform', 'var(--tw-transform)']]], + ['translate-y', ['--tw-translate-y', ['transform', 'var(--tw-transform)']]], + ], ], - ])({ config, ...rest }) + { + lolback(_value, { selector }) { + addBaseSelector(rest.memory, selector) + }, + } + )({ config, ...rest }) } else { return createUtilityPlugin('translate', [ [ diff --git a/src/util/createUtilityPlugin.js b/src/util/createUtilityPlugin.js index ad87bc294..d397a61a6 100644 --- a/src/util/createUtilityPlugin.js +++ b/src/util/createUtilityPlugin.js @@ -13,7 +13,7 @@ let asMap = new Map([ export default function createUtilityPlugin( themeKey, utilityVariations = [[themeKey, [themeKey]]], - { filterDefault = false, resolveArbitraryValue = asValue } = {} + { filterDefault = false, resolveArbitraryValue = asValue, lolback = () => {} } = {} ) { let transformValue = transformThemeValue(themeKey) return function ({ matchUtilities, variants, theme }) { @@ -23,7 +23,10 @@ export default function createUtilityPlugin( matchUtilities( group.reduce((obj, [classPrefix, properties]) => { return Object.assign(obj, { - [classPrefix]: (value) => { + [classPrefix]: (value, helpers) => { + // Holy shit I can't believe this is real + lolback(value, helpers) + return properties.reduce((obj, name) => { if (Array.isArray(name)) { return Object.assign(obj, { [name[0]]: name[1] }) diff --git a/tests/jit/arbitrary-values.test.css b/tests/jit/arbitrary-values.test.css index 9c6e41c97..5d666fc57 100644 --- a/tests/jit/arbitrary-values.test.css +++ b/tests/jit/arbitrary-values.test.css @@ -1,3 +1,64 @@ +*, +::before, +::after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + --tw-border-opacity: 1; + border-color: rgba(229, 231, 235, var(--tw-border-opacity)); + --tw-shadow: 0 0 #0000; + --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgba(59, 130, 246, 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; +} +.blur-\[15px\], +.brightness-\[300\%\], +.contrast-\[2\.4\], +.grayscale-\[0\.55\], +.hue-rotate-\[0\.8turn\], +.invert-\[0\.75\], +.saturate-\[180\%\], +.sepia-\[0\.2\] { + --tw-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); + --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); + filter: var(--tw-filter); +} +*, +::before, +::after { + --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); +} .inset-\[11px\] { top: 11px; right: 11px; @@ -319,35 +380,27 @@ } .blur-\[15px\] { --tw-blur: blur(15px); - filter: var(--tw-filter); } .brightness-\[300\%\] { --tw-brightness: brightness(300%); - filter: var(--tw-filter); } .contrast-\[2\.4\] { --tw-contrast: contrast(2.4); - filter: var(--tw-filter); } .grayscale-\[0\.55\] { --tw-grayscale: grayscale(0.55); - filter: var(--tw-filter); } .hue-rotate-\[0\.8turn\] { --tw-hue-rotate: hue-rotate(0.8turn); - filter: var(--tw-filter); } .invert-\[0\.75\] { --tw-invert: invert(0.75); - filter: var(--tw-filter); } .saturate-\[180\%\] { --tw-saturate: saturate(180%); - filter: var(--tw-filter); } .sepia-\[0\.2\] { --tw-sepia: sepia(0.2); - filter: var(--tw-filter); } .backdrop-blur-\[11px\] { --tw-backdrop-blur: blur(11px); diff --git a/tests/jit/arbitrary-values.test.js b/tests/jit/arbitrary-values.test.js index ef1fcf692..7a0b22fdb 100644 --- a/tests/jit/arbitrary-values.test.js +++ b/tests/jit/arbitrary-values.test.js @@ -17,6 +17,7 @@ test('arbitrary values', () => { } let css = ` + @tailwind base; @tailwind utilities; ` diff --git a/tests/jit/basic-usage.test.css b/tests/jit/basic-usage.test.css index e4ceeffd3..8b570b69e 100644 --- a/tests/jit/basic-usage.test.css +++ b/tests/jit/basic-usage.test.css @@ -1,6 +1,13 @@ -*, -::before, -::after { +.rotate-3, +.scale-95, +.skew-y-12, +.skew-x-12, +.transform, +.transform-gpu, +.translate-x-5, +.-translate-x-4, +.translate-y-6, +.-translate-x-3 { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -11,6 +18,10 @@ --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} +*, +::before, +::after { --tw-border-opacity: 1; border-color: rgba(229, 231, 235, var(--tw-border-opacity)); --tw-shadow: 0 0 #0000; @@ -20,6 +31,17 @@ --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; +} +.filter, +.blur-md, +.brightness-150, +.contrast-50, +.drop-shadow-md, +.grayscale, +.hue-rotate-60, +.invert, +.saturate-200, +.sepia { --tw-blur: var(--tw-empty, /*!*/ /*!*/); --tw-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -31,6 +53,10 @@ --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); --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 { --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -232,6 +258,17 @@ .origin-top-right { transform-origin: top right; } +.transform { + transform: var(--tw-transform); +} +.transform-gpu { + transform: translate3d(var(--tw-translate-x), var(--tw-translate-y), 0) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); +} +.transform-none { + transform: none; +} .translate-x-5 { --tw-translate-x: 1.25rem; transform: var(--tw-transform); @@ -265,17 +302,6 @@ --tw-scale-y: 0.95; transform: var(--tw-transform); } -.transform { - transform: var(--tw-transform); -} -.transform-gpu { - --tw-transform: translate3d(var(--tw-translate-x), var(--tw-translate-y), 0) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} -.transform-none { - transform: none; -} .animate-none { animation: none; } @@ -699,6 +725,12 @@ .ring-offset-blue-300 { --tw-ring-offset-color: #93c5fd; } +.filter { + filter: var(--tw-filter); +} +.filter-none { + filter: none; +} .blur-md { --tw-blur: blur(12px); filter: var(--tw-filter); @@ -736,12 +768,6 @@ --tw-sepia: sepia(100%); filter: var(--tw-filter); } -.filter { - filter: var(--tw-filter); -} -.filter-none { - filter: none; -} .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); backdrop-filter: var(--tw-backdrop-filter); diff --git a/tests/jit/filter-utilities.test.js b/tests/jit/filter-utilities.test.js new file mode 100644 index 000000000..5f8484a0d --- /dev/null +++ b/tests/jit/filter-utilities.test.js @@ -0,0 +1,233 @@ +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 filter class', 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(` + .brightness-150, .contrast-50 { + --tw-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); + --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); + } + .brightness-150 { + --tw-brightness: brightness(1.5); + filter: var(--tw-filter); + } + .contrast-50 { + --tw-contrast: contrast(0.5); + filter: var(--tw-filter); + } + `) + }) +}) + +test('with filter class', 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(` + .filter, .brightness-150, .contrast-50 { + --tw-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); + --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); + } + .filter { + filter: var(--tw-filter) + } + .brightness-150 { + --tw-brightness: brightness(1.5); + filter: var(--tw-filter); + } + .contrast-50 { + --tw-contrast: contrast(0.5); + filter: var(--tw-filter); + } + `) + }) +}) + +test('with filter-none class', 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(` + .brightness-150, .contrast-50 { + --tw-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); + --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); + } + .filter-none { + filter: none + } + .brightness-150 { + --tw-brightness: brightness(1.5); + filter: var(--tw-filter); + } + .contrast-50 { + --tw-contrast: contrast(0.5); + filter: var(--tw-filter); + } + `) + }) +}) + +test('with variants', 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(` + .brightness-100, + .hover\\:brightness-150, + .contrast-50, + .lg\\:contrast-100 { + --tw-blur: var(--tw-empty, /*!*/ /*!*/); + --tw-brightness: var(--tw-empty, /*!*/ /*!*/); + --tw-contrast: var(--tw-empty, /*!*/ /*!*/); + --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); + --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); + --tw-invert: var(--tw-empty, /*!*/ /*!*/); + --tw-saturate: var(--tw-empty, /*!*/ /*!*/); + --tw-sepia: var(--tw-empty, /*!*/ /*!*/); + --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); + --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); + } + .brightness-100 { + --tw-brightness: brightness(1); + filter: var(--tw-filter); + } + .contrast-50 { + --tw-contrast: contrast(0.5); + filter: var(--tw-filter); + } + .hover\\:brightness-150:hover { + --tw-brightness: brightness(1.5); + filter: var(--tw-filter); + } + @media (min-width: 1024px) { + .lg\\:contrast-100 { + --tw-contrast: contrast(1); + filter: var(--tw-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/important-boolean.test.css b/tests/jit/important-boolean.test.css index a61b268ac..03092814d 100644 --- a/tests/jit/important-boolean.test.css +++ b/tests/jit/important-boolean.test.css @@ -20,6 +20,9 @@ --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; +} +.brightness-150, +.contrast-50 { --tw-blur: var(--tw-empty, /*!*/ /*!*/); --tw-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -31,6 +34,11 @@ --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); --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); + filter: var(--tw-filter); +} +*, +::before, +::after { --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -99,6 +107,12 @@ .font-bold { font-weight: 700 !important; } +.brightness-150 { + --tw-brightness: brightness(1.5) !important; +} +.contrast-50 { + --tw-contrast: contrast(0.5) !important; +} .custom-util { button: no; } diff --git a/tests/jit/important-boolean.test.html b/tests/jit/important-boolean.test.html index 56680435e..d72c3ac1e 100644 --- a/tests/jit/important-boolean.test.html +++ b/tests/jit/important-boolean.test.html @@ -5,6 +5,7 @@
+
diff --git a/tests/jit/kitchen-sink.test.css b/tests/jit/kitchen-sink.test.css index 38f26fcdd..0a3246f18 100644 --- a/tests/jit/kitchen-sink.test.css +++ b/tests/jit/kitchen-sink.test.css @@ -148,17 +148,6 @@ --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; - --tw-blur: var(--tw-empty, /*!*/ /*!*/); - --tw-brightness: var(--tw-empty, /*!*/ /*!*/); - --tw-contrast: var(--tw-empty, /*!*/ /*!*/); - --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); - --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); - --tw-invert: var(--tw-empty, /*!*/ /*!*/); - --tw-saturate: var(--tw-empty, /*!*/ /*!*/); - --tw-sepia: var(--tw-empty, /*!*/ /*!*/); - --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); - --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); --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); diff --git a/tests/jit/prefix.test.css b/tests/jit/prefix.test.css index 718a928fa..f20e0618a 100644 --- a/tests/jit/prefix.test.css +++ b/tests/jit/prefix.test.css @@ -20,6 +20,9 @@ --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; +} +.tw-brightness-150, +.tw-contrast-50 { --tw-blur: var(--tw-empty, /*!*/ /*!*/); --tw-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -31,6 +34,11 @@ --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); --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); + filter: var(--tw-filter); +} +*, +::before, +::after { --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -102,6 +110,12 @@ .tw-font-bold { font-weight: 700; } +.tw-brightness-150 { + --tw-brightness: brightness(1.5); +} +.tw-contrast-50 { + --tw-contrast: contrast(0.5); +} .tw-custom-util-prefix { button: no; } diff --git a/tests/jit/prefix.test.html b/tests/jit/prefix.test.html index 69be55f07..3957db7da 100644 --- a/tests/jit/prefix.test.html +++ b/tests/jit/prefix.test.html @@ -10,6 +10,7 @@
+
diff --git a/tests/jit/raw-content.test.css b/tests/jit/raw-content.test.css index 771694661..98048c241 100644 --- a/tests/jit/raw-content.test.css +++ b/tests/jit/raw-content.test.css @@ -630,49 +630,40 @@ .ring-offset-blue-300 { --tw-ring-offset-color: #93c5fd; } -.blur-md { - --tw-blur: blur(12px); - filter: var(--tw-filter); -} -.brightness-150 { - --tw-brightness: brightness(1.5); - filter: var(--tw-filter); -} -.contrast-50 { - --tw-contrast: contrast(0.5); - filter: var(--tw-filter); -} -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) - drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06)); - filter: var(--tw-filter); -} -.grayscale { - --tw-grayscale: grayscale(100%); - filter: var(--tw-filter); -} -.hue-rotate-60 { - --tw-hue-rotate: hue-rotate(60deg); - filter: var(--tw-filter); -} -.invert { - --tw-invert: invert(100%); - filter: var(--tw-filter); -} -.saturate-200 { - --tw-saturate: saturate(2); - filter: var(--tw-filter); -} -.sepia { - --tw-sepia: sepia(100%); - filter: var(--tw-filter); -} .filter { filter: var(--tw-filter); } .filter-none { filter: none; } +.blur-md { + --tw-blur: blur(12px); +} +.brightness-150 { + --tw-brightness: brightness(1.5); +} +.contrast-50 { + --tw-contrast: contrast(0.5); +} +.drop-shadow-md { + --tw-drop-shadow: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) + drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06)); +} +.grayscale { + --tw-grayscale: grayscale(100%); +} +.hue-rotate-60 { + --tw-hue-rotate: hue-rotate(60deg); +} +.invert { + --tw-invert: invert(100%); +} +.saturate-200 { + --tw-saturate: saturate(2); +} +.sepia { + --tw-sepia: sepia(100%); +} .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); backdrop-filter: var(--tw-backdrop-filter); diff --git a/tests/jit/relative-purge-paths.test.css b/tests/jit/relative-purge-paths.test.css index d73226c60..a4e382206 100644 --- a/tests/jit/relative-purge-paths.test.css +++ b/tests/jit/relative-purge-paths.test.css @@ -20,6 +20,17 @@ --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; +} +.filter, +.blur-md, +.brightness-150, +.contrast-50, +.drop-shadow-md, +.grayscale, +.hue-rotate-60, +.invert, +.saturate-200, +.sepia { --tw-blur: var(--tw-empty, /*!*/ /*!*/); --tw-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -31,6 +42,11 @@ --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); --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); + filter: var(--tw-filter); +} +*, +::before, +::after { --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/); @@ -677,49 +693,40 @@ .ring-offset-blue-300 { --tw-ring-offset-color: #93c5fd; } -.blur-md { - --tw-blur: blur(12px); - filter: var(--tw-filter); -} -.brightness-150 { - --tw-brightness: brightness(1.5); - filter: var(--tw-filter); -} -.contrast-50 { - --tw-contrast: contrast(0.5); - filter: var(--tw-filter); -} -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) - drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06)); - filter: var(--tw-filter); -} -.grayscale { - --tw-grayscale: grayscale(100%); - filter: var(--tw-filter); -} -.hue-rotate-60 { - --tw-hue-rotate: hue-rotate(60deg); - filter: var(--tw-filter); -} -.invert { - --tw-invert: invert(100%); - filter: var(--tw-filter); -} -.saturate-200 { - --tw-saturate: saturate(2); - filter: var(--tw-filter); -} -.sepia { - --tw-sepia: sepia(100%); - filter: var(--tw-filter); -} .filter { filter: var(--tw-filter); } .filter-none { filter: none; } +.blur-md { + --tw-blur: blur(12px); +} +.brightness-150 { + --tw-brightness: brightness(1.5); +} +.contrast-50 { + --tw-contrast: contrast(0.5); +} +.drop-shadow-md { + --tw-drop-shadow: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) + drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06)); +} +.grayscale { + --tw-grayscale: grayscale(100%); +} +.hue-rotate-60 { + --tw-hue-rotate: hue-rotate(60deg); +} +.invert { + --tw-invert: invert(100%); +} +.saturate-200 { + --tw-saturate: saturate(2); +} +.sepia { + --tw-sepia: sepia(100%); +} .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); backdrop-filter: var(--tw-backdrop-filter); diff --git a/tests/jit/transform-utilities.test.js b/tests/jit/transform-utilities.test.js new file mode 100644 index 000000000..66463847b --- /dev/null +++ b/tests/jit/transform-utilities.test.js @@ -0,0 +1,231 @@ +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 transform class', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['transform', 'scale', 'translate'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .scale-50, .translate-x-4 { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + .translate-x-4 { + --tw-translate-x: 1rem; + transform: var(--tw-transform); + } + .scale-50 { + --tw-scale-x: 0.5; + --tw-scale-y: 0.5; + transform: var(--tw-transform); + } + `) + }) +}) + +test('with transform class', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['transform', 'scale', 'translate'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .transform, .scale-50, .translate-x-4 { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + .transform { + transform: var(--tw-transform); + } + .translate-x-4 { + --tw-translate-x: 1rem; + transform: var(--tw-transform); + } + .scale-50 { + --tw-scale-x: 0.5; + --tw-scale-y: 0.5; + transform: var(--tw-transform); + } + `) + }) +}) + +test('with transform-none class', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['transform', 'scale', 'translate'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .scale-50, .translate-x-4 { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + .transform-none { + transform: none; + } + .translate-x-4 { + --tw-translate-x: 1rem; + transform: var(--tw-transform); + } + .scale-50 { + --tw-scale-x: 0.5; + --tw-scale-y: 0.5; + transform: var(--tw-transform); + } + `) + }) +}) + +test('with variants', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['transform', 'scale', 'translate'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .scale-50, .hover\\:scale-100, .translate-x-4, .lg\\:translate-x-6 { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + .translate-x-4 { + --tw-translate-x: 1rem; + transform: var(--tw-transform); + } + .scale-50 { + --tw-scale-x: 0.5; + --tw-scale-y: 0.5; + transform: var(--tw-transform); + } + .hover\\:scale-100:hover { + --tw-scale-x: 1; + --tw-scale-y: 1; + transform: var(--tw-transform); + } + @media (min-width: 1024px) { + .lg\\:translate-x-6 { + --tw-translate-x: 1.5rem; + transform: var(--tw-transform); + } + } + `) + }) +}) + +test('without any transform classes', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['transform', 'scale', 'translate'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) diff --git a/tests/jit/variants.test.css b/tests/jit/variants.test.css index a80370eae..770773797 100644 --- a/tests/jit/variants.test.css +++ b/tests/jit/variants.test.css @@ -20,17 +20,6 @@ --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; - --tw-blur: var(--tw-empty, /*!*/ /*!*/); - --tw-brightness: var(--tw-empty, /*!*/ /*!*/); - --tw-contrast: var(--tw-empty, /*!*/ /*!*/); - --tw-grayscale: var(--tw-empty, /*!*/ /*!*/); - --tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/); - --tw-invert: var(--tw-empty, /*!*/ /*!*/); - --tw-saturate: var(--tw-empty, /*!*/ /*!*/); - --tw-sepia: var(--tw-empty, /*!*/ /*!*/); - --tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/); - --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); --tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/); --tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/);