diff --git a/src/lib/expandApplyAtRules.js b/src/lib/expandApplyAtRules.js index 056057c17f79..e9de77130b3d 100644 --- a/src/lib/expandApplyAtRules.js +++ b/src/lib/expandApplyAtRules.js @@ -3,6 +3,11 @@ import { resolveMatches } from './generateRules' import bigSign from '../util/bigSign' import escapeClassName from '../util/escapeClassName' +function prefix(context, selector) { + let prefix = context.tailwindConfig.prefix + return typeof prefix === 'function' ? prefix(selector) : prefix + selector +} + function buildApplyCache(applyCandidates, context) { for (let candidate of applyCandidates) { if (context.notClassCache.has(candidate) || context.applyClassCache.has(candidate)) { @@ -170,6 +175,11 @@ function processApply(root, context) { for (let applyCandidate of applyCandidates) { if (!applyClassCache.has(applyCandidate)) { + if (applyCandidate === prefix(context, 'group')) { + // TODO: Link to specific documentation page with error code. + throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`) + } + throw apply.error( `The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.` ) diff --git a/src/util/resolveConfig.js b/src/util/resolveConfig.js index 17265125d5e4..ffb94d1a013c 100644 --- a/src/util/resolveConfig.js +++ b/src/util/resolveConfig.js @@ -261,7 +261,6 @@ export default function resolveConfig(configs) { let allConfigs = [ ...extractPluginConfigs(configs), { - content: [], prefix: '', important: false, separator: ':', @@ -302,10 +301,10 @@ function normalizeConfig(config) { content: (() => { let { content, purge } = config - if (Array.isArray(content)) return content - if (Array.isArray(content?.content)) return content.content if (Array.isArray(purge)) return purge if (Array.isArray(purge?.content)) return purge.content + if (Array.isArray(content)) return content + if (Array.isArray(content?.content)) return content.content return [] })(), diff --git a/tests/jit/apply.test.js b/tests/jit/apply.test.js index 08992239f191..3dba79d3f437 100644 --- a/tests/jit/apply.test.js +++ b/tests/jit/apply.test.js @@ -11,6 +11,10 @@ function run(input, config = {}) { }) } +function css(templates) { + return templates.join('') +} + test('@apply', () => { let config = { darkMode: 'class', @@ -207,19 +211,68 @@ test('@apply error with nested @anyatrulehere', async () => { } let css = ` - @tailwind components; - @tailwind utilities; + @tailwind components; + @tailwind utilities; - @layer components { - .foo { - @genie { - @apply text-black; + @layer components { + .foo { + @genie { + @apply text-black; + } } } - } -` + ` await expect(run(css, config)).rejects.toThrowError( '@apply is not supported within nested at-rules like @genie' ) }) + +test('@apply error when using .group utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: '
' }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply group; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'group' utility` + ) +}) + +test('@apply error when using a prefixed .group utility', async () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [{ raw: '
' }], + corePlugins: { preflight: false }, + plugins: [], + } + + let css = ` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply tw-group; + } + } + ` + + await expect(run(css, config)).rejects.toThrowError( + `@apply should not be used with the 'tw-group' utility` + ) +})