diff --git a/src/jit/lib/optimizeUniversalRules.js b/src/jit/lib/optimizeUniversalRules.js index 22987f783..fceeb524f 100644 --- a/src/jit/lib/optimizeUniversalRules.js +++ b/src/jit/lib/optimizeUniversalRules.js @@ -1,3 +1,4 @@ +import postcss from 'postcss' import selectorParser from 'postcss-selector-parser' let elementSelectorParser = selectorParser((selectors) => { @@ -26,27 +27,25 @@ export default function collapseAdjacentRules() { let variableNodeMap = new Map() let universals = new Set() - root.walkDecls((decl) => { - if (!decl.prop.startsWith('--')) { + root.walkAtRules('defaults', (rule) => { + if (rule.nodes.length > 0) { + universals.add(rule) return } - if (decl.parent.selector === '*::tailwind') { - universals.add(decl.parent) - return - } - - let variable = decl.prop - + let variable = rule.params if (!variableNodeMap.has(variable)) { variableNodeMap.set(variable, new Set()) } - variableNodeMap.get(variable).add(decl.parent) + variableNodeMap.get(variable).add(rule.parent) + + rule.remove() }) for (let universal of universals) { let selectors = new Set() + let rule = postcss.rule() universal.walkDecls((decl) => { let variable = decl.prop @@ -58,7 +57,10 @@ export default function collapseAdjacentRules() { } }) - universal.selectors = [...selectors] + rule.selectors = [...selectors] + rule.append(universal.clone().nodes) + universal.before(rule) + universal.remove() } } } diff --git a/src/jit/processTailwindFeatures.js b/src/jit/processTailwindFeatures.js index 6344b5219..31a9b212f 100644 --- a/src/jit/processTailwindFeatures.js +++ b/src/jit/processTailwindFeatures.js @@ -46,7 +46,9 @@ export default function processTailwindFeatures(setupContext) { expandApplyAtRules(context)(root, result) evaluateTailwindFunctions(context)(root, result) substituteScreenAtRules(context)(root, result) + console.time('Optimizer') optimizeUniversalRules(context)(root, result) + console.timeEnd('Optimizer') collapseAdjacentRules(context)(root, result) } } diff --git a/src/plugins/borderColor.js b/src/plugins/borderColor.js index 63d4e1f12..87e550fbc 100644 --- a/src/plugins/borderColor.js +++ b/src/plugins/borderColor.js @@ -6,13 +6,13 @@ export default function () { if (config('mode') === 'jit') { if (!corePlugins('borderOpacity')) { addBase({ - '*::tailwind': { + '@defaults --tw-border-opacity': { 'border-color': theme('borderColor.DEFAULT', 'currentColor'), }, }) } else { addBase({ - '*::tailwind': withAlphaVariable({ + '@defaults --tw-border-opacity': withAlphaVariable({ color: theme('borderColor.DEFAULT', 'currentColor'), property: 'border-color', variable: '--tw-border-opacity', diff --git a/src/plugins/borderWidth.js b/src/plugins/borderWidth.js index 39871f287..e87e3e145 100644 --- a/src/plugins/borderWidth.js +++ b/src/plugins/borderWidth.js @@ -5,7 +5,7 @@ export default function () { return createUtilityPlugin( 'borderWidth', [ - ['border', ['border-width']], + ['border', ['border-width', ['@defaults --tw-border-opacity', {}]]], [ ['border-t', ['border-top-width']], ['border-r', ['border-right-width']], diff --git a/src/plugins/boxShadow.js b/src/plugins/boxShadow.js index 846c64199..31c391c4f 100644 --- a/src/plugins/boxShadow.js +++ b/src/plugins/boxShadow.js @@ -11,7 +11,9 @@ export default function () { return function ({ config, matchUtilities, addBase, addUtilities, theme, variants }) { if (config('mode') === 'jit') { addBase({ - '*::tailwind': { + '@defaults --tw-shadow': { + '--tw-ring-offset-shadow': '0 0 #0000', + '--tw-ring-shadow': '0 0 #0000', '--tw-shadow': '0 0 #0000', }, }) @@ -32,6 +34,7 @@ export default function () { value = transformValue(value) return { + ...(config('mode') === 'jit' ? { '@defaults --tw-shadow': {} } : {}), '--tw-shadow': value === 'none' ? '0 0 #0000' : value, 'box-shadow': defaultBoxShadow, } diff --git a/src/plugins/filter.js b/src/plugins/filter.js index 904cf556d..7d3cc5266 100644 --- a/src/plugins/filter.js +++ b/src/plugins/filter.js @@ -2,7 +2,7 @@ export default function () { return function ({ config, addBase, addUtilities, variants }) { if (config('mode') === 'jit') { addBase({ - '*::tailwind': { + '@defaults --tw-filter': { '--tw-blur': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-brightness': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-contrast': 'var(--tw-empty,/*!*/ /*!*/)', @@ -27,7 +27,7 @@ export default function () { }) addUtilities( { - '.filter': { filter: 'var(--tw-filter)' }, + '.filter': { '@defaults --tw-filter': {}, filter: 'var(--tw-filter)' }, '.filter-none': { filter: 'none' }, }, variants('filter') diff --git a/src/plugins/ringWidth.js b/src/plugins/ringWidth.js index c3de5d106..41f861d0f 100644 --- a/src/plugins/ringWidth.js +++ b/src/plugins/ringWidth.js @@ -11,13 +11,14 @@ export default function () { if (config('mode') === 'jit') { addBase({ - '*::tailwind': { + '@defaults --tw-ring-shadow': { '--tw-ring-inset': 'var(--tw-empty,/*!*/ /*!*/)', '--tw-ring-offset-width': theme('ringOffsetWidth.DEFAULT', '0px'), '--tw-ring-offset-color': theme('ringOffsetColor.DEFAULT', '#fff'), '--tw-ring-color': ringColorDefault, '--tw-ring-offset-shadow': '0 0 #0000', '--tw-ring-shadow': '0 0 #0000', + '--tw-shadow': '0 0 #0000', }, }) } else { @@ -40,6 +41,7 @@ export default function () { { ring: (value) => { return { + ...(config('mode') === 'jit' ? { '@defaults --tw-ring-shadow': {} } : {}), '--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(${value} + var(--tw-ring-offset-width)) var(--tw-ring-color)`, 'box-shadow': [ @@ -57,6 +59,14 @@ export default function () { } ) - addUtilities({ '.ring-inset': { '--tw-ring-inset': 'inset' } }, variants('ringWidth')) + addUtilities( + { + '.ring-inset': { + ...(config('mode') === 'jit' ? { '@defaults --tw-ring-shadow': {} } : {}), + '--tw-ring-inset': 'inset', + }, + }, + variants('ringWidth') + ) } } diff --git a/src/plugins/rotate.js b/src/plugins/rotate.js index 0d7151254..832211a69 100644 --- a/src/plugins/rotate.js +++ b/src/plugins/rotate.js @@ -4,7 +4,10 @@ export default function () { return function ({ config, ...rest }) { if (config('mode') === 'jit') { return createUtilityPlugin('rotate', [ - ['rotate', ['--tw-rotate', ['transform', 'var(--tw-transform)']]], + [ + 'rotate', + [['@defaults --tw-transform', {}], '--tw-rotate', ['transform', 'var(--tw-transform)']], + ], ])({ config, ...rest }) } else { return createUtilityPlugin('rotate', [['rotate', ['--tw-rotate']]])({ config, ...rest }) diff --git a/src/plugins/scale.js b/src/plugins/scale.js index 6637039d7..95f05f758 100644 --- a/src/plugins/scale.js +++ b/src/plugins/scale.js @@ -4,10 +4,32 @@ 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)']]], [ - ['scale-x', ['--tw-scale-x', ['transform', 'var(--tw-transform)']]], - ['scale-y', ['--tw-scale-y', ['transform', 'var(--tw-transform)']]], + 'scale', + [ + ['@defaults --tw-transform', {}], + '--tw-scale-x', + '--tw-scale-y', + ['transform', 'var(--tw-transform)'], + ], + ], + [ + [ + 'scale-x', + [ + ['@defaults --tw-transform', {}], + '--tw-scale-x', + ['transform', 'var(--tw-transform)'], + ], + ], + [ + 'scale-y', + [ + ['@defaults --tw-transform', {}], + '--tw-scale-y', + ['transform', 'var(--tw-transform)'], + ], + ], ], ])({ config, ...rest }) } else { diff --git a/src/plugins/skew.js b/src/plugins/skew.js index 5ad20446f..9f7cf2c55 100644 --- a/src/plugins/skew.js +++ b/src/plugins/skew.js @@ -5,8 +5,14 @@ export default function () { if (config('mode') === 'jit') { return createUtilityPlugin('skew', [ [ - ['skew-x', ['--tw-skew-x', ['transform', 'var(--tw-transform)']]], - ['skew-y', ['--tw-skew-y', ['transform', 'var(--tw-transform)']]], + [ + 'skew-x', + [['@defaults --tw-transform', {}], '--tw-skew-x', ['transform', 'var(--tw-transform)']], + ], + [ + 'skew-y', + [['@defaults --tw-transform', {}], '--tw-skew-y', ['transform', 'var(--tw-transform)']], + ], ], ])({ config, ...rest }) } else { diff --git a/src/plugins/transform.js b/src/plugins/transform.js index a0ef643f8..64601b687 100644 --- a/src/plugins/transform.js +++ b/src/plugins/transform.js @@ -2,7 +2,7 @@ export default function () { return function ({ config, addBase, addUtilities, variants }) { if (config('mode') === 'jit') { addBase({ - '*::tailwind': { + '@defaults --tw-transform': { '--tw-translate-x': '0', '--tw-translate-y': '0', '--tw-rotate': '0', @@ -24,6 +24,7 @@ export default function () { addUtilities( { '.transform': { + '@defaults --tw-transform': {}, transform: 'var(--tw-transform)', }, '.transform-cpu': { diff --git a/tests/jit/optimize-universal-selectors.test.js b/tests/jit/optimize-universal-selectors.test.js index 844a979b5..ea9c89158 100644 --- a/tests/jit/optimize-universal-selectors.test.js +++ b/tests/jit/optimize-universal-selectors.test.js @@ -83,9 +83,9 @@ test('with pseudo-class variants', async () => { return run(css, config).then((result) => { expect(result.css).toMatchFormattedCss(` + .hover\\:scale-x-110, .focus\\:rotate-3, - .hover\\:focus\\:skew-y-6, - .hover\\:scale-x-110 { + .hover\\:focus\\:skew-y-6 { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -135,8 +135,8 @@ test('with pseudo-element variants', async () => { return run(css, config).then((result) => { expect(result.css).toMatchFormattedCss(` - .after\\:rotate-3::after, - .before\\:scale-x-110::before { + .before\\:scale-x-110::before, + .after\\:rotate-3::after { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -184,8 +184,8 @@ test('with multi-class variants', async () => { return run(css, config).then((result) => { expect(result.css).toMatchFormattedCss(` - .peer-focus\\:rotate-3, - .group-hover\\:scale-x-110 { + .group-hover\\:scale-x-110, + .peer-focus\\:rotate-3 { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -231,8 +231,8 @@ test('with multi-class pseudo-element variants', async () => { return run(css, config).then((result) => { expect(result.css).toMatchFormattedCss(` - .peer-focus\\:after\\:rotate-3::after, - .group-hover\\:before\\:scale-x-110::before { + .group-hover\\:before\\:scale-x-110::before, + .peer-focus\\:after\\:rotate-3::after { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -280,8 +280,8 @@ test('with multi-class pseudo-element and pseudo-class variants', async () => { return run(css, config).then((result) => { expect(result.css).toMatchFormattedCss(` - .peer-focus\\:focus\\:after\\:rotate-3::after, - .group-hover\\:hover\\:before\\:scale-x-110::before { + .group-hover\\:hover\\:before\\:scale-x-110::before, + .peer-focus\\:focus\\:after\\:rotate-3::after { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -373,16 +373,16 @@ test('with apply', async () => { return run(css, config).then((result) => { expect(result.css).toMatchFormattedCss(` .foo, + .bar::before, .baz::before, + span, .media-queries, .a, .b, + .c, .a::before, .b::after, - .recursive, - span, - .c, - .bar::before { + .recursive { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; @@ -486,3 +486,66 @@ test('with borders', async () => { `) }) }) + +test('with shadows', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + theme: {}, + plugins: [], + corePlugins: ['boxShadow', 'ringColor', 'ringWidth', 'transform'], + } + + let css = ` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .ring-1 { + --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; + --tw-shadow: 0 0 #0000; + } + .shadow, + .md\\:shadow-xl { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + } + /* --- */ + .shadow { + --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .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); + } + .ring-black\\/25 { + --tw-ring-color: rgba(0, 0, 0, 0.25); + } + @media (min-width: 768px) { + .md\\:shadow-xl { + --tw-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + } + `) + }) +})