Skip to content

Commit bd21bef

Browse files
authored
Polish match APIs (tailwindlabs#5664)
* fix incorrect logic for validating content paths * remove `includeRules` helper * generate keyframes as part of the animate plugin * add matchUtilities * splitup `variantPlugins` and `corePlugins`
1 parent d94541c commit bd21bef

File tree

10 files changed

+331
-99
lines changed

10 files changed

+331
-99
lines changed

scripts/create-plugin-list.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import corePlugins from '../src/corePlugins'
1+
import { corePlugins } from '../src/corePlugins'
22
import fs from 'fs'
33
import path from 'path'
44

5-
let corePluginList = Object.keys(corePlugins).filter((plugin) => !plugin.includes('Variants'))
5+
let corePluginList = Object.keys(corePlugins)
66

77
fs.writeFileSync(
88
path.join(process.cwd(), 'src', 'corePluginList.js'),

src/corePlugins.js

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import {
2020
import { version as tailwindVersion } from '../package.json'
2121
import log from './util/log'
2222

23-
export default {
24-
// Variant plugins
23+
export let variantPlugins = {
2524
pseudoElementVariants: ({ config, addVariant }) => {
2625
addVariant(
2726
'first-letter',
@@ -360,8 +359,9 @@ export default {
360359
)
361360
}
362361
},
362+
}
363363

364-
// Actual plugins
364+
export let corePlugins = {
365365
preflight: ({ addBase }) => {
366366
let preflightStyles = postcss.parse(fs.readFileSync(`${__dirname}/css/preflight.css`, 'utf8'))
367367

@@ -753,31 +753,28 @@ export default {
753753
let prefixName = (name) => prefix(`.${name}`).slice(1)
754754
let keyframes = Object.fromEntries(
755755
Object.entries(theme('keyframes') ?? {}).map(([key, value]) => {
756-
return [key, [{ [`@keyframes ${prefixName(key)}`]: value }]]
756+
return [key, { [`@keyframes ${prefixName(key)}`]: value }]
757757
})
758758
)
759759

760760
matchUtilities(
761761
{
762-
animate: (value, { includeRules }) => {
762+
animate: (value) => {
763763
let animations = parseAnimationValue(value)
764764

765-
for (let { name } of animations) {
766-
if (keyframes[name] !== undefined) {
767-
includeRules(keyframes[name], { respectImportant: false })
768-
}
769-
}
770-
771-
return {
772-
animation: animations
773-
.map(({ name, value }) => {
774-
if (name === undefined || keyframes[name] === undefined) {
775-
return value
776-
}
777-
return value.replace(name, prefixName(name))
778-
})
779-
.join(', '),
780-
}
765+
return [
766+
...animations.flatMap((animation) => keyframes[animation.name]),
767+
{
768+
animation: animations
769+
.map(({ name, value }) => {
770+
if (name === undefined || keyframes[name] === undefined) {
771+
return value
772+
}
773+
return value.replace(name, prefixName(name))
774+
})
775+
.join(', '),
776+
},
777+
]
781778
},
782779
},
783780
{ values: theme('animation') }

src/lib/generateRules.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,6 @@ function applyVariant(variant, matches, context) {
108108
let result = []
109109

110110
for (let [meta, rule] of matches) {
111-
if (meta.options.respectVariants === false) {
112-
result.push([meta, rule])
113-
continue
114-
}
115-
116111
let container = postcss.root({ nodes: [rule.clone()] })
117112

118113
for (let [variantSort, variantFunction] of variantFunctionTuples) {

src/lib/setupContextUtils.js

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import escapeClassName from '../util/escapeClassName'
1212
import nameClass, { formatClass } from '../util/nameClass'
1313
import { coerceValue } from '../util/pluginUtils'
1414
import bigSign from '../util/bigSign'
15-
import corePlugins from '../corePlugins'
15+
import { variantPlugins, corePlugins } from '../corePlugins'
1616
import * as sharedState from './sharedState'
1717
import { env } from './sharedState'
1818
import { toPath } from '../util/toPath'
@@ -237,17 +237,11 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
237237
},
238238
addComponents(components, options) {
239239
let defaultOptions = {
240-
variants: [],
241240
respectPrefix: true,
242241
respectImportant: false,
243-
respectVariants: true,
244242
}
245243

246-
options = Object.assign(
247-
{},
248-
defaultOptions,
249-
Array.isArray(options) ? { variants: options } : options
250-
)
244+
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options)
251245

252246
for (let [identifier, rule] of withIdentifiers(components)) {
253247
let prefixedIdentifier = prefixIdentifier(identifier, options)
@@ -266,17 +260,11 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
266260
},
267261
addUtilities(utilities, options) {
268262
let defaultOptions = {
269-
variants: [],
270263
respectPrefix: true,
271264
respectImportant: true,
272-
respectVariants: true,
273265
}
274266

275-
options = Object.assign(
276-
{},
277-
defaultOptions,
278-
Array.isArray(options) ? { variants: options } : options
279-
)
267+
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options)
280268

281269
for (let [identifier, rule] of withIdentifiers(utilities)) {
282270
let prefixedIdentifier = prefixIdentifier(identifier, options)
@@ -295,10 +283,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
295283
},
296284
matchUtilities: function (utilities, options) {
297285
let defaultOptions = {
298-
variants: [],
299286
respectPrefix: true,
300287
respectImportant: true,
301-
respectVariants: true,
302288
}
303289

304290
options = { ...defaultOptions, ...options }
@@ -338,21 +324,14 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
338324
return []
339325
}
340326

341-
let includedRules = []
342327
let ruleSets = []
343-
.concat(
344-
rule(value, {
345-
includeRules(rules) {
346-
includedRules.push(...rules)
347-
},
348-
})
349-
)
328+
.concat(rule(value))
350329
.filter(Boolean)
351330
.map((declaration) => ({
352331
[nameClass(identifier, modifier)]: declaration,
353332
}))
354333

355-
return [...includedRules, ...ruleSets]
334+
return ruleSets
356335
}
357336

358337
let withOffsets = [{ sort: offset, layer: 'utilities', options }, wrapped]
@@ -361,6 +340,68 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
361340
context.candidateRuleMap.set(prefixedIdentifier, [])
362341
}
363342

343+
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
344+
}
345+
},
346+
matchComponents: function (components, options) {
347+
let defaultOptions = {
348+
respectPrefix: true,
349+
respectImportant: false,
350+
}
351+
352+
options = { ...defaultOptions, ...options }
353+
354+
let offset = offsets.components++
355+
356+
for (let identifier in components) {
357+
let prefixedIdentifier = prefixIdentifier(identifier, options)
358+
let rule = components[identifier]
359+
360+
classList.add([prefixedIdentifier, options])
361+
362+
function wrapped(modifier, { isOnlyPlugin }) {
363+
let { type = 'any' } = options
364+
type = [].concat(type)
365+
let [value, coercedType] = coerceValue(type, modifier, options.values, tailwindConfig)
366+
367+
if (value === undefined) {
368+
return []
369+
}
370+
371+
if (!type.includes(coercedType)) {
372+
if (isOnlyPlugin) {
373+
log.warn([
374+
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
375+
`You can safely update it to \`${identifier}-${modifier.replace(
376+
coercedType + ':',
377+
''
378+
)}\`.`,
379+
])
380+
} else {
381+
return []
382+
}
383+
}
384+
385+
if (!isValidArbitraryValue(value)) {
386+
return []
387+
}
388+
389+
let ruleSets = []
390+
.concat(rule(value))
391+
.filter(Boolean)
392+
.map((declaration) => ({
393+
[nameClass(identifier, modifier)]: declaration,
394+
}))
395+
396+
return ruleSets
397+
}
398+
399+
let withOffsets = [{ sort: offset, layer: 'components', options }, wrapped]
400+
401+
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
402+
context.candidateRuleMap.set(prefixedIdentifier, [])
403+
}
404+
364405
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
365406
}
366407
},
@@ -457,7 +498,7 @@ function collectLayerPlugins(root) {
457498
}
458499

459500
function resolvePlugins(context, root) {
460-
let corePluginList = Object.entries(corePlugins)
501+
let corePluginList = Object.entries({ ...variantPlugins, ...corePlugins })
461502
.map(([name, plugin]) => {
462503
if (!context.tailwindConfig.corePlugins.includes(name)) {
463504
return null
@@ -479,12 +520,15 @@ function resolvePlugins(context, root) {
479520

480521
// TODO: This is a workaround for backwards compatibility, since custom variants
481522
// were historically sorted before screen/stackable variants.
482-
let beforeVariants = [corePlugins['pseudoElementVariants'], corePlugins['pseudoClassVariants']]
523+
let beforeVariants = [
524+
variantPlugins['pseudoElementVariants'],
525+
variantPlugins['pseudoClassVariants'],
526+
]
483527
let afterVariants = [
484-
corePlugins['directionVariants'],
485-
corePlugins['reducedMotionVariants'],
486-
corePlugins['darkVariants'],
487-
corePlugins['screenVariants'],
528+
variantPlugins['directionVariants'],
529+
variantPlugins['reducedMotionVariants'],
530+
variantPlugins['darkVariants'],
531+
variantPlugins['screenVariants'],
488532
]
489533

490534
return [...corePluginList, ...beforeVariants, ...userPlugins, ...afterVariants, ...layerPlugins]

src/util/normalizeConfig.js

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ export function normalizeConfig(config) {
1818
*/
1919
let valid = (() => {
2020
// `config.purge` should not exist anymore
21-
if (config.purge) return false
21+
if (config.purge) {
22+
return false
23+
}
2224

2325
// `config.content` should exist
24-
if (!config.content) return false
26+
if (!config.content) {
27+
return false
28+
}
2529

2630
// `config.content` should be an object or an array
2731
if (
28-
!Array.isArray(config.content) ||
32+
!Array.isArray(config.content) &&
2933
!(typeof config.content === 'object' && config.content !== null)
3034
) {
3135
return false
@@ -38,17 +42,15 @@ export function normalizeConfig(config) {
3842
if (typeof path === 'string') return true
3943

4044
// `path` can be an object { raw: string, extension?: string }
41-
if (
42-
// `raw` must be a string
43-
typeof path?.raw === 'string' &&
44-
// `extension` (if provided) should also be a string
45-
path?.extension !== undefined &&
46-
typeof path?.extension === 'string'
47-
) {
48-
return true
45+
// `raw` must be a string
46+
if (typeof path?.raw !== 'string') return false
47+
48+
// `extension` (if provided) should also be a string
49+
if (path?.extension && typeof path?.extension !== 'string') {
50+
return false
4951
}
5052

51-
return false
53+
return true
5254
})
5355
}
5456

@@ -69,17 +71,15 @@ export function normalizeConfig(config) {
6971
if (typeof path === 'string') return true
7072

7173
// `path` can be an object { raw: string, extension?: string }
72-
if (
73-
// `raw` must be a string
74-
typeof path?.raw === 'string' &&
75-
// `extension` (if provided) should also be a string
76-
path?.extension !== undefined &&
77-
typeof path?.extension === 'string'
78-
) {
79-
return true
74+
// `raw` must be a string
75+
if (typeof path?.raw !== 'string') return false
76+
77+
// `extension` (if provided) should also be a string
78+
if (path?.extension && typeof path?.extension !== 'string') {
79+
return false
8080
}
8181

82-
return false
82+
return true
8383
})
8484
) {
8585
return false
@@ -92,7 +92,6 @@ export function normalizeConfig(config) {
9292
return false
9393
}
9494
}
95-
return false
9695
} else if (
9796
!(config.content.extract === undefined || typeof config.content.extract === 'function')
9897
) {
@@ -106,7 +105,6 @@ export function normalizeConfig(config) {
106105
return false
107106
}
108107
}
109-
return false
110108
} else if (
111109
!(
112110
config.content.transform === undefined || typeof config.content.transform === 'function'

0 commit comments

Comments
 (0)