tailwindcss 0.0.0-insiders.fe08e91 → 0.0.0-oxide.6bf5e56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +379 -3
- package/LICENSE +1 -2
- package/README.md +12 -8
- package/colors.d.ts +3 -0
- package/defaultConfig.d.ts +3 -0
- package/defaultTheme.d.ts +4 -0
- package/lib/cli/build/deps.js +54 -0
- package/lib/cli/build/index.js +48 -0
- package/lib/cli/build/plugin.js +367 -0
- package/lib/cli/build/utils.js +78 -0
- package/lib/cli/build/watching.js +178 -0
- package/lib/cli/help/index.js +71 -0
- package/lib/cli/index.js +18 -0
- package/lib/cli/init/index.js +46 -0
- package/lib/cli/shared.js +13 -0
- package/lib/cli-peer-dependencies.js +20 -7
- package/lib/cli.js +107 -611
- package/lib/constants.js +27 -20
- package/lib/corePluginList.js +6 -3
- package/lib/corePlugins.js +2064 -1811
- package/lib/css/preflight.css +5 -5
- package/lib/featureFlags.js +31 -22
- package/lib/index.js +28 -10
- package/lib/lib/cacheInvalidation.js +90 -0
- package/lib/lib/collapseAdjacentRules.js +27 -9
- package/lib/lib/collapseDuplicateDeclarations.js +12 -9
- package/lib/lib/content.js +176 -0
- package/lib/lib/defaultExtractor.js +225 -31
- package/lib/lib/detectNesting.js +13 -10
- package/lib/lib/evaluateTailwindFunctions.js +118 -55
- package/lib/lib/expandApplyAtRules.js +439 -190
- package/lib/lib/expandTailwindAtRules.js +151 -134
- package/lib/lib/findAtConfigPath.js +44 -0
- package/lib/lib/generateRules.js +454 -187
- package/lib/lib/getModuleDependencies.js +11 -8
- package/lib/lib/normalizeTailwindDirectives.js +36 -32
- package/lib/lib/offsets.js +217 -0
- package/lib/lib/partitionApplyAtRules.js +56 -0
- package/lib/lib/regex.js +60 -0
- package/lib/lib/resolveDefaultsAtRules.js +89 -67
- package/lib/lib/setupContextUtils.js +667 -376
- package/lib/lib/setupTrackingContext.js +38 -67
- package/lib/lib/sharedState.js +27 -14
- package/lib/lib/substituteScreenAtRules.js +11 -9
- package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
- package/lib/postcss-plugins/nesting/index.js +19 -0
- package/lib/postcss-plugins/nesting/plugin.js +87 -0
- package/lib/processTailwindFeatures.js +35 -25
- package/lib/public/colors.js +247 -245
- package/lib/public/create-plugin.js +6 -4
- package/lib/public/default-config.js +7 -5
- package/lib/public/default-theme.js +7 -5
- package/lib/public/resolve-config.js +8 -5
- package/lib/util/bigSign.js +4 -1
- package/lib/util/buildMediaQuery.js +11 -6
- package/lib/util/cloneDeep.js +7 -6
- package/lib/util/cloneNodes.js +21 -3
- package/lib/util/color.js +53 -54
- package/lib/util/configurePlugins.js +5 -2
- package/lib/util/createPlugin.js +6 -6
- package/lib/util/createUtilityPlugin.js +12 -14
- package/lib/util/dataTypes.js +119 -110
- package/lib/util/defaults.js +4 -1
- package/lib/util/escapeClassName.js +7 -4
- package/lib/util/escapeCommas.js +5 -2
- package/lib/util/flattenColorPalette.js +9 -12
- package/lib/util/formatVariantSelector.js +184 -85
- package/lib/util/getAllConfigs.js +27 -8
- package/lib/util/hashConfig.js +6 -3
- package/lib/util/isKeyframeRule.js +5 -2
- package/lib/util/isPlainObject.js +5 -2
- package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +23 -15
- package/lib/util/log.js +20 -14
- package/lib/util/nameClass.js +20 -9
- package/lib/util/negateValue.js +23 -8
- package/lib/util/normalizeConfig.js +116 -72
- package/lib/util/normalizeScreens.js +120 -11
- package/lib/util/parseAnimationValue.js +42 -40
- package/lib/util/parseBoxShadowValue.js +30 -23
- package/lib/util/parseDependency.js +38 -56
- package/lib/util/parseGlob.js +34 -0
- package/lib/util/parseObjectStyles.js +11 -8
- package/lib/util/pluginUtils.js +147 -50
- package/lib/util/prefixSelector.js +10 -8
- package/lib/util/removeAlphaVariables.js +29 -0
- package/lib/util/resolveConfig.js +97 -85
- package/lib/util/resolveConfigPath.js +11 -9
- package/lib/util/responsive.js +8 -5
- package/lib/util/splitAtTopLevelOnly.js +43 -0
- package/lib/util/tap.js +4 -1
- package/lib/util/toColorValue.js +5 -3
- package/lib/util/toPath.js +20 -4
- package/lib/util/transformThemeValue.js +37 -29
- package/lib/util/validateConfig.js +24 -0
- package/lib/util/validateFormalSyntax.js +24 -0
- package/lib/util/withAlphaVariable.js +23 -15
- package/nesting/index.js +2 -12
- package/package.json +47 -42
- package/peers/index.js +11381 -7950
- package/plugin.d.ts +11 -0
- package/resolveConfig.d.ts +12 -0
- package/scripts/generate-types.js +105 -0
- package/scripts/release-channel.js +18 -0
- package/scripts/release-notes.js +21 -0
- package/scripts/type-utils.js +27 -0
- package/src/cli/build/deps.js +56 -0
- package/src/cli/build/index.js +49 -0
- package/src/cli/build/plugin.js +439 -0
- package/src/cli/build/utils.js +76 -0
- package/src/cli/build/watching.js +227 -0
- package/src/cli/help/index.js +70 -0
- package/src/cli/index.js +3 -0
- package/src/cli/init/index.js +50 -0
- package/src/cli/shared.js +6 -0
- package/src/cli-peer-dependencies.js +7 -1
- package/src/cli.js +50 -629
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +532 -217
- package/src/css/preflight.css +5 -5
- package/src/featureFlags.js +15 -9
- package/src/index.js +20 -1
- package/src/lib/cacheInvalidation.js +52 -0
- package/src/lib/collapseAdjacentRules.js +21 -2
- package/src/lib/content.js +212 -0
- package/src/lib/defaultExtractor.js +196 -33
- package/src/lib/evaluateTailwindFunctions.js +78 -7
- package/src/lib/expandApplyAtRules.js +482 -183
- package/src/lib/expandTailwindAtRules.js +106 -85
- package/src/lib/findAtConfigPath.js +48 -0
- package/src/lib/generateRules.js +418 -129
- package/src/lib/normalizeTailwindDirectives.js +1 -0
- package/src/lib/offsets.js +270 -0
- package/src/lib/partitionApplyAtRules.js +52 -0
- package/src/lib/regex.js +74 -0
- package/src/lib/resolveDefaultsAtRules.js +51 -30
- package/src/lib/setupContextUtils.js +556 -208
- package/src/lib/setupTrackingContext.js +11 -48
- package/src/lib/sharedState.js +5 -0
- package/src/postcss-plugins/nesting/README.md +42 -0
- package/src/postcss-plugins/nesting/index.js +13 -0
- package/src/postcss-plugins/nesting/plugin.js +80 -0
- package/src/processTailwindFeatures.js +8 -0
- package/src/util/buildMediaQuery.js +5 -3
- package/src/util/cloneNodes.js +19 -2
- package/src/util/color.js +25 -21
- package/src/util/dataTypes.js +29 -21
- package/src/util/formatVariantSelector.js +184 -61
- package/src/util/getAllConfigs.js +19 -0
- package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
- package/src/util/log.js +8 -8
- package/src/util/nameClass.js +4 -0
- package/src/util/negateValue.js +11 -3
- package/src/util/normalizeConfig.js +44 -6
- package/src/util/normalizeScreens.js +99 -4
- package/src/util/parseBoxShadowValue.js +4 -3
- package/src/util/parseDependency.js +37 -42
- package/src/util/parseGlob.js +24 -0
- package/src/util/pluginUtils.js +132 -10
- package/src/util/prefixSelector.js +7 -5
- package/src/util/removeAlphaVariables.js +24 -0
- package/src/util/resolveConfig.js +70 -32
- package/src/util/splitAtTopLevelOnly.js +45 -0
- package/src/util/toPath.js +1 -1
- package/src/util/transformThemeValue.js +13 -3
- package/src/util/validateConfig.js +13 -0
- package/src/util/validateFormalSyntax.js +34 -0
- package/src/util/withAlphaVariable.js +1 -1
- package/stubs/defaultConfig.stub.js +23 -20
- package/stubs/simpleConfig.stub.js +1 -0
- package/types/config.d.ts +362 -0
- package/types/generated/.gitkeep +0 -0
- package/types/generated/colors.d.ts +276 -0
- package/types/generated/corePluginList.d.ts +1 -0
- package/types/generated/default-theme.d.ts +342 -0
- package/types/index.d.ts +7 -0
- package/nesting/plugin.js +0 -41
|
@@ -11,65 +11,46 @@ import isPlainObject from '../util/isPlainObject'
|
|
|
11
11
|
import escapeClassName from '../util/escapeClassName'
|
|
12
12
|
import nameClass, { formatClass } from '../util/nameClass'
|
|
13
13
|
import { coerceValue } from '../util/pluginUtils'
|
|
14
|
-
import bigSign from '../util/bigSign'
|
|
15
14
|
import { variantPlugins, corePlugins } from '../corePlugins'
|
|
16
15
|
import * as sharedState from './sharedState'
|
|
17
16
|
import { env } from './sharedState'
|
|
18
17
|
import { toPath } from '../util/toPath'
|
|
19
18
|
import log from '../util/log'
|
|
20
19
|
import negateValue from '../util/negateValue'
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPropertyValue'
|
|
21
|
+
import { generateRules, getClassNameFromSelector } from './generateRules'
|
|
22
|
+
import { hasContentChanged } from './cacheInvalidation.js'
|
|
23
|
+
import { Offsets } from './offsets.js'
|
|
24
|
+
import { flagEnabled } from '../featureFlags.js'
|
|
25
|
+
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
|
|
26
|
+
|
|
27
|
+
const VARIANT_TYPES = {
|
|
28
|
+
AddVariant: Symbol.for('ADD_VARIANT'),
|
|
29
|
+
MatchVariant: Symbol.for('MATCH_VARIANT'),
|
|
30
|
+
}
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
const VARIANT_INFO = {
|
|
33
|
+
Base: 1 << 0,
|
|
34
|
+
Dynamic: 1 << 1,
|
|
35
|
+
}
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
function prefix(context, selector) {
|
|
38
|
+
let prefix = context.tailwindConfig.prefix
|
|
39
|
+
return typeof prefix === 'function' ? prefix(selector) : prefix + selector
|
|
40
|
+
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let lastGroup = []
|
|
42
|
+
function normalizeOptionTypes({ type = 'any', ...options }) {
|
|
43
|
+
let types = [].concat(type)
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
nodeGroups.push([node])
|
|
48
|
-
} else {
|
|
49
|
-
lastGroup.push(node)
|
|
45
|
+
return {
|
|
46
|
+
...options,
|
|
47
|
+
types: types.map((type) => {
|
|
48
|
+
if (Array.isArray(type)) {
|
|
49
|
+
return { type: type[0], ...type[1] }
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (lastGroup.length > 0) {
|
|
54
|
-
nodeGroups.push(lastGroup)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (nodeGroups.length === 1) {
|
|
58
|
-
rules.push(rule)
|
|
59
|
-
continue
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
for (let group of [...nodeGroups].reverse()) {
|
|
63
|
-
let clone = rule.clone({ nodes: [] })
|
|
64
|
-
clone.append(group)
|
|
65
|
-
rules.unshift(clone)
|
|
66
|
-
rule.after(clone)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
rule.remove()
|
|
51
|
+
return { type, preferOnConflict: false }
|
|
52
|
+
}),
|
|
70
53
|
}
|
|
71
|
-
|
|
72
|
-
return rules
|
|
73
54
|
}
|
|
74
55
|
|
|
75
56
|
function parseVariantFormatString(input) {
|
|
@@ -130,12 +111,18 @@ function parseStyles(styles) {
|
|
|
130
111
|
})
|
|
131
112
|
}
|
|
132
113
|
|
|
133
|
-
function getClasses(selector) {
|
|
114
|
+
function getClasses(selector, mutate) {
|
|
134
115
|
let parser = selectorParser((selectors) => {
|
|
135
116
|
let allClasses = []
|
|
117
|
+
|
|
118
|
+
if (mutate) {
|
|
119
|
+
mutate(selectors)
|
|
120
|
+
}
|
|
121
|
+
|
|
136
122
|
selectors.walkClasses((classNode) => {
|
|
137
123
|
allClasses.push(classNode.value)
|
|
138
124
|
})
|
|
125
|
+
|
|
139
126
|
return allClasses
|
|
140
127
|
})
|
|
141
128
|
return parser.transformSync(selector)
|
|
@@ -146,8 +133,20 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
|
|
|
146
133
|
|
|
147
134
|
// Handle normal rules
|
|
148
135
|
if (node.type === 'rule') {
|
|
136
|
+
// Ignore everything inside a :not(...). This allows you to write code like
|
|
137
|
+
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to
|
|
138
|
+
// not generated it. But now we will ignore everything inside a `:not`, so
|
|
139
|
+
// that it still gets generated.
|
|
140
|
+
function ignoreNot(selectors) {
|
|
141
|
+
selectors.walkPseudos((pseudo) => {
|
|
142
|
+
if (pseudo.value === ':not') {
|
|
143
|
+
pseudo.remove()
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
149
148
|
for (let selector of node.selectors) {
|
|
150
|
-
let classCandidates = getClasses(selector)
|
|
149
|
+
let classCandidates = getClasses(selector, ignoreNot)
|
|
151
150
|
// At least one of the selectors contains non-"on-demandable" candidates.
|
|
152
151
|
if (classCandidates.length === 0) {
|
|
153
152
|
state.containsNonOnDemandable = true
|
|
@@ -162,9 +161,7 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
|
|
|
162
161
|
// Handle at-rules (which contains nested rules)
|
|
163
162
|
else if (node.type === 'atrule') {
|
|
164
163
|
node.walkRules((rule) => {
|
|
165
|
-
for (let classCandidate of rule.selectors.flatMap((selector) =>
|
|
166
|
-
getClasses(selector, state, depth + 1)
|
|
167
|
-
)) {
|
|
164
|
+
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) {
|
|
168
165
|
classes.push(classCandidate)
|
|
169
166
|
}
|
|
170
167
|
})
|
|
@@ -184,7 +181,7 @@ function withIdentifiers(styles) {
|
|
|
184
181
|
|
|
185
182
|
// If this isn't "on-demandable", assign it a universal candidate to always include it.
|
|
186
183
|
if (containsNonOnDemandableSelectors) {
|
|
187
|
-
candidates.unshift(
|
|
184
|
+
candidates.unshift(sharedState.NOT_ON_DEMAND)
|
|
188
185
|
}
|
|
189
186
|
|
|
190
187
|
// However, it could be that it also contains "on-demandable" candidates.
|
|
@@ -199,6 +196,41 @@ function withIdentifiers(styles) {
|
|
|
199
196
|
})
|
|
200
197
|
}
|
|
201
198
|
|
|
199
|
+
export function isValidVariantFormatString(format) {
|
|
200
|
+
return format.startsWith('@') || format.includes('&')
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function parseVariant(variant) {
|
|
204
|
+
variant = variant
|
|
205
|
+
.replace(/\n+/g, '')
|
|
206
|
+
.replace(/\s{1,}/g, ' ')
|
|
207
|
+
.trim()
|
|
208
|
+
|
|
209
|
+
let fns = parseVariantFormatString(variant)
|
|
210
|
+
.map((str) => {
|
|
211
|
+
if (!str.startsWith('@')) {
|
|
212
|
+
return ({ format }) => format(str)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(str)
|
|
216
|
+
return ({ wrap }) => wrap(postcss.atRule({ name, params: params.trim() }))
|
|
217
|
+
})
|
|
218
|
+
.reverse()
|
|
219
|
+
|
|
220
|
+
return (api) => {
|
|
221
|
+
for (let fn of fns) {
|
|
222
|
+
fn(api)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
*
|
|
229
|
+
* @param {any} tailwindConfig
|
|
230
|
+
* @param {any} context
|
|
231
|
+
* @param {object} param2
|
|
232
|
+
* @param {Offsets} param2.offsets
|
|
233
|
+
*/
|
|
202
234
|
function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
|
|
203
235
|
function getConfigValue(path, defaultValue) {
|
|
204
236
|
return path ? dlv(tailwindConfig, path, defaultValue) : tailwindConfig
|
|
@@ -209,8 +241,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
209
241
|
}
|
|
210
242
|
|
|
211
243
|
function prefixIdentifier(identifier, options) {
|
|
212
|
-
if (identifier ===
|
|
213
|
-
return
|
|
244
|
+
if (identifier === sharedState.NOT_ON_DEMAND) {
|
|
245
|
+
return sharedState.NOT_ON_DEMAND
|
|
214
246
|
}
|
|
215
247
|
|
|
216
248
|
if (!options.respectPrefix) {
|
|
@@ -220,51 +252,19 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
220
252
|
return context.tailwindConfig.prefix + identifier
|
|
221
253
|
}
|
|
222
254
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return ({ modifySelectors, container, separator }) => {
|
|
229
|
-
return variantFunction({ modifySelectors, container, separator })
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
variantFunction = variantFunction
|
|
234
|
-
.replace(/\n+/g, '')
|
|
235
|
-
.replace(/\s{1,}/g, ' ')
|
|
236
|
-
.trim()
|
|
237
|
-
|
|
238
|
-
let fns = parseVariantFormatString(variantFunction)
|
|
239
|
-
.map((str) => {
|
|
240
|
-
if (!str.startsWith('@')) {
|
|
241
|
-
return ({ format }) => format(str)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
let [, name, params] = /@(.*?) (.*)/g.exec(str)
|
|
245
|
-
return ({ wrap }) => wrap(postcss.atRule({ name, params }))
|
|
246
|
-
})
|
|
247
|
-
.reverse()
|
|
248
|
-
|
|
249
|
-
return (api) => {
|
|
250
|
-
for (let fn of fns) {
|
|
251
|
-
fn(api)
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
})
|
|
255
|
+
function resolveThemeValue(path, defaultValue, opts = {}) {
|
|
256
|
+
let parts = toPath(path)
|
|
257
|
+
let value = getConfigValue(['theme', ...parts], defaultValue)
|
|
258
|
+
return transformThemeValue(parts[0])(value, opts)
|
|
259
|
+
}
|
|
255
260
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
},
|
|
261
|
+
let variantIdentifier = 0
|
|
262
|
+
let api = {
|
|
259
263
|
postcss,
|
|
260
264
|
prefix: applyConfiguredPrefix,
|
|
261
265
|
e: escapeClassName,
|
|
262
266
|
config: getConfigValue,
|
|
263
|
-
theme
|
|
264
|
-
const [pathRoot, ...subPaths] = toPath(path)
|
|
265
|
-
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
|
266
|
-
return transformThemeValue(pathRoot)(value)
|
|
267
|
-
},
|
|
267
|
+
theme: resolveThemeValue,
|
|
268
268
|
corePlugins: (path) => {
|
|
269
269
|
if (Array.isArray(tailwindConfig.corePlugins)) {
|
|
270
270
|
return tailwindConfig.corePlugins.includes(path)
|
|
@@ -276,23 +276,10 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
276
276
|
// Preserved for backwards compatibility but not used in v3.0+
|
|
277
277
|
return []
|
|
278
278
|
},
|
|
279
|
-
addUserCss(userCss) {
|
|
280
|
-
for (let [identifier, rule] of withIdentifiers(userCss)) {
|
|
281
|
-
let offset = offsets.user++
|
|
282
|
-
|
|
283
|
-
if (!context.candidateRuleMap.has(identifier)) {
|
|
284
|
-
context.candidateRuleMap.set(identifier, [])
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
context.candidateRuleMap
|
|
288
|
-
.get(identifier)
|
|
289
|
-
.push(...partitionRules(rule).map((rule) => [{ sort: offset, layer: 'user' }, rule]))
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
279
|
addBase(base) {
|
|
293
280
|
for (let [identifier, rule] of withIdentifiers(base)) {
|
|
294
281
|
let prefixedIdentifier = prefixIdentifier(identifier, {})
|
|
295
|
-
let offset = offsets.base
|
|
282
|
+
let offset = offsets.create('base')
|
|
296
283
|
|
|
297
284
|
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
298
285
|
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
@@ -300,7 +287,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
300
287
|
|
|
301
288
|
context.candidateRuleMap
|
|
302
289
|
.get(prefixedIdentifier)
|
|
303
|
-
.push(
|
|
290
|
+
.push([{ sort: offset, layer: 'base' }, rule])
|
|
304
291
|
}
|
|
305
292
|
},
|
|
306
293
|
/**
|
|
@@ -321,16 +308,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
321
308
|
|
|
322
309
|
context.candidateRuleMap
|
|
323
310
|
.get(prefixedIdentifier)
|
|
324
|
-
.push(
|
|
325
|
-
...partitionRules(rule).map((rule) => [
|
|
326
|
-
{ sort: offsets.base++, layer: 'defaults' },
|
|
327
|
-
rule,
|
|
328
|
-
])
|
|
329
|
-
)
|
|
311
|
+
.push([{ sort: offsets.create('defaults'), layer: 'defaults' }, rule])
|
|
330
312
|
}
|
|
331
313
|
},
|
|
332
314
|
addComponents(components, options) {
|
|
333
315
|
let defaultOptions = {
|
|
316
|
+
preserveSource: false,
|
|
334
317
|
respectPrefix: true,
|
|
335
318
|
respectImportant: false,
|
|
336
319
|
}
|
|
@@ -348,16 +331,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
348
331
|
|
|
349
332
|
context.candidateRuleMap
|
|
350
333
|
.get(prefixedIdentifier)
|
|
351
|
-
.push(
|
|
352
|
-
...partitionRules(rule).map((rule) => [
|
|
353
|
-
{ sort: offsets.components++, layer: 'components', options },
|
|
354
|
-
rule,
|
|
355
|
-
])
|
|
356
|
-
)
|
|
334
|
+
.push([{ sort: offsets.create('components'), layer: 'components', options }, rule])
|
|
357
335
|
}
|
|
358
336
|
},
|
|
359
337
|
addUtilities(utilities, options) {
|
|
360
338
|
let defaultOptions = {
|
|
339
|
+
preserveSource: false,
|
|
361
340
|
respectPrefix: true,
|
|
362
341
|
respectImportant: true,
|
|
363
342
|
}
|
|
@@ -375,23 +354,19 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
375
354
|
|
|
376
355
|
context.candidateRuleMap
|
|
377
356
|
.get(prefixedIdentifier)
|
|
378
|
-
.push(
|
|
379
|
-
...partitionRules(rule).map((rule) => [
|
|
380
|
-
{ sort: offsets.utilities++, layer: 'utilities', options },
|
|
381
|
-
rule,
|
|
382
|
-
])
|
|
383
|
-
)
|
|
357
|
+
.push([{ sort: offsets.create('utilities'), layer: 'utilities', options }, rule])
|
|
384
358
|
}
|
|
385
359
|
},
|
|
386
360
|
matchUtilities: function (utilities, options) {
|
|
387
361
|
let defaultOptions = {
|
|
388
362
|
respectPrefix: true,
|
|
389
363
|
respectImportant: true,
|
|
364
|
+
modifiers: false,
|
|
390
365
|
}
|
|
391
366
|
|
|
392
|
-
options = { ...defaultOptions, ...options }
|
|
367
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
393
368
|
|
|
394
|
-
let offset = offsets.utilities
|
|
369
|
+
let offset = offsets.create('utilities')
|
|
395
370
|
|
|
396
371
|
for (let identifier in utilities) {
|
|
397
372
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
@@ -400,24 +375,51 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
400
375
|
classList.add([prefixedIdentifier, options])
|
|
401
376
|
|
|
402
377
|
function wrapped(modifier, { isOnlyPlugin }) {
|
|
403
|
-
let
|
|
404
|
-
|
|
405
|
-
|
|
378
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
379
|
+
options.types,
|
|
380
|
+
modifier,
|
|
381
|
+
options,
|
|
382
|
+
tailwindConfig
|
|
383
|
+
)
|
|
406
384
|
|
|
407
385
|
if (value === undefined) {
|
|
408
386
|
return []
|
|
409
387
|
}
|
|
410
388
|
|
|
411
|
-
if (!
|
|
412
|
-
|
|
389
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
390
|
+
if (isOnlyPlugin) {
|
|
391
|
+
log.warn([
|
|
392
|
+
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
393
|
+
`You can safely update it to \`${identifier}-${modifier.replace(
|
|
394
|
+
coercedType + ':',
|
|
395
|
+
''
|
|
396
|
+
)}\`.`,
|
|
397
|
+
])
|
|
398
|
+
} else {
|
|
399
|
+
return []
|
|
400
|
+
}
|
|
413
401
|
}
|
|
414
402
|
|
|
415
|
-
if (!
|
|
403
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
416
404
|
return []
|
|
417
405
|
}
|
|
418
406
|
|
|
407
|
+
let extras = {
|
|
408
|
+
get modifier() {
|
|
409
|
+
if (!options.modifiers) {
|
|
410
|
+
log.warn(`modifier-used-without-options-for-${identifier}`, [
|
|
411
|
+
'Your plugin must set `modifiers: true` in its options to support modifiers.',
|
|
412
|
+
])
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return utilityModifier
|
|
416
|
+
},
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
|
|
420
|
+
|
|
419
421
|
let ruleSets = []
|
|
420
|
-
.concat(rule(value))
|
|
422
|
+
.concat(modifiersEnabled ? rule(value, extras) : rule(value))
|
|
421
423
|
.filter(Boolean)
|
|
422
424
|
.map((declaration) => ({
|
|
423
425
|
[nameClass(identifier, modifier)]: declaration,
|
|
@@ -439,11 +441,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
439
441
|
let defaultOptions = {
|
|
440
442
|
respectPrefix: true,
|
|
441
443
|
respectImportant: false,
|
|
444
|
+
modifiers: false,
|
|
442
445
|
}
|
|
443
446
|
|
|
444
|
-
options = { ...defaultOptions, ...options }
|
|
447
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
445
448
|
|
|
446
|
-
let offset = offsets.components
|
|
449
|
+
let offset = offsets.create('components')
|
|
447
450
|
|
|
448
451
|
for (let identifier in components) {
|
|
449
452
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
@@ -452,15 +455,18 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
452
455
|
classList.add([prefixedIdentifier, options])
|
|
453
456
|
|
|
454
457
|
function wrapped(modifier, { isOnlyPlugin }) {
|
|
455
|
-
let
|
|
456
|
-
|
|
457
|
-
|
|
458
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
459
|
+
options.types,
|
|
460
|
+
modifier,
|
|
461
|
+
options,
|
|
462
|
+
tailwindConfig
|
|
463
|
+
)
|
|
458
464
|
|
|
459
465
|
if (value === undefined) {
|
|
460
466
|
return []
|
|
461
467
|
}
|
|
462
468
|
|
|
463
|
-
if (!
|
|
469
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
464
470
|
if (isOnlyPlugin) {
|
|
465
471
|
log.warn([
|
|
466
472
|
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
@@ -474,12 +480,26 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
474
480
|
}
|
|
475
481
|
}
|
|
476
482
|
|
|
477
|
-
if (!
|
|
483
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
478
484
|
return []
|
|
479
485
|
}
|
|
480
486
|
|
|
487
|
+
let extras = {
|
|
488
|
+
get modifier() {
|
|
489
|
+
if (!options.modifiers) {
|
|
490
|
+
log.warn(`modifier-used-without-options-for-${identifier}`, [
|
|
491
|
+
'Your plugin must set `modifiers: true` in its options to support modifiers.',
|
|
492
|
+
])
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return utilityModifier
|
|
496
|
+
},
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
|
|
500
|
+
|
|
481
501
|
let ruleSets = []
|
|
482
|
-
.concat(rule(value))
|
|
502
|
+
.concat(modifiersEnabled ? rule(value, extras) : rule(value))
|
|
483
503
|
.filter(Boolean)
|
|
484
504
|
.map((declaration) => ({
|
|
485
505
|
[nameClass(identifier, modifier)]: declaration,
|
|
@@ -497,7 +517,109 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
497
517
|
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
|
|
498
518
|
}
|
|
499
519
|
},
|
|
520
|
+
addVariant(variantName, variantFunctions, options = {}) {
|
|
521
|
+
variantFunctions = [].concat(variantFunctions).map((variantFunction) => {
|
|
522
|
+
if (typeof variantFunction !== 'string') {
|
|
523
|
+
// Safelist public API functions
|
|
524
|
+
return (api = {}) => {
|
|
525
|
+
let { args, modifySelectors, container, separator, wrap, format } = api
|
|
526
|
+
let result = variantFunction(
|
|
527
|
+
Object.assign(
|
|
528
|
+
{ modifySelectors, container, separator },
|
|
529
|
+
options.type === VARIANT_TYPES.MatchVariant && { args, wrap, format }
|
|
530
|
+
)
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
if (typeof result === 'string' && !isValidVariantFormatString(result)) {
|
|
534
|
+
throw new Error(
|
|
535
|
+
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
|
|
536
|
+
)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (Array.isArray(result)) {
|
|
540
|
+
return result
|
|
541
|
+
.filter((variant) => typeof variant === 'string')
|
|
542
|
+
.map((variant) => parseVariant(variant))
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// result may be undefined with legacy variants that use APIs like `modifySelectors`
|
|
546
|
+
// result may also be a postcss node if someone was returning the result from `modifySelectors`
|
|
547
|
+
return result && typeof result === 'string' && parseVariant(result)(api)
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (!isValidVariantFormatString(variantFunction)) {
|
|
552
|
+
throw new Error(
|
|
553
|
+
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
|
|
554
|
+
)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return parseVariant(variantFunction)
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
insertInto(variantList, variantName, options)
|
|
561
|
+
variantMap.set(variantName, variantFunctions)
|
|
562
|
+
context.variantOptions.set(variantName, options)
|
|
563
|
+
},
|
|
564
|
+
matchVariant(variant, variantFn, options) {
|
|
565
|
+
// A unique identifier that "groups" these variants together.
|
|
566
|
+
// This is for internal use only which is why it is not present in the types
|
|
567
|
+
let id = options?.id ?? ++variantIdentifier
|
|
568
|
+
let isSpecial = variant === '@'
|
|
569
|
+
|
|
570
|
+
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
|
|
571
|
+
|
|
572
|
+
for (let [key, value] of Object.entries(options?.values ?? {})) {
|
|
573
|
+
if (key === 'DEFAULT') continue
|
|
574
|
+
|
|
575
|
+
api.addVariant(
|
|
576
|
+
isSpecial ? `${variant}${key}` : `${variant}-${key}`,
|
|
577
|
+
({ args, container }) => {
|
|
578
|
+
return variantFn(
|
|
579
|
+
value,
|
|
580
|
+
modifiersEnabled ? { modifier: args?.modifier, container } : { container }
|
|
581
|
+
)
|
|
582
|
+
},
|
|
583
|
+
|
|
584
|
+
{
|
|
585
|
+
...options,
|
|
586
|
+
value,
|
|
587
|
+
id,
|
|
588
|
+
type: VARIANT_TYPES.MatchVariant,
|
|
589
|
+
variantInfo: VARIANT_INFO.Base,
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let hasDefault = 'DEFAULT' in (options?.values ?? {})
|
|
595
|
+
|
|
596
|
+
api.addVariant(
|
|
597
|
+
variant,
|
|
598
|
+
({ args, container }) => {
|
|
599
|
+
if (args?.value === sharedState.NONE && !hasDefault) {
|
|
600
|
+
return null
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return variantFn(
|
|
604
|
+
args?.value === sharedState.NONE
|
|
605
|
+
? options.values.DEFAULT
|
|
606
|
+
: // Falling back to args if it is a string, otherwise '' for older intellisense
|
|
607
|
+
// (JetBrains) plugins.
|
|
608
|
+
args?.value ?? (typeof args === 'string' ? args : ''),
|
|
609
|
+
modifiersEnabled ? { modifier: args?.modifier, container } : { container }
|
|
610
|
+
)
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
...options,
|
|
614
|
+
id,
|
|
615
|
+
type: VARIANT_TYPES.MatchVariant,
|
|
616
|
+
variantInfo: VARIANT_INFO.Dynamic,
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
},
|
|
500
620
|
}
|
|
621
|
+
|
|
622
|
+
return api
|
|
501
623
|
}
|
|
502
624
|
|
|
503
625
|
let fileModifiedMapCache = new WeakMap()
|
|
@@ -570,29 +692,20 @@ function collectLayerPlugins(root) {
|
|
|
570
692
|
} else if (layerRule.params === 'components') {
|
|
571
693
|
for (let node of layerRule.nodes) {
|
|
572
694
|
layerPlugins.push(function ({ addComponents }) {
|
|
573
|
-
addComponents(node, { respectPrefix: false })
|
|
695
|
+
addComponents(node, { respectPrefix: false, preserveSource: true })
|
|
574
696
|
})
|
|
575
697
|
}
|
|
576
698
|
layerRule.remove()
|
|
577
699
|
} else if (layerRule.params === 'utilities') {
|
|
578
700
|
for (let node of layerRule.nodes) {
|
|
579
701
|
layerPlugins.push(function ({ addUtilities }) {
|
|
580
|
-
addUtilities(node, { respectPrefix: false })
|
|
702
|
+
addUtilities(node, { respectPrefix: false, preserveSource: true })
|
|
581
703
|
})
|
|
582
704
|
}
|
|
583
705
|
layerRule.remove()
|
|
584
706
|
}
|
|
585
707
|
})
|
|
586
708
|
|
|
587
|
-
root.walkRules((rule) => {
|
|
588
|
-
// At this point it is safe to include all the left-over css from the
|
|
589
|
-
// user's css file. This is because the `@tailwind` and `@layer` directives
|
|
590
|
-
// will already be handled and will be removed from the css tree.
|
|
591
|
-
layerPlugins.push(function ({ addUserCss }) {
|
|
592
|
-
addUserCss(rule, { respectPrefix: false })
|
|
593
|
-
})
|
|
594
|
-
})
|
|
595
|
-
|
|
596
709
|
return layerPlugins
|
|
597
710
|
}
|
|
598
711
|
|
|
@@ -622,10 +735,14 @@ function resolvePlugins(context, root) {
|
|
|
622
735
|
let beforeVariants = [
|
|
623
736
|
variantPlugins['pseudoElementVariants'],
|
|
624
737
|
variantPlugins['pseudoClassVariants'],
|
|
738
|
+
variantPlugins['ariaVariants'],
|
|
739
|
+
variantPlugins['dataVariants'],
|
|
625
740
|
]
|
|
626
741
|
let afterVariants = [
|
|
742
|
+
variantPlugins['supportsVariants'],
|
|
627
743
|
variantPlugins['directionVariants'],
|
|
628
744
|
variantPlugins['reducedMotionVariants'],
|
|
745
|
+
variantPlugins['prefersContrastVariants'],
|
|
629
746
|
variantPlugins['darkVariants'],
|
|
630
747
|
variantPlugins['printVariant'],
|
|
631
748
|
variantPlugins['screenVariants'],
|
|
@@ -638,13 +755,10 @@ function resolvePlugins(context, root) {
|
|
|
638
755
|
function registerPlugins(plugins, context) {
|
|
639
756
|
let variantList = []
|
|
640
757
|
let variantMap = new Map()
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
utilities: 0n,
|
|
646
|
-
user: 0n,
|
|
647
|
-
}
|
|
758
|
+
context.variantMap = variantMap
|
|
759
|
+
|
|
760
|
+
let offsets = new Offsets()
|
|
761
|
+
context.offsets = offsets
|
|
648
762
|
|
|
649
763
|
let classList = new Set()
|
|
650
764
|
|
|
@@ -665,49 +779,17 @@ function registerPlugins(plugins, context) {
|
|
|
665
779
|
}
|
|
666
780
|
}
|
|
667
781
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
offsets.defaults,
|
|
671
|
-
offsets.components,
|
|
672
|
-
offsets.utilities,
|
|
673
|
-
offsets.user,
|
|
674
|
-
])
|
|
675
|
-
let reservedBits = BigInt(highestOffset.toString(2).length)
|
|
676
|
-
|
|
677
|
-
// A number one less than the top range of the highest offset area
|
|
678
|
-
// so arbitrary properties are always sorted at the end.
|
|
679
|
-
context.arbitraryPropertiesSort = ((1n << reservedBits) << 0n) - 1n
|
|
680
|
-
|
|
681
|
-
context.layerOrder = {
|
|
682
|
-
defaults: (1n << reservedBits) << 0n,
|
|
683
|
-
base: (1n << reservedBits) << 1n,
|
|
684
|
-
components: (1n << reservedBits) << 2n,
|
|
685
|
-
utilities: (1n << reservedBits) << 3n,
|
|
686
|
-
user: (1n << reservedBits) << 4n,
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
reservedBits += 5n
|
|
690
|
-
|
|
691
|
-
let offset = 0
|
|
692
|
-
context.variantOrder = new Map(
|
|
693
|
-
variantList
|
|
694
|
-
.map((variant, i) => {
|
|
695
|
-
let variantFunctions = variantMap.get(variant).length
|
|
696
|
-
let bits = (1n << BigInt(i + offset)) << reservedBits
|
|
697
|
-
offset += variantFunctions - 1
|
|
698
|
-
return [variant, bits]
|
|
699
|
-
})
|
|
700
|
-
.sort(([, a], [, z]) => bigSign(a - z))
|
|
701
|
-
)
|
|
702
|
-
|
|
703
|
-
context.minimumScreen = [...context.variantOrder.values()].shift()
|
|
782
|
+
// Make sure to record bit masks for every variant
|
|
783
|
+
offsets.recordVariants(variantList, (variant) => variantMap.get(variant).length)
|
|
704
784
|
|
|
705
785
|
// Build variantMap
|
|
706
786
|
for (let [variantName, variantFunctions] of variantMap.entries()) {
|
|
707
|
-
let sort = context.variantOrder.get(variantName)
|
|
708
787
|
context.variantMap.set(
|
|
709
788
|
variantName,
|
|
710
|
-
variantFunctions.map((variantFunction, idx) => [
|
|
789
|
+
variantFunctions.map((variantFunction, idx) => [
|
|
790
|
+
offsets.forVariant(variantName, idx),
|
|
791
|
+
variantFunction,
|
|
792
|
+
])
|
|
711
793
|
)
|
|
712
794
|
}
|
|
713
795
|
|
|
@@ -725,7 +807,7 @@ function registerPlugins(plugins, context) {
|
|
|
725
807
|
log.warn('root-regex', [
|
|
726
808
|
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
|
|
727
809
|
'Update your `safelist` configuration to eliminate this warning.',
|
|
728
|
-
|
|
810
|
+
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
|
|
729
811
|
])
|
|
730
812
|
continue
|
|
731
813
|
}
|
|
@@ -735,17 +817,46 @@ function registerPlugins(plugins, context) {
|
|
|
735
817
|
|
|
736
818
|
if (checks.length > 0) {
|
|
737
819
|
let patternMatchingCount = new Map()
|
|
820
|
+
let prefixLength = context.tailwindConfig.prefix.length
|
|
821
|
+
let checkImportantUtils = checks.some((check) => check.pattern.source.includes('!'))
|
|
738
822
|
|
|
739
823
|
for (let util of classList) {
|
|
740
824
|
let utils = Array.isArray(util)
|
|
741
825
|
? (() => {
|
|
742
826
|
let [utilName, options] = util
|
|
743
|
-
let
|
|
744
|
-
|
|
745
|
-
)
|
|
827
|
+
let values = Object.keys(options?.values ?? {})
|
|
828
|
+
let classes = values.map((value) => formatClass(utilName, value))
|
|
746
829
|
|
|
747
830
|
if (options?.supportsNegativeValues) {
|
|
831
|
+
// This is the normal negated version
|
|
832
|
+
// e.g. `-inset-1` or `-tw-inset-1`
|
|
748
833
|
classes = [...classes, ...classes.map((cls) => '-' + cls)]
|
|
834
|
+
|
|
835
|
+
// This is the negated version *after* the prefix
|
|
836
|
+
// e.g. `tw--inset-1`
|
|
837
|
+
// The prefix is already attached to util name
|
|
838
|
+
// So we add the negative after the prefix
|
|
839
|
+
classes = [
|
|
840
|
+
...classes,
|
|
841
|
+
...classes.map(
|
|
842
|
+
(cls) => cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength)
|
|
843
|
+
),
|
|
844
|
+
]
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (options.types.some(({ type }) => type === 'color')) {
|
|
848
|
+
classes = [
|
|
849
|
+
...classes,
|
|
850
|
+
...classes.flatMap((cls) =>
|
|
851
|
+
Object.keys(context.tailwindConfig.theme.opacity).map(
|
|
852
|
+
(opacity) => `${cls}/${opacity}`
|
|
853
|
+
)
|
|
854
|
+
),
|
|
855
|
+
]
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
if (checkImportantUtils && options?.respectImportant) {
|
|
859
|
+
classes = [...classes, ...classes.map((cls) => '!' + cls)]
|
|
749
860
|
}
|
|
750
861
|
|
|
751
862
|
return classes
|
|
@@ -783,14 +894,56 @@ function registerPlugins(plugins, context) {
|
|
|
783
894
|
log.warn([
|
|
784
895
|
`The safelist pattern \`${regex}\` doesn't match any Tailwind CSS classes.`,
|
|
785
896
|
'Fix this pattern or remove it from your `safelist` configuration.',
|
|
897
|
+
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
|
|
786
898
|
])
|
|
787
899
|
}
|
|
788
900
|
}
|
|
789
901
|
}
|
|
790
902
|
|
|
903
|
+
let darkClassName = [].concat(context.tailwindConfig.darkMode ?? 'media')[1] ?? 'dark'
|
|
904
|
+
|
|
905
|
+
// A list of utilities that are used by certain Tailwind CSS utilities but
|
|
906
|
+
// that don't exist on their own. This will result in them "not existing" and
|
|
907
|
+
// sorting could be weird since you still require them in order to make the
|
|
908
|
+
// host utilities work properly. (Thanks Biology)
|
|
909
|
+
let parasiteUtilities = [
|
|
910
|
+
prefix(context, darkClassName),
|
|
911
|
+
prefix(context, 'group'),
|
|
912
|
+
prefix(context, 'peer'),
|
|
913
|
+
]
|
|
914
|
+
context.getClassOrder = function getClassOrder(classes) {
|
|
915
|
+
// Non-util classes won't be generated, so we default them to null
|
|
916
|
+
let sortedClassNames = new Map(classes.map((className) => [className, null]))
|
|
917
|
+
|
|
918
|
+
// Sort all classes in order
|
|
919
|
+
// Non-tailwind classes won't be generated and will be left as `null`
|
|
920
|
+
let rules = generateRules(new Set(classes), context)
|
|
921
|
+
rules = context.offsets.sort(rules)
|
|
922
|
+
|
|
923
|
+
let idx = BigInt(parasiteUtilities.length)
|
|
924
|
+
|
|
925
|
+
for (const [, rule] of rules) {
|
|
926
|
+
sortedClassNames.set(rule.raws.tailwind.candidate, idx++)
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
return classes.map((className) => {
|
|
930
|
+
let order = sortedClassNames.get(className) ?? null
|
|
931
|
+
let parasiteIndex = parasiteUtilities.indexOf(className)
|
|
932
|
+
|
|
933
|
+
if (order === null && parasiteIndex !== -1) {
|
|
934
|
+
// This will make sure that it is at the very beginning of the
|
|
935
|
+
// `components` layer which technically means 'before any
|
|
936
|
+
// components'.
|
|
937
|
+
order = BigInt(parasiteIndex)
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return [className, order]
|
|
941
|
+
})
|
|
942
|
+
}
|
|
943
|
+
|
|
791
944
|
// Generate a list of strings for autocompletion purposes, e.g.
|
|
792
945
|
// ['uppercase', 'lowercase', ...]
|
|
793
|
-
context.getClassList = function () {
|
|
946
|
+
context.getClassList = function getClassList() {
|
|
794
947
|
let output = []
|
|
795
948
|
|
|
796
949
|
for (let util of classList) {
|
|
@@ -799,6 +952,11 @@ function registerPlugins(plugins, context) {
|
|
|
799
952
|
let negativeClasses = []
|
|
800
953
|
|
|
801
954
|
for (let [key, value] of Object.entries(options?.values ?? {})) {
|
|
955
|
+
// Ignore undefined and null values
|
|
956
|
+
if (value == null) {
|
|
957
|
+
continue
|
|
958
|
+
}
|
|
959
|
+
|
|
802
960
|
output.push(formatClass(utilName, key))
|
|
803
961
|
if (options?.supportsNegativeValues && negateValue(value)) {
|
|
804
962
|
negativeClasses.push(formatClass(utilName, `-${key}`))
|
|
@@ -813,21 +971,205 @@ function registerPlugins(plugins, context) {
|
|
|
813
971
|
|
|
814
972
|
return output
|
|
815
973
|
}
|
|
974
|
+
|
|
975
|
+
// Generate a list of available variants with meta information of the type of variant.
|
|
976
|
+
context.getVariants = function getVariants() {
|
|
977
|
+
let result = []
|
|
978
|
+
for (let [name, options] of context.variantOptions.entries()) {
|
|
979
|
+
if (options.variantInfo === VARIANT_INFO.Base) continue
|
|
980
|
+
|
|
981
|
+
result.push({
|
|
982
|
+
name,
|
|
983
|
+
isArbitrary: options.type === Symbol.for('MATCH_VARIANT'),
|
|
984
|
+
values: Object.keys(options.values ?? {}),
|
|
985
|
+
hasDash: name !== '@',
|
|
986
|
+
selectors({ modifier, value } = {}) {
|
|
987
|
+
let candidate = '__TAILWIND_PLACEHOLDER__'
|
|
988
|
+
|
|
989
|
+
let rule = postcss.rule({ selector: `.${candidate}` })
|
|
990
|
+
let container = postcss.root({ nodes: [rule.clone()] })
|
|
991
|
+
|
|
992
|
+
let before = container.toString()
|
|
993
|
+
|
|
994
|
+
let fns = (context.variantMap.get(name) ?? []).flatMap(([_, fn]) => fn)
|
|
995
|
+
let formatStrings = []
|
|
996
|
+
for (let fn of fns) {
|
|
997
|
+
let localFormatStrings = []
|
|
998
|
+
|
|
999
|
+
let api = {
|
|
1000
|
+
args: { modifier, value: options.values?.[value] ?? value },
|
|
1001
|
+
separator: context.tailwindConfig.separator,
|
|
1002
|
+
modifySelectors(modifierFunction) {
|
|
1003
|
+
// Run the modifierFunction over each rule
|
|
1004
|
+
container.each((rule) => {
|
|
1005
|
+
if (rule.type !== 'rule') {
|
|
1006
|
+
return
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
rule.selectors = rule.selectors.map((selector) => {
|
|
1010
|
+
return modifierFunction({
|
|
1011
|
+
get className() {
|
|
1012
|
+
return getClassNameFromSelector(selector)
|
|
1013
|
+
},
|
|
1014
|
+
selector,
|
|
1015
|
+
})
|
|
1016
|
+
})
|
|
1017
|
+
})
|
|
1018
|
+
|
|
1019
|
+
return container
|
|
1020
|
+
},
|
|
1021
|
+
format(str) {
|
|
1022
|
+
localFormatStrings.push(str)
|
|
1023
|
+
},
|
|
1024
|
+
wrap(wrapper) {
|
|
1025
|
+
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`)
|
|
1026
|
+
},
|
|
1027
|
+
container,
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
let ruleWithVariant = fn(api)
|
|
1031
|
+
if (localFormatStrings.length > 0) {
|
|
1032
|
+
formatStrings.push(localFormatStrings)
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if (Array.isArray(ruleWithVariant)) {
|
|
1036
|
+
for (let variantFunction of ruleWithVariant) {
|
|
1037
|
+
localFormatStrings = []
|
|
1038
|
+
variantFunction(api)
|
|
1039
|
+
formatStrings.push(localFormatStrings)
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Reverse engineer the result of the `container`
|
|
1045
|
+
let manualFormatStrings = []
|
|
1046
|
+
let after = container.toString()
|
|
1047
|
+
|
|
1048
|
+
if (before !== after) {
|
|
1049
|
+
// Figure out all selectors
|
|
1050
|
+
container.walkRules((rule) => {
|
|
1051
|
+
let modified = rule.selector
|
|
1052
|
+
|
|
1053
|
+
// Rebuild the base selector, this is what plugin authors would do
|
|
1054
|
+
// as well. E.g.: `${variant}${separator}${className}`.
|
|
1055
|
+
// However, plugin authors probably also prepend or append certain
|
|
1056
|
+
// classes, pseudos, ids, ...
|
|
1057
|
+
let rebuiltBase = selectorParser((selectors) => {
|
|
1058
|
+
selectors.walkClasses((classNode) => {
|
|
1059
|
+
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`
|
|
1060
|
+
})
|
|
1061
|
+
}).processSync(modified)
|
|
1062
|
+
|
|
1063
|
+
// Now that we know the original selector, the new selector, and
|
|
1064
|
+
// the rebuild part in between, we can replace the part that plugin
|
|
1065
|
+
// authors need to rebuild with `&`, and eventually store it in the
|
|
1066
|
+
// collectedFormats. Similar to what `format('...')` would do.
|
|
1067
|
+
//
|
|
1068
|
+
// E.g.:
|
|
1069
|
+
// variant: foo
|
|
1070
|
+
// selector: .markdown > p
|
|
1071
|
+
// modified (by plugin): .foo .foo\\:markdown > p
|
|
1072
|
+
// rebuiltBase (internal): .foo\\:markdown > p
|
|
1073
|
+
// format: .foo &
|
|
1074
|
+
manualFormatStrings.push(modified.replace(rebuiltBase, '&').replace(candidate, '&'))
|
|
1075
|
+
})
|
|
1076
|
+
|
|
1077
|
+
// Figure out all atrules
|
|
1078
|
+
container.walkAtRules((atrule) => {
|
|
1079
|
+
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`)
|
|
1080
|
+
})
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
let result = formatStrings.map((formatString) =>
|
|
1084
|
+
finalizeSelector(formatVariantSelector('&', ...formatString), {
|
|
1085
|
+
selector: `.${candidate}`,
|
|
1086
|
+
candidate,
|
|
1087
|
+
context,
|
|
1088
|
+
isArbitraryVariant: !(value in (options.values ?? {})),
|
|
1089
|
+
})
|
|
1090
|
+
.replace(`.${candidate}`, '&')
|
|
1091
|
+
.replace('{ & }', '')
|
|
1092
|
+
.trim()
|
|
1093
|
+
)
|
|
1094
|
+
|
|
1095
|
+
if (manualFormatStrings.length > 0) {
|
|
1096
|
+
result.push(formatVariantSelector('&', ...manualFormatStrings))
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
return result
|
|
1100
|
+
},
|
|
1101
|
+
})
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
return result
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Mark as class as retroactively invalid
|
|
1110
|
+
*
|
|
1111
|
+
*
|
|
1112
|
+
* @param {string} candidate
|
|
1113
|
+
*/
|
|
1114
|
+
function markInvalidUtilityCandidate(context, candidate) {
|
|
1115
|
+
if (!context.classCache.has(candidate)) {
|
|
1116
|
+
return
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Mark this as not being a real utility
|
|
1120
|
+
context.notClassCache.add(candidate)
|
|
1121
|
+
|
|
1122
|
+
// Remove it from any candidate-specific caches
|
|
1123
|
+
context.classCache.delete(candidate)
|
|
1124
|
+
context.applyClassCache.delete(candidate)
|
|
1125
|
+
context.candidateRuleMap.delete(candidate)
|
|
1126
|
+
context.candidateRuleCache.delete(candidate)
|
|
1127
|
+
|
|
1128
|
+
// Ensure the stylesheet gets rebuilt
|
|
1129
|
+
context.stylesheetCache = null
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/**
|
|
1133
|
+
* Mark as class as retroactively invalid
|
|
1134
|
+
*
|
|
1135
|
+
* @param {import('postcss').Node} node
|
|
1136
|
+
*/
|
|
1137
|
+
function markInvalidUtilityNode(context, node) {
|
|
1138
|
+
let candidate = node.raws.tailwind.candidate
|
|
1139
|
+
|
|
1140
|
+
if (!candidate) {
|
|
1141
|
+
return
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
for (const entry of context.ruleCache) {
|
|
1145
|
+
if (entry[1].raws.tailwind.candidate === candidate) {
|
|
1146
|
+
context.ruleCache.delete(entry)
|
|
1147
|
+
// context.postCssNodeCache.delete(node)
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
markInvalidUtilityCandidate(context, candidate)
|
|
816
1152
|
}
|
|
817
1153
|
|
|
818
1154
|
export function createContext(tailwindConfig, changedContent = [], root = postcss.root()) {
|
|
819
1155
|
let context = {
|
|
820
1156
|
disposables: [],
|
|
821
1157
|
ruleCache: new Set(),
|
|
1158
|
+
candidateRuleCache: new Map(),
|
|
822
1159
|
classCache: new Map(),
|
|
823
1160
|
applyClassCache: new Map(),
|
|
824
|
-
|
|
1161
|
+
// Seed the not class cache with the blocklist (which is only strings)
|
|
1162
|
+
notClassCache: new Set(tailwindConfig.blocklist ?? []),
|
|
825
1163
|
postCssNodeCache: new Map(),
|
|
826
1164
|
candidateRuleMap: new Map(),
|
|
827
1165
|
tailwindConfig,
|
|
828
1166
|
changedContent: changedContent,
|
|
829
1167
|
variantMap: new Map(),
|
|
830
1168
|
stylesheetCache: null,
|
|
1169
|
+
variantOptions: new Map(),
|
|
1170
|
+
|
|
1171
|
+
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
|
|
1172
|
+
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
|
|
831
1173
|
}
|
|
832
1174
|
|
|
833
1175
|
let resolvedPlugins = resolvePlugins(context, root)
|
|
@@ -865,6 +1207,8 @@ export function getContext(
|
|
|
865
1207
|
existingContext = context
|
|
866
1208
|
}
|
|
867
1209
|
|
|
1210
|
+
let cssDidChange = hasContentChanged(sourcePath, root)
|
|
1211
|
+
|
|
868
1212
|
// If there's already a context in the cache and we don't need to
|
|
869
1213
|
// reset the context, return the cached context.
|
|
870
1214
|
if (existingContext) {
|
|
@@ -872,7 +1216,7 @@ export function getContext(
|
|
|
872
1216
|
[...contextDependencies],
|
|
873
1217
|
getFileModifiedMap(existingContext)
|
|
874
1218
|
)
|
|
875
|
-
if (!contextDependenciesChanged) {
|
|
1219
|
+
if (!contextDependenciesChanged && !cssDidChange) {
|
|
876
1220
|
return [existingContext, false]
|
|
877
1221
|
}
|
|
878
1222
|
}
|
|
@@ -904,6 +1248,10 @@ export function getContext(
|
|
|
904
1248
|
|
|
905
1249
|
let context = createContext(tailwindConfig, [], root)
|
|
906
1250
|
|
|
1251
|
+
Object.assign(context, {
|
|
1252
|
+
userConfigPath,
|
|
1253
|
+
})
|
|
1254
|
+
|
|
907
1255
|
trackModified([...contextDependencies], getFileModifiedMap(context))
|
|
908
1256
|
|
|
909
1257
|
// ---
|