diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 0912ffab7..c237f6cd1 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -697,7 +697,35 @@ function collectLayerPlugins(root) { } layerRule.remove() } else if (layerRule.params === 'utilities') { + let pattern = + /\.(?[\w_-]+)-\((?@[\w_-]+)(?:\: theme\((?\w+)\))?\)/ for (let node of layerRule.nodes) { + let matches + if (node.selector.includes('@') && (matches = node.selector.match(pattern))) { + let key = matches.groups.namespace + let themeKey = matches.groups.themeKey + + layerPlugins.push(function ({ matchUtilities, theme }) { + matchUtilities( + { + [key]: (value) => { + let nodesObj = {} + node.walkDecls((n) => { + nodesObj[n.prop] = n.value.replace(matches.groups.valueVariable, value) + }) + return nodesObj + }, + }, + { + values: themeKey ? theme(themeKey) : {}, + respectPrefix: false, + preserveSource: true, + } + ) + }) + continue + } + layerPlugins.push(function ({ addUtilities }) { addUtilities(node, { respectPrefix: false, preserveSource: true }) }) diff --git a/tests/custom-dynamic-utilities.test.js b/tests/custom-dynamic-utilities.test.js new file mode 100644 index 000000000..224a907d8 --- /dev/null +++ b/tests/custom-dynamic-utilities.test.js @@ -0,0 +1,47 @@ +import { run, html, css } from './util/run' + +test('defining parametric utilities in CSS', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + tabSize: { + 0: '0', + 2: '2', + 4: '4', + }, + }, + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .tab-(@size: theme(tabSize)) { + tab-size: @size; + } + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tab-2 { + tab-size: 2; + } + @media (min-width: 768px) { + .md\:tab-4 { + tab-size: 4; + } + } + @media (min-width: 1024px) { + .lg\:tab-\[6\] { + tab-size: 6; + } + } + `) +})