diff --git a/src/plugins/boxShadow.js b/src/plugins/boxShadow.js index c5bf5e2a5..e98ce941b 100644 --- a/src/plugins/boxShadow.js +++ b/src/plugins/boxShadow.js @@ -1,11 +1,28 @@ import transformThemeValue from '../util/transformThemeValue' +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-ring-offset-shadow': '0 0 #0000', + '--tw-ring-shadow': '0 0 #0000', + '--tw-shadow': '0 0 #0000', + }, + }) + ) + } else { + baseRoot.nodes[0].selectors = [...baseRoot.nodes[0].selectors, selector] + } +} let transformValue = transformThemeValue('boxShadow') -let shadowReset = { - '*, ::before, ::after': { - '--tw-shadow': '0 0 #0000', - }, -} let defaultBoxShadow = [ `var(--tw-ring-offset-shadow, 0 0 #0000)`, `var(--tw-ring-shadow, 0 0 #0000)`, @@ -13,16 +30,29 @@ let defaultBoxShadow = [ ].join(', ') export default function () { - return function ({ config, matchUtilities, addBase, addUtilities, theme, variants }) { + return function ({ config, matchUtilities, addBase, addUtilities, theme, variants, memory }) { if (config('mode') === 'jit') { - addBase(shadowReset) + let baseRoot = postcss.root() + memory.set(baseRulesKey, baseRoot) + addBase(baseRoot) } else { - addUtilities(shadowReset, { respectImportant: false }) + addUtilities( + { + '*, ::before, ::after': { + '--tw-shadow': '0 0 #0000', + }, + }, + { respectImportant: false } + ) } matchUtilities( { - shadow: (value) => { + shadow: (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, selector) + } + value = transformValue(value) return { diff --git a/src/plugins/ringWidth.js b/src/plugins/ringWidth.js index f4f5c978d..bac4d2f91 100644 --- a/src/plugins/ringWidth.js +++ b/src/plugins/ringWidth.js @@ -1,7 +1,13 @@ import { withAlphaValue } from '../util/withAlphaVariable' +import postcss from 'postcss' +import parseObjectStyles from '../util/parseObjectStyles' -export default function () { - return function ({ config, matchUtilities, addBase, addUtilities, theme, variants }) { +let baseRulesKey = Symbol() + +export function addBaseSelector(memory, theme, selector) { + let baseRoot = memory.get(baseRulesKey) + + if (baseRoot.nodes.length === 0) { let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5') let ringColorDefault = withAlphaValue( theme('ringColor.DEFAULT'), @@ -9,26 +15,58 @@ export default function () { `rgba(147, 197, 253, ${ringOpacityDefault})` ) - let ringReset = { - '*, ::before, ::after': { - '--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', - }, - } + baseRoot.append( + parseObjectStyles({ + [selector]: { + '--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 { + baseRoot.nodes[0].selectors = [...baseRoot.nodes[0].selectors, selector] + } +} - if (config('mode') === 'jit') { - addBase(ringReset) +export default function () { + return function ({ config, matchUtilities, addBase, addUtilities, theme, variants, memory }) { + if (config('mode') == 'jit') { + let baseRoot = postcss.root() + memory.set(baseRulesKey, baseRoot) + addBase(baseRoot) } else { + let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5') + let ringColorDefault = withAlphaValue( + theme('ringColor.DEFAULT'), + ringOpacityDefault, + `rgba(147, 197, 253, ${ringOpacityDefault})` + ) + + let ringReset = { + '*, ::before, ::after': { + '--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', + }, + } addUtilities(ringReset, { respectImportant: false }) } matchUtilities( { - ring: (value) => { + ring: (value, { selector }) => { + if (config('mode') === 'jit') { + addBaseSelector(memory, theme, selector) + } + return { '--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)`, diff --git a/tests/jit/box-shadow-utilities.test.js b/tests/jit/box-shadow-utilities.test.js new file mode 100644 index 000000000..0bbcac405 --- /dev/null +++ b/tests/jit/box-shadow-utilities.test.js @@ -0,0 +1,57 @@ +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('basic ring width', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['boxShadow'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .shadow, + .shadow-md, + .shadow-lg { + --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); + } + .shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px 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); + } + .shadow-lg { + --tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) diff --git a/tests/jit/ring-utilities.test.js b/tests/jit/ring-utilities.test.js new file mode 100644 index 000000000..d803a369e --- /dev/null +++ b/tests/jit/ring-utilities.test.js @@ -0,0 +1,71 @@ +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('basic ring width', async () => { + let config = { + mode: 'jit', + purge: [ + { + raw: '
', + }, + ], + corePlugins: ['ringColor', 'ringOffsetColor', 'ringOffsetWidth', 'ringOpacity', 'ringWidth'], + theme: {}, + plugins: [], + } + + let css = ` + @tailwind base; + @tailwind utilities + ` + + return run(css, config).then((result) => { + expect(result.css).toMatchFormattedCss(` + .ring, + .ring-2, + .ring-4 { + --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; + } + .ring { + --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(3px + 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-2 { + --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(2px + 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-4 { + --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(4px + 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-blue-500 { + --tw-ring-opacity: 1; + --tw-ring-color: rgba(59, 130, 246, var(--tw-ring-opacity)); + } + .ring-offset-2 { + --tw-ring-offset-width: 2px; + } + .ring-offset-blue-100 { + --tw-ring-offset-color: #dbeafe; + } + `) + }) +})