tailwindcss 0.0.0-insiders.ea80db2 → 0.0.0-insiders.eae2b7a
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/README.md +13 -9
- package/defaultTheme.d.ts +2 -1
- package/index.css +5 -0
- package/lib/cli/build/index.js +57 -0
- package/lib/cli/build/plugin.js +427 -0
- package/lib/cli/build/utils.js +88 -0
- package/lib/cli/build/watching.js +182 -0
- package/lib/cli/help/index.js +73 -0
- package/lib/cli/index.js +231 -0
- package/lib/cli/init/index.js +63 -0
- package/lib/cli.js +1 -759
- package/lib/corePluginList.js +12 -3
- package/lib/corePlugins.js +2308 -1739
- package/lib/css/preflight.css +13 -5
- package/lib/featureFlags.js +50 -25
- package/lib/index.js +1 -40
- package/lib/lib/cacheInvalidation.js +48 -25
- package/lib/lib/collapseAdjacentRules.js +17 -10
- package/lib/lib/collapseDuplicateDeclarations.js +13 -8
- package/lib/lib/content.js +207 -0
- package/lib/lib/defaultExtractor.js +232 -33
- package/lib/lib/detectNesting.js +21 -10
- package/lib/lib/evaluateTailwindFunctions.js +117 -50
- package/lib/lib/expandApplyAtRules.js +316 -215
- package/lib/lib/expandTailwindAtRules.js +167 -115
- package/lib/lib/findAtConfigPath.js +46 -0
- package/lib/lib/generateRules.js +444 -211
- package/lib/lib/getModuleDependencies.js +88 -37
- package/lib/lib/handleImportAtRules.js +50 -0
- package/lib/lib/load-config.js +42 -0
- package/lib/lib/normalizeTailwindDirectives.js +29 -39
- package/lib/lib/offsets.js +306 -0
- package/lib/lib/partitionApplyAtRules.js +13 -8
- package/lib/lib/regex.js +74 -0
- package/lib/lib/remap-bitfield.js +89 -0
- package/lib/lib/resolveDefaultsAtRules.js +96 -74
- package/lib/lib/setupContextUtils.js +672 -300
- package/lib/lib/setupTrackingContext.js +63 -68
- package/lib/lib/sharedState.js +44 -17
- package/lib/lib/substituteScreenAtRules.js +14 -10
- package/lib/plugin.js +160 -0
- package/lib/postcss-plugins/nesting/README.md +2 -2
- package/lib/postcss-plugins/nesting/index.js +10 -6
- package/lib/postcss-plugins/nesting/plugin.js +24 -20
- package/lib/processTailwindFeatures.js +34 -29
- package/lib/public/colors.js +272 -246
- package/lib/public/create-plugin.js +9 -5
- package/lib/public/default-config.js +10 -6
- package/lib/public/default-theme.js +10 -6
- package/lib/public/load-config.js +12 -0
- package/lib/public/resolve-config.js +11 -6
- package/lib/util/applyImportantSelector.js +36 -0
- package/lib/util/bigSign.js +6 -1
- package/lib/util/buildMediaQuery.js +13 -6
- package/lib/util/cloneDeep.js +9 -6
- package/lib/util/cloneNodes.js +12 -3
- package/lib/util/color.js +66 -50
- package/lib/util/colorNames.js +752 -0
- package/lib/util/configurePlugins.js +7 -2
- package/lib/util/createPlugin.js +8 -5
- package/lib/util/createUtilityPlugin.js +13 -9
- package/lib/util/dataTypes.js +182 -111
- package/lib/util/defaults.js +12 -7
- package/lib/util/escapeClassName.js +13 -8
- package/lib/util/escapeCommas.js +7 -2
- package/lib/util/flattenColorPalette.js +11 -10
- package/lib/util/formatVariantSelector.js +228 -151
- package/lib/util/getAllConfigs.js +33 -12
- package/lib/util/hashConfig.js +9 -4
- package/lib/util/isKeyframeRule.js +7 -2
- package/lib/util/isPlainObject.js +7 -2
- package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +25 -15
- package/lib/util/log.js +40 -13
- package/lib/util/nameClass.js +27 -10
- package/lib/util/negateValue.js +25 -8
- package/lib/util/normalizeConfig.js +155 -87
- package/lib/util/normalizeScreens.js +127 -8
- package/lib/util/parseAnimationValue.js +44 -40
- package/lib/util/parseBoxShadowValue.js +33 -62
- package/lib/util/parseDependency.js +39 -55
- package/lib/util/parseGlob.js +36 -0
- package/lib/util/parseObjectStyles.js +15 -10
- package/lib/util/pluginUtils.js +154 -59
- package/lib/util/prefixSelector.js +29 -10
- package/lib/util/pseudoElements.js +209 -0
- package/lib/util/removeAlphaVariables.js +31 -0
- package/lib/util/resolveConfig.js +96 -95
- package/lib/util/resolveConfigPath.js +29 -10
- package/lib/util/responsive.js +11 -6
- package/lib/util/splitAtTopLevelOnly.js +51 -0
- package/lib/util/tap.js +6 -1
- package/lib/util/toColorValue.js +7 -2
- package/lib/util/toPath.js +22 -4
- package/lib/util/transformThemeValue.js +40 -26
- package/lib/util/validateConfig.js +48 -0
- package/lib/util/validateFormalSyntax.js +26 -0
- package/lib/util/withAlphaVariable.js +27 -15
- package/lib/value-parser/LICENSE +22 -0
- package/lib/value-parser/README.md +3 -0
- package/lib/value-parser/index.d.js +2 -0
- package/lib/value-parser/index.js +22 -0
- package/lib/value-parser/parse.js +259 -0
- package/lib/value-parser/stringify.js +38 -0
- package/lib/value-parser/unit.js +86 -0
- package/lib/value-parser/walk.js +16 -0
- package/loadConfig.d.ts +4 -0
- package/loadConfig.js +2 -0
- package/package.json +54 -52
- package/plugin.d.ts +10 -5
- package/resolveConfig.d.ts +12 -0
- package/scripts/generate-types.js +53 -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/index.js +53 -0
- package/src/cli/build/plugin.js +465 -0
- package/src/cli/build/utils.js +76 -0
- package/src/cli/build/watching.js +229 -0
- package/src/cli/help/index.js +70 -0
- package/src/cli/index.js +217 -0
- package/src/cli/init/index.js +79 -0
- package/src/cli.js +1 -836
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +576 -106
- package/src/css/preflight.css +13 -5
- package/src/featureFlags.js +17 -3
- package/src/index.js +1 -42
- package/src/lib/collapseAdjacentRules.js +5 -1
- package/src/lib/content.js +240 -0
- package/src/lib/defaultExtractor.js +202 -35
- package/src/lib/detectNesting.js +9 -1
- package/src/lib/evaluateTailwindFunctions.js +82 -8
- package/src/lib/expandApplyAtRules.js +322 -189
- package/src/lib/expandTailwindAtRules.js +82 -59
- package/src/lib/findAtConfigPath.js +48 -0
- package/src/lib/generateRules.js +413 -132
- package/src/lib/getModuleDependencies.js +70 -30
- package/src/lib/handleImportAtRules.js +34 -0
- package/src/lib/load-config.ts +31 -0
- package/src/lib/normalizeTailwindDirectives.js +0 -27
- package/src/lib/offsets.js +373 -0
- package/src/lib/regex.js +74 -0
- package/src/lib/remap-bitfield.js +82 -0
- package/src/lib/resolveDefaultsAtRules.js +53 -36
- package/src/lib/setupContextUtils.js +570 -151
- package/src/lib/setupTrackingContext.js +44 -58
- package/src/lib/sharedState.js +13 -4
- package/src/plugin.js +128 -0
- package/src/postcss-plugins/nesting/README.md +2 -2
- package/src/public/colors.js +22 -0
- package/src/public/default-config.js +1 -1
- package/src/public/default-theme.js +2 -2
- package/src/public/load-config.js +2 -0
- package/src/util/applyImportantSelector.js +27 -0
- package/src/util/buildMediaQuery.js +5 -3
- package/src/util/cloneNodes.js +5 -1
- package/src/util/color.js +34 -17
- package/src/util/colorNames.js +150 -0
- package/src/util/dataTypes.js +67 -23
- package/src/util/formatVariantSelector.js +264 -144
- package/src/util/getAllConfigs.js +21 -2
- package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
- package/src/util/log.js +25 -1
- package/src/util/nameClass.js +4 -0
- package/src/util/negateValue.js +11 -3
- package/src/util/normalizeConfig.js +78 -20
- package/src/util/normalizeScreens.js +99 -4
- package/src/util/parseBoxShadowValue.js +3 -50
- package/src/util/parseDependency.js +37 -42
- package/src/util/parseGlob.js +24 -0
- package/src/util/pluginUtils.js +118 -23
- package/src/util/prefixSelector.js +28 -10
- package/src/util/pseudoElements.js +167 -0
- package/src/util/removeAlphaVariables.js +24 -0
- package/src/util/resolveConfig.js +70 -62
- package/src/util/resolveConfigPath.js +12 -1
- package/src/util/splitAtTopLevelOnly.js +52 -0
- package/src/util/toPath.js +1 -1
- package/src/util/transformThemeValue.js +13 -3
- package/src/util/validateConfig.js +36 -0
- package/src/util/validateFormalSyntax.js +34 -0
- package/src/util/withAlphaVariable.js +1 -1
- package/src/value-parser/LICENSE +22 -0
- package/src/value-parser/README.md +3 -0
- package/src/value-parser/index.d.ts +177 -0
- package/src/value-parser/index.js +28 -0
- package/src/value-parser/parse.js +303 -0
- package/src/value-parser/stringify.js +41 -0
- package/src/value-parser/unit.js +118 -0
- package/src/value-parser/walk.js +18 -0
- package/stubs/.gitignore +1 -0
- package/stubs/.prettierrc.json +6 -0
- package/stubs/{defaultConfig.stub.js → config.full.js} +215 -165
- package/stubs/{simpleConfig.stub.js → config.simple.js} +1 -1
- package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -1
- package/stubs/postcss.config.js +5 -0
- package/stubs/tailwind.config.cjs +2 -0
- package/stubs/tailwind.config.js +2 -0
- package/stubs/tailwind.config.ts +3 -0
- package/types/config.d.ts +102 -56
- package/types/generated/colors.d.ts +22 -0
- package/types/generated/corePluginList.d.ts +1 -1
- package/types/generated/default-theme.d.ts +372 -0
- package/types/index.d.ts +7 -1
- package/CHANGELOG.md +0 -2099
- package/lib/cli-peer-dependencies.js +0 -15
- package/lib/constants.js +0 -37
- package/peers/index.js +0 -75156
- package/scripts/install-integrations.js +0 -27
- package/scripts/rebuildFixtures.js +0 -68
- package/src/cli-peer-dependencies.js +0 -9
- package/src/constants.js +0 -17
- package/types.d.ts +0 -1
|
@@ -11,49 +11,92 @@ 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
|
-
import { generateRules } from './generateRules'
|
|
20
|
+
import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPropertyValue'
|
|
21
|
+
import { generateRules, getClassNameFromSelector } from './generateRules'
|
|
23
22
|
import { hasContentChanged } from './cacheInvalidation.js'
|
|
23
|
+
import { Offsets } from './offsets.js'
|
|
24
|
+
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
|
|
25
|
+
|
|
26
|
+
const VARIANT_TYPES = {
|
|
27
|
+
AddVariant: Symbol.for('ADD_VARIANT'),
|
|
28
|
+
MatchVariant: Symbol.for('MATCH_VARIANT'),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const VARIANT_INFO = {
|
|
32
|
+
Base: 1 << 0,
|
|
33
|
+
Dynamic: 1 << 1,
|
|
34
|
+
}
|
|
24
35
|
|
|
25
36
|
function prefix(context, selector) {
|
|
26
37
|
let prefix = context.tailwindConfig.prefix
|
|
27
38
|
return typeof prefix === 'function' ? prefix(selector) : prefix + selector
|
|
28
39
|
}
|
|
29
40
|
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`)
|
|
41
|
+
function normalizeOptionTypes({ type = 'any', ...options }) {
|
|
42
|
+
let types = [].concat(type)
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.
|
|
44
|
+
return {
|
|
45
|
+
...options,
|
|
46
|
+
types: types.map((type) => {
|
|
47
|
+
if (Array.isArray(type)) {
|
|
48
|
+
return { type: type[0], ...type[1] }
|
|
49
|
+
}
|
|
50
|
+
return { type, preferOnConflict: false }
|
|
51
|
+
}),
|
|
38
52
|
}
|
|
39
|
-
|
|
40
|
-
return [input.trim()]
|
|
41
53
|
}
|
|
42
54
|
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
function parseVariantFormatString(input) {
|
|
56
|
+
/** @type {string[]} */
|
|
57
|
+
let parts = []
|
|
58
|
+
|
|
59
|
+
// When parsing whitespace around special characters are insignificant
|
|
60
|
+
// However, _inside_ of a variant they could be
|
|
61
|
+
// Because the selector could look like this
|
|
62
|
+
// @media { &[data-name="foo bar"] }
|
|
63
|
+
// This is why we do not skip whitespace
|
|
64
|
+
|
|
65
|
+
let current = ''
|
|
66
|
+
let depth = 0
|
|
67
|
+
|
|
68
|
+
for (let idx = 0; idx < input.length; idx++) {
|
|
69
|
+
let char = input[idx]
|
|
70
|
+
|
|
71
|
+
if (char === '\\') {
|
|
72
|
+
// Escaped characters are not special
|
|
73
|
+
current += '\\' + input[++idx]
|
|
74
|
+
} else if (char === '{') {
|
|
75
|
+
// Nested rule: start
|
|
76
|
+
++depth
|
|
77
|
+
parts.push(current.trim())
|
|
78
|
+
current = ''
|
|
49
79
|
} else if (char === '}') {
|
|
50
|
-
|
|
51
|
-
|
|
80
|
+
// Nested rule: end
|
|
81
|
+
if (--depth < 0) {
|
|
82
|
+
throw new Error(`Your { and } are unbalanced.`)
|
|
52
83
|
}
|
|
84
|
+
|
|
85
|
+
parts.push(current.trim())
|
|
86
|
+
current = ''
|
|
87
|
+
} else {
|
|
88
|
+
// Normal character
|
|
89
|
+
current += char
|
|
53
90
|
}
|
|
54
91
|
}
|
|
55
92
|
|
|
56
|
-
|
|
93
|
+
if (current.length > 0) {
|
|
94
|
+
parts.push(current.trim())
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
parts = parts.filter((part) => part !== '')
|
|
98
|
+
|
|
99
|
+
return parts
|
|
57
100
|
}
|
|
58
101
|
|
|
59
102
|
function insertInto(list, value, { before = [] } = {}) {
|
|
@@ -170,6 +213,41 @@ function withIdentifiers(styles) {
|
|
|
170
213
|
})
|
|
171
214
|
}
|
|
172
215
|
|
|
216
|
+
export function isValidVariantFormatString(format) {
|
|
217
|
+
return format.startsWith('@') || format.includes('&')
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function parseVariant(variant) {
|
|
221
|
+
variant = variant
|
|
222
|
+
.replace(/\n+/g, '')
|
|
223
|
+
.replace(/\s{1,}/g, ' ')
|
|
224
|
+
.trim()
|
|
225
|
+
|
|
226
|
+
let fns = parseVariantFormatString(variant)
|
|
227
|
+
.map((str) => {
|
|
228
|
+
if (!str.startsWith('@')) {
|
|
229
|
+
return ({ format }) => format(str)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(str)
|
|
233
|
+
return ({ wrap }) => wrap(postcss.atRule({ name, params: params.trim() }))
|
|
234
|
+
})
|
|
235
|
+
.reverse()
|
|
236
|
+
|
|
237
|
+
return (api) => {
|
|
238
|
+
for (let fn of fns) {
|
|
239
|
+
fn(api)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
*
|
|
246
|
+
* @param {any} tailwindConfig
|
|
247
|
+
* @param {any} context
|
|
248
|
+
* @param {object} param2
|
|
249
|
+
* @param {Offsets} param2.offsets
|
|
250
|
+
*/
|
|
173
251
|
function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
|
|
174
252
|
function getConfigValue(path, defaultValue) {
|
|
175
253
|
return path ? dlv(tailwindConfig, path, defaultValue) : tailwindConfig
|
|
@@ -191,51 +269,19 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
191
269
|
return context.tailwindConfig.prefix + identifier
|
|
192
270
|
}
|
|
193
271
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return ({ modifySelectors, container, separator }) => {
|
|
200
|
-
return variantFunction({ modifySelectors, container, separator })
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
variantFunction = variantFunction
|
|
205
|
-
.replace(/\n+/g, '')
|
|
206
|
-
.replace(/\s{1,}/g, ' ')
|
|
207
|
-
.trim()
|
|
208
|
-
|
|
209
|
-
let fns = parseVariantFormatString(variantFunction)
|
|
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 }))
|
|
217
|
-
})
|
|
218
|
-
.reverse()
|
|
219
|
-
|
|
220
|
-
return (api) => {
|
|
221
|
-
for (let fn of fns) {
|
|
222
|
-
fn(api)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
})
|
|
272
|
+
function resolveThemeValue(path, defaultValue, opts = {}) {
|
|
273
|
+
let parts = toPath(path)
|
|
274
|
+
let value = getConfigValue(['theme', ...parts], defaultValue)
|
|
275
|
+
return transformThemeValue(parts[0])(value, opts)
|
|
276
|
+
}
|
|
226
277
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
},
|
|
278
|
+
let variantIdentifier = 0
|
|
279
|
+
let api = {
|
|
230
280
|
postcss,
|
|
231
281
|
prefix: applyConfiguredPrefix,
|
|
232
282
|
e: escapeClassName,
|
|
233
283
|
config: getConfigValue,
|
|
234
|
-
theme
|
|
235
|
-
const [pathRoot, ...subPaths] = toPath(path)
|
|
236
|
-
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
|
237
|
-
return transformThemeValue(pathRoot)(value)
|
|
238
|
-
},
|
|
284
|
+
theme: resolveThemeValue,
|
|
239
285
|
corePlugins: (path) => {
|
|
240
286
|
if (Array.isArray(tailwindConfig.corePlugins)) {
|
|
241
287
|
return tailwindConfig.corePlugins.includes(path)
|
|
@@ -250,7 +296,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
250
296
|
addBase(base) {
|
|
251
297
|
for (let [identifier, rule] of withIdentifiers(base)) {
|
|
252
298
|
let prefixedIdentifier = prefixIdentifier(identifier, {})
|
|
253
|
-
let offset = offsets.base
|
|
299
|
+
let offset = offsets.create('base')
|
|
254
300
|
|
|
255
301
|
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
256
302
|
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
@@ -279,11 +325,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
279
325
|
|
|
280
326
|
context.candidateRuleMap
|
|
281
327
|
.get(prefixedIdentifier)
|
|
282
|
-
.push([{ sort: offsets.
|
|
328
|
+
.push([{ sort: offsets.create('defaults'), layer: 'defaults' }, rule])
|
|
283
329
|
}
|
|
284
330
|
},
|
|
285
331
|
addComponents(components, options) {
|
|
286
332
|
let defaultOptions = {
|
|
333
|
+
preserveSource: false,
|
|
287
334
|
respectPrefix: true,
|
|
288
335
|
respectImportant: false,
|
|
289
336
|
}
|
|
@@ -301,11 +348,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
301
348
|
|
|
302
349
|
context.candidateRuleMap
|
|
303
350
|
.get(prefixedIdentifier)
|
|
304
|
-
.push([{ sort: offsets.components
|
|
351
|
+
.push([{ sort: offsets.create('components'), layer: 'components', options }, rule])
|
|
305
352
|
}
|
|
306
353
|
},
|
|
307
354
|
addUtilities(utilities, options) {
|
|
308
355
|
let defaultOptions = {
|
|
356
|
+
preserveSource: false,
|
|
309
357
|
respectPrefix: true,
|
|
310
358
|
respectImportant: true,
|
|
311
359
|
}
|
|
@@ -323,18 +371,19 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
323
371
|
|
|
324
372
|
context.candidateRuleMap
|
|
325
373
|
.get(prefixedIdentifier)
|
|
326
|
-
.push([{ sort: offsets.utilities
|
|
374
|
+
.push([{ sort: offsets.create('utilities'), layer: 'utilities', options }, rule])
|
|
327
375
|
}
|
|
328
376
|
},
|
|
329
377
|
matchUtilities: function (utilities, options) {
|
|
330
378
|
let defaultOptions = {
|
|
331
379
|
respectPrefix: true,
|
|
332
380
|
respectImportant: true,
|
|
381
|
+
modifiers: false,
|
|
333
382
|
}
|
|
334
383
|
|
|
335
|
-
options = { ...defaultOptions, ...options }
|
|
384
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
336
385
|
|
|
337
|
-
let offset = offsets.utilities
|
|
386
|
+
let offset = offsets.create('utilities')
|
|
338
387
|
|
|
339
388
|
for (let identifier in utilities) {
|
|
340
389
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
@@ -343,24 +392,49 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
343
392
|
classList.add([prefixedIdentifier, options])
|
|
344
393
|
|
|
345
394
|
function wrapped(modifier, { isOnlyPlugin }) {
|
|
346
|
-
let
|
|
347
|
-
|
|
348
|
-
|
|
395
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
396
|
+
options.types,
|
|
397
|
+
modifier,
|
|
398
|
+
options,
|
|
399
|
+
tailwindConfig
|
|
400
|
+
)
|
|
349
401
|
|
|
350
402
|
if (value === undefined) {
|
|
351
403
|
return []
|
|
352
404
|
}
|
|
353
405
|
|
|
354
|
-
if (!
|
|
355
|
-
|
|
406
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
407
|
+
if (isOnlyPlugin) {
|
|
408
|
+
log.warn([
|
|
409
|
+
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
410
|
+
`You can safely update it to \`${identifier}-${modifier.replace(
|
|
411
|
+
coercedType + ':',
|
|
412
|
+
''
|
|
413
|
+
)}\`.`,
|
|
414
|
+
])
|
|
415
|
+
} else {
|
|
416
|
+
return []
|
|
417
|
+
}
|
|
356
418
|
}
|
|
357
419
|
|
|
358
|
-
if (!
|
|
420
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
359
421
|
return []
|
|
360
422
|
}
|
|
361
423
|
|
|
424
|
+
let extras = {
|
|
425
|
+
get modifier() {
|
|
426
|
+
if (!options.modifiers) {
|
|
427
|
+
log.warn(`modifier-used-without-options-for-${identifier}`, [
|
|
428
|
+
'Your plugin must set `modifiers: true` in its options to support modifiers.',
|
|
429
|
+
])
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return utilityModifier
|
|
433
|
+
},
|
|
434
|
+
}
|
|
435
|
+
|
|
362
436
|
let ruleSets = []
|
|
363
|
-
.concat(rule(value))
|
|
437
|
+
.concat(rule(value, extras))
|
|
364
438
|
.filter(Boolean)
|
|
365
439
|
.map((declaration) => ({
|
|
366
440
|
[nameClass(identifier, modifier)]: declaration,
|
|
@@ -382,11 +456,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
382
456
|
let defaultOptions = {
|
|
383
457
|
respectPrefix: true,
|
|
384
458
|
respectImportant: false,
|
|
459
|
+
modifiers: false,
|
|
385
460
|
}
|
|
386
461
|
|
|
387
|
-
options = { ...defaultOptions, ...options }
|
|
462
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
388
463
|
|
|
389
|
-
let offset = offsets.components
|
|
464
|
+
let offset = offsets.create('components')
|
|
390
465
|
|
|
391
466
|
for (let identifier in components) {
|
|
392
467
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
@@ -395,15 +470,18 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
395
470
|
classList.add([prefixedIdentifier, options])
|
|
396
471
|
|
|
397
472
|
function wrapped(modifier, { isOnlyPlugin }) {
|
|
398
|
-
let
|
|
399
|
-
|
|
400
|
-
|
|
473
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
474
|
+
options.types,
|
|
475
|
+
modifier,
|
|
476
|
+
options,
|
|
477
|
+
tailwindConfig
|
|
478
|
+
)
|
|
401
479
|
|
|
402
480
|
if (value === undefined) {
|
|
403
481
|
return []
|
|
404
482
|
}
|
|
405
483
|
|
|
406
|
-
if (!
|
|
484
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
407
485
|
if (isOnlyPlugin) {
|
|
408
486
|
log.warn([
|
|
409
487
|
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
@@ -417,12 +495,24 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
417
495
|
}
|
|
418
496
|
}
|
|
419
497
|
|
|
420
|
-
if (!
|
|
498
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
421
499
|
return []
|
|
422
500
|
}
|
|
423
501
|
|
|
502
|
+
let extras = {
|
|
503
|
+
get modifier() {
|
|
504
|
+
if (!options.modifiers) {
|
|
505
|
+
log.warn(`modifier-used-without-options-for-${identifier}`, [
|
|
506
|
+
'Your plugin must set `modifiers: true` in its options to support modifiers.',
|
|
507
|
+
])
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return utilityModifier
|
|
511
|
+
},
|
|
512
|
+
}
|
|
513
|
+
|
|
424
514
|
let ruleSets = []
|
|
425
|
-
.concat(rule(value))
|
|
515
|
+
.concat(rule(value, extras))
|
|
426
516
|
.filter(Boolean)
|
|
427
517
|
.map((declaration) => ({
|
|
428
518
|
[nameClass(identifier, modifier)]: declaration,
|
|
@@ -440,7 +530,104 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
440
530
|
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
|
|
441
531
|
}
|
|
442
532
|
},
|
|
533
|
+
addVariant(variantName, variantFunctions, options = {}) {
|
|
534
|
+
variantFunctions = [].concat(variantFunctions).map((variantFunction) => {
|
|
535
|
+
if (typeof variantFunction !== 'string') {
|
|
536
|
+
// Safelist public API functions
|
|
537
|
+
return (api = {}) => {
|
|
538
|
+
let { args, modifySelectors, container, separator, wrap, format } = api
|
|
539
|
+
let result = variantFunction(
|
|
540
|
+
Object.assign(
|
|
541
|
+
{ modifySelectors, container, separator },
|
|
542
|
+
options.type === VARIANT_TYPES.MatchVariant && { args, wrap, format }
|
|
543
|
+
)
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
if (typeof result === 'string' && !isValidVariantFormatString(result)) {
|
|
547
|
+
throw new Error(
|
|
548
|
+
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
|
|
549
|
+
)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (Array.isArray(result)) {
|
|
553
|
+
return result
|
|
554
|
+
.filter((variant) => typeof variant === 'string')
|
|
555
|
+
.map((variant) => parseVariant(variant))
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// result may be undefined with legacy variants that use APIs like `modifySelectors`
|
|
559
|
+
// result may also be a postcss node if someone was returning the result from `modifySelectors`
|
|
560
|
+
return result && typeof result === 'string' && parseVariant(result)(api)
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (!isValidVariantFormatString(variantFunction)) {
|
|
565
|
+
throw new Error(
|
|
566
|
+
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
|
|
567
|
+
)
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return parseVariant(variantFunction)
|
|
571
|
+
})
|
|
572
|
+
|
|
573
|
+
insertInto(variantList, variantName, options)
|
|
574
|
+
variantMap.set(variantName, variantFunctions)
|
|
575
|
+
context.variantOptions.set(variantName, options)
|
|
576
|
+
},
|
|
577
|
+
matchVariant(variant, variantFn, options) {
|
|
578
|
+
// A unique identifier that "groups" these variants together.
|
|
579
|
+
// This is for internal use only which is why it is not present in the types
|
|
580
|
+
let id = options?.id ?? ++variantIdentifier
|
|
581
|
+
let isSpecial = variant === '@'
|
|
582
|
+
|
|
583
|
+
for (let [key, value] of Object.entries(options?.values ?? {})) {
|
|
584
|
+
if (key === 'DEFAULT') continue
|
|
585
|
+
|
|
586
|
+
api.addVariant(
|
|
587
|
+
isSpecial ? `${variant}${key}` : `${variant}-${key}`,
|
|
588
|
+
({ args, container }) => {
|
|
589
|
+
return variantFn(value, { modifier: args?.modifier, container })
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
{
|
|
593
|
+
...options,
|
|
594
|
+
value,
|
|
595
|
+
id,
|
|
596
|
+
type: VARIANT_TYPES.MatchVariant,
|
|
597
|
+
variantInfo: VARIANT_INFO.Base,
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
let hasDefault = 'DEFAULT' in (options?.values ?? {})
|
|
603
|
+
|
|
604
|
+
api.addVariant(
|
|
605
|
+
variant,
|
|
606
|
+
({ args, container }) => {
|
|
607
|
+
if (args?.value === sharedState.NONE && !hasDefault) {
|
|
608
|
+
return null
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return variantFn(
|
|
612
|
+
args?.value === sharedState.NONE
|
|
613
|
+
? options.values.DEFAULT
|
|
614
|
+
: // Falling back to args if it is a string, otherwise '' for older intellisense
|
|
615
|
+
// (JetBrains) plugins.
|
|
616
|
+
args?.value ?? (typeof args === 'string' ? args : ''),
|
|
617
|
+
{ modifier: args?.modifier, container }
|
|
618
|
+
)
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
...options,
|
|
622
|
+
id,
|
|
623
|
+
type: VARIANT_TYPES.MatchVariant,
|
|
624
|
+
variantInfo: VARIANT_INFO.Dynamic,
|
|
625
|
+
}
|
|
626
|
+
)
|
|
627
|
+
},
|
|
443
628
|
}
|
|
629
|
+
|
|
630
|
+
return api
|
|
444
631
|
}
|
|
445
632
|
|
|
446
633
|
let fileModifiedMapCache = new WeakMap()
|
|
@@ -453,6 +640,7 @@ export function getFileModifiedMap(context) {
|
|
|
453
640
|
|
|
454
641
|
function trackModified(files, fileModifiedMap) {
|
|
455
642
|
let changed = false
|
|
643
|
+
let mtimesToCommit = new Map()
|
|
456
644
|
|
|
457
645
|
for (let file of files) {
|
|
458
646
|
if (!file) continue
|
|
@@ -473,10 +661,10 @@ function trackModified(files, fileModifiedMap) {
|
|
|
473
661
|
changed = true
|
|
474
662
|
}
|
|
475
663
|
|
|
476
|
-
|
|
664
|
+
mtimesToCommit.set(file, newModified)
|
|
477
665
|
}
|
|
478
666
|
|
|
479
|
-
return changed
|
|
667
|
+
return [changed, mtimesToCommit]
|
|
480
668
|
}
|
|
481
669
|
|
|
482
670
|
function extractVariantAtRules(node) {
|
|
@@ -513,14 +701,14 @@ function collectLayerPlugins(root) {
|
|
|
513
701
|
} else if (layerRule.params === 'components') {
|
|
514
702
|
for (let node of layerRule.nodes) {
|
|
515
703
|
layerPlugins.push(function ({ addComponents }) {
|
|
516
|
-
addComponents(node, { respectPrefix: false })
|
|
704
|
+
addComponents(node, { respectPrefix: false, preserveSource: true })
|
|
517
705
|
})
|
|
518
706
|
}
|
|
519
707
|
layerRule.remove()
|
|
520
708
|
} else if (layerRule.params === 'utilities') {
|
|
521
709
|
for (let node of layerRule.nodes) {
|
|
522
710
|
layerPlugins.push(function ({ addUtilities }) {
|
|
523
|
-
addUtilities(node, { respectPrefix: false })
|
|
711
|
+
addUtilities(node, { respectPrefix: false, preserveSource: true })
|
|
524
712
|
})
|
|
525
713
|
}
|
|
526
714
|
layerRule.remove()
|
|
@@ -531,7 +719,7 @@ function collectLayerPlugins(root) {
|
|
|
531
719
|
}
|
|
532
720
|
|
|
533
721
|
function resolvePlugins(context, root) {
|
|
534
|
-
let corePluginList = Object.entries(
|
|
722
|
+
let corePluginList = Object.entries(corePlugins)
|
|
535
723
|
.map(([name, plugin]) => {
|
|
536
724
|
if (!context.tailwindConfig.corePlugins.includes(name)) {
|
|
537
725
|
return null
|
|
@@ -556,10 +744,15 @@ function resolvePlugins(context, root) {
|
|
|
556
744
|
let beforeVariants = [
|
|
557
745
|
variantPlugins['pseudoElementVariants'],
|
|
558
746
|
variantPlugins['pseudoClassVariants'],
|
|
747
|
+
variantPlugins['hasVariants'],
|
|
748
|
+
variantPlugins['ariaVariants'],
|
|
749
|
+
variantPlugins['dataVariants'],
|
|
559
750
|
]
|
|
560
751
|
let afterVariants = [
|
|
752
|
+
variantPlugins['supportsVariants'],
|
|
561
753
|
variantPlugins['directionVariants'],
|
|
562
754
|
variantPlugins['reducedMotionVariants'],
|
|
755
|
+
variantPlugins['prefersContrastVariants'],
|
|
563
756
|
variantPlugins['darkVariants'],
|
|
564
757
|
variantPlugins['printVariant'],
|
|
565
758
|
variantPlugins['screenVariants'],
|
|
@@ -572,13 +765,10 @@ function resolvePlugins(context, root) {
|
|
|
572
765
|
function registerPlugins(plugins, context) {
|
|
573
766
|
let variantList = []
|
|
574
767
|
let variantMap = new Map()
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
utilities: 0n,
|
|
580
|
-
user: 0n,
|
|
581
|
-
}
|
|
768
|
+
context.variantMap = variantMap
|
|
769
|
+
|
|
770
|
+
let offsets = new Offsets()
|
|
771
|
+
context.offsets = offsets
|
|
582
772
|
|
|
583
773
|
let classList = new Set()
|
|
584
774
|
|
|
@@ -599,49 +789,17 @@ function registerPlugins(plugins, context) {
|
|
|
599
789
|
}
|
|
600
790
|
}
|
|
601
791
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
offsets.defaults,
|
|
605
|
-
offsets.components,
|
|
606
|
-
offsets.utilities,
|
|
607
|
-
offsets.user,
|
|
608
|
-
])
|
|
609
|
-
let reservedBits = BigInt(highestOffset.toString(2).length)
|
|
610
|
-
|
|
611
|
-
// A number one less than the top range of the highest offset area
|
|
612
|
-
// so arbitrary properties are always sorted at the end.
|
|
613
|
-
context.arbitraryPropertiesSort = ((1n << reservedBits) << 0n) - 1n
|
|
614
|
-
|
|
615
|
-
context.layerOrder = {
|
|
616
|
-
defaults: (1n << reservedBits) << 0n,
|
|
617
|
-
base: (1n << reservedBits) << 1n,
|
|
618
|
-
components: (1n << reservedBits) << 2n,
|
|
619
|
-
utilities: (1n << reservedBits) << 3n,
|
|
620
|
-
user: (1n << reservedBits) << 4n,
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
reservedBits += 5n
|
|
624
|
-
|
|
625
|
-
let offset = 0
|
|
626
|
-
context.variantOrder = new Map(
|
|
627
|
-
variantList
|
|
628
|
-
.map((variant, i) => {
|
|
629
|
-
let variantFunctions = variantMap.get(variant).length
|
|
630
|
-
let bits = (1n << BigInt(i + offset)) << reservedBits
|
|
631
|
-
offset += variantFunctions - 1
|
|
632
|
-
return [variant, bits]
|
|
633
|
-
})
|
|
634
|
-
.sort(([, a], [, z]) => bigSign(a - z))
|
|
635
|
-
)
|
|
636
|
-
|
|
637
|
-
context.minimumScreen = [...context.variantOrder.values()].shift()
|
|
792
|
+
// Make sure to record bit masks for every variant
|
|
793
|
+
offsets.recordVariants(variantList, (variant) => variantMap.get(variant).length)
|
|
638
794
|
|
|
639
795
|
// Build variantMap
|
|
640
796
|
for (let [variantName, variantFunctions] of variantMap.entries()) {
|
|
641
|
-
let sort = context.variantOrder.get(variantName)
|
|
642
797
|
context.variantMap.set(
|
|
643
798
|
variantName,
|
|
644
|
-
variantFunctions.map((variantFunction, idx) => [
|
|
799
|
+
variantFunctions.map((variantFunction, idx) => [
|
|
800
|
+
offsets.forVariant(variantName, idx),
|
|
801
|
+
variantFunction,
|
|
802
|
+
])
|
|
645
803
|
)
|
|
646
804
|
}
|
|
647
805
|
|
|
@@ -670,6 +828,7 @@ function registerPlugins(plugins, context) {
|
|
|
670
828
|
if (checks.length > 0) {
|
|
671
829
|
let patternMatchingCount = new Map()
|
|
672
830
|
let prefixLength = context.tailwindConfig.prefix.length
|
|
831
|
+
let checkImportantUtils = checks.some((check) => check.pattern.source.includes('!'))
|
|
673
832
|
|
|
674
833
|
for (let util of classList) {
|
|
675
834
|
let utils = Array.isArray(util)
|
|
@@ -695,6 +854,21 @@ function registerPlugins(plugins, context) {
|
|
|
695
854
|
]
|
|
696
855
|
}
|
|
697
856
|
|
|
857
|
+
if (options.types.some(({ type }) => type === 'color')) {
|
|
858
|
+
classes = [
|
|
859
|
+
...classes,
|
|
860
|
+
...classes.flatMap((cls) =>
|
|
861
|
+
Object.keys(context.tailwindConfig.theme.opacity).map(
|
|
862
|
+
(opacity) => `${cls}/${opacity}`
|
|
863
|
+
)
|
|
864
|
+
),
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (checkImportantUtils && options?.respectImportant) {
|
|
869
|
+
classes = [...classes, ...classes.map((cls) => '!' + cls)]
|
|
870
|
+
}
|
|
871
|
+
|
|
698
872
|
return classes
|
|
699
873
|
})()
|
|
700
874
|
: [util]
|
|
@@ -736,26 +910,48 @@ function registerPlugins(plugins, context) {
|
|
|
736
910
|
}
|
|
737
911
|
}
|
|
738
912
|
|
|
913
|
+
let darkClassName = [].concat(context.tailwindConfig.darkMode ?? 'media')[1] ?? 'dark'
|
|
914
|
+
|
|
739
915
|
// A list of utilities that are used by certain Tailwind CSS utilities but
|
|
740
916
|
// that don't exist on their own. This will result in them "not existing" and
|
|
741
917
|
// sorting could be weird since you still require them in order to make the
|
|
742
|
-
// host
|
|
743
|
-
let parasiteUtilities =
|
|
918
|
+
// host utilities work properly. (Thanks Biology)
|
|
919
|
+
let parasiteUtilities = [
|
|
920
|
+
prefix(context, darkClassName),
|
|
921
|
+
prefix(context, 'group'),
|
|
922
|
+
prefix(context, 'peer'),
|
|
923
|
+
]
|
|
744
924
|
context.getClassOrder = function getClassOrder(classes) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
if (
|
|
748
|
-
|
|
925
|
+
// Sort classes so they're ordered in a deterministic manner
|
|
926
|
+
let sorted = [...classes].sort((a, z) => {
|
|
927
|
+
if (a === z) return 0
|
|
928
|
+
if (a < z) return -1
|
|
929
|
+
return 1
|
|
930
|
+
})
|
|
931
|
+
|
|
932
|
+
// Non-util classes won't be generated, so we default them to null
|
|
933
|
+
let sortedClassNames = new Map(sorted.map((className) => [className, null]))
|
|
934
|
+
|
|
935
|
+
// Sort all classes in order
|
|
936
|
+
// Non-tailwind classes won't be generated and will be left as `null`
|
|
937
|
+
let rules = generateRules(new Set(sorted), context)
|
|
938
|
+
rules = context.offsets.sort(rules)
|
|
939
|
+
|
|
940
|
+
let idx = BigInt(parasiteUtilities.length)
|
|
941
|
+
|
|
942
|
+
for (const [, rule] of rules) {
|
|
943
|
+
sortedClassNames.set(rule.raws.tailwind.candidate, idx++)
|
|
749
944
|
}
|
|
750
945
|
|
|
751
946
|
return classes.map((className) => {
|
|
752
947
|
let order = sortedClassNames.get(className) ?? null
|
|
948
|
+
let parasiteIndex = parasiteUtilities.indexOf(className)
|
|
753
949
|
|
|
754
|
-
if (order === null &&
|
|
950
|
+
if (order === null && parasiteIndex !== -1) {
|
|
755
951
|
// This will make sure that it is at the very beginning of the
|
|
756
952
|
// `components` layer which technically means 'before any
|
|
757
953
|
// components'.
|
|
758
|
-
order =
|
|
954
|
+
order = BigInt(parasiteIndex)
|
|
759
955
|
}
|
|
760
956
|
|
|
761
957
|
return [className, order]
|
|
@@ -764,18 +960,35 @@ function registerPlugins(plugins, context) {
|
|
|
764
960
|
|
|
765
961
|
// Generate a list of strings for autocompletion purposes, e.g.
|
|
766
962
|
// ['uppercase', 'lowercase', ...]
|
|
767
|
-
context.getClassList = function getClassList() {
|
|
963
|
+
context.getClassList = function getClassList(options = {}) {
|
|
768
964
|
let output = []
|
|
769
965
|
|
|
770
966
|
for (let util of classList) {
|
|
771
967
|
if (Array.isArray(util)) {
|
|
772
|
-
let [utilName,
|
|
968
|
+
let [utilName, utilOptions] = util
|
|
773
969
|
let negativeClasses = []
|
|
774
970
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
971
|
+
let modifiers = Object.keys(utilOptions?.modifiers ?? {})
|
|
972
|
+
|
|
973
|
+
if (utilOptions?.types?.some(({ type }) => type === 'color')) {
|
|
974
|
+
modifiers.push(...Object.keys(context.tailwindConfig.theme.opacity ?? {}))
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
let metadata = { modifiers }
|
|
978
|
+
let includeMetadata = options.includeMetadata && modifiers.length > 0
|
|
979
|
+
|
|
980
|
+
for (let [key, value] of Object.entries(utilOptions?.values ?? {})) {
|
|
981
|
+
// Ignore undefined and null values
|
|
982
|
+
if (value == null) {
|
|
983
|
+
continue
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
let cls = formatClass(utilName, key)
|
|
987
|
+
output.push(includeMetadata ? [cls, metadata] : cls)
|
|
988
|
+
|
|
989
|
+
if (utilOptions?.supportsNegativeValues && negateValue(value)) {
|
|
990
|
+
let cls = formatClass(utilName, `-${key}`)
|
|
991
|
+
negativeClasses.push(includeMetadata ? [cls, metadata] : cls)
|
|
779
992
|
}
|
|
780
993
|
}
|
|
781
994
|
|
|
@@ -787,21 +1000,223 @@ function registerPlugins(plugins, context) {
|
|
|
787
1000
|
|
|
788
1001
|
return output
|
|
789
1002
|
}
|
|
1003
|
+
|
|
1004
|
+
// Generate a list of available variants with meta information of the type of variant.
|
|
1005
|
+
context.getVariants = function getVariants() {
|
|
1006
|
+
let result = []
|
|
1007
|
+
for (let [name, options] of context.variantOptions.entries()) {
|
|
1008
|
+
if (options.variantInfo === VARIANT_INFO.Base) continue
|
|
1009
|
+
|
|
1010
|
+
result.push({
|
|
1011
|
+
name,
|
|
1012
|
+
isArbitrary: options.type === Symbol.for('MATCH_VARIANT'),
|
|
1013
|
+
values: Object.keys(options.values ?? {}),
|
|
1014
|
+
hasDash: name !== '@',
|
|
1015
|
+
selectors({ modifier, value } = {}) {
|
|
1016
|
+
let candidate = '__TAILWIND_PLACEHOLDER__'
|
|
1017
|
+
|
|
1018
|
+
let rule = postcss.rule({ selector: `.${candidate}` })
|
|
1019
|
+
let container = postcss.root({ nodes: [rule.clone()] })
|
|
1020
|
+
|
|
1021
|
+
let before = container.toString()
|
|
1022
|
+
|
|
1023
|
+
let fns = (context.variantMap.get(name) ?? []).flatMap(([_, fn]) => fn)
|
|
1024
|
+
let formatStrings = []
|
|
1025
|
+
for (let fn of fns) {
|
|
1026
|
+
let localFormatStrings = []
|
|
1027
|
+
|
|
1028
|
+
let api = {
|
|
1029
|
+
args: { modifier, value: options.values?.[value] ?? value },
|
|
1030
|
+
separator: context.tailwindConfig.separator,
|
|
1031
|
+
modifySelectors(modifierFunction) {
|
|
1032
|
+
// Run the modifierFunction over each rule
|
|
1033
|
+
container.each((rule) => {
|
|
1034
|
+
if (rule.type !== 'rule') {
|
|
1035
|
+
return
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
rule.selectors = rule.selectors.map((selector) => {
|
|
1039
|
+
return modifierFunction({
|
|
1040
|
+
get className() {
|
|
1041
|
+
return getClassNameFromSelector(selector)
|
|
1042
|
+
},
|
|
1043
|
+
selector,
|
|
1044
|
+
})
|
|
1045
|
+
})
|
|
1046
|
+
})
|
|
1047
|
+
|
|
1048
|
+
return container
|
|
1049
|
+
},
|
|
1050
|
+
format(str) {
|
|
1051
|
+
localFormatStrings.push(str)
|
|
1052
|
+
},
|
|
1053
|
+
wrap(wrapper) {
|
|
1054
|
+
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`)
|
|
1055
|
+
},
|
|
1056
|
+
container,
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
let ruleWithVariant = fn(api)
|
|
1060
|
+
if (localFormatStrings.length > 0) {
|
|
1061
|
+
formatStrings.push(localFormatStrings)
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (Array.isArray(ruleWithVariant)) {
|
|
1065
|
+
for (let variantFunction of ruleWithVariant) {
|
|
1066
|
+
localFormatStrings = []
|
|
1067
|
+
variantFunction(api)
|
|
1068
|
+
formatStrings.push(localFormatStrings)
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// Reverse engineer the result of the `container`
|
|
1074
|
+
let manualFormatStrings = []
|
|
1075
|
+
let after = container.toString()
|
|
1076
|
+
|
|
1077
|
+
if (before !== after) {
|
|
1078
|
+
// Figure out all selectors
|
|
1079
|
+
container.walkRules((rule) => {
|
|
1080
|
+
let modified = rule.selector
|
|
1081
|
+
|
|
1082
|
+
// Rebuild the base selector, this is what plugin authors would do
|
|
1083
|
+
// as well. E.g.: `${variant}${separator}${className}`.
|
|
1084
|
+
// However, plugin authors probably also prepend or append certain
|
|
1085
|
+
// classes, pseudos, ids, ...
|
|
1086
|
+
let rebuiltBase = selectorParser((selectors) => {
|
|
1087
|
+
selectors.walkClasses((classNode) => {
|
|
1088
|
+
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`
|
|
1089
|
+
})
|
|
1090
|
+
}).processSync(modified)
|
|
1091
|
+
|
|
1092
|
+
// Now that we know the original selector, the new selector, and
|
|
1093
|
+
// the rebuild part in between, we can replace the part that plugin
|
|
1094
|
+
// authors need to rebuild with `&`, and eventually store it in the
|
|
1095
|
+
// collectedFormats. Similar to what `format('...')` would do.
|
|
1096
|
+
//
|
|
1097
|
+
// E.g.:
|
|
1098
|
+
// variant: foo
|
|
1099
|
+
// selector: .markdown > p
|
|
1100
|
+
// modified (by plugin): .foo .foo\\:markdown > p
|
|
1101
|
+
// rebuiltBase (internal): .foo\\:markdown > p
|
|
1102
|
+
// format: .foo &
|
|
1103
|
+
manualFormatStrings.push(modified.replace(rebuiltBase, '&').replace(candidate, '&'))
|
|
1104
|
+
})
|
|
1105
|
+
|
|
1106
|
+
// Figure out all atrules
|
|
1107
|
+
container.walkAtRules((atrule) => {
|
|
1108
|
+
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`)
|
|
1109
|
+
})
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
let isArbitraryVariant = !(value in (options.values ?? {}))
|
|
1113
|
+
|
|
1114
|
+
formatStrings = formatStrings.map((format) =>
|
|
1115
|
+
format.map((str) => ({
|
|
1116
|
+
format: str,
|
|
1117
|
+
isArbitraryVariant,
|
|
1118
|
+
}))
|
|
1119
|
+
)
|
|
1120
|
+
|
|
1121
|
+
manualFormatStrings = manualFormatStrings.map((format) => ({
|
|
1122
|
+
format,
|
|
1123
|
+
isArbitraryVariant,
|
|
1124
|
+
}))
|
|
1125
|
+
|
|
1126
|
+
let opts = {
|
|
1127
|
+
candidate,
|
|
1128
|
+
context,
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
let result = formatStrings.map((formats) =>
|
|
1132
|
+
finalizeSelector(`.${candidate}`, formatVariantSelector(formats, opts), opts)
|
|
1133
|
+
.replace(`.${candidate}`, '&')
|
|
1134
|
+
.replace('{ & }', '')
|
|
1135
|
+
.trim()
|
|
1136
|
+
)
|
|
1137
|
+
|
|
1138
|
+
if (manualFormatStrings.length > 0) {
|
|
1139
|
+
result.push(
|
|
1140
|
+
formatVariantSelector(manualFormatStrings, opts)
|
|
1141
|
+
.toString()
|
|
1142
|
+
.replace(`.${candidate}`, '&')
|
|
1143
|
+
)
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
return result
|
|
1147
|
+
},
|
|
1148
|
+
})
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
return result
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Mark as class as retroactively invalid
|
|
1157
|
+
*
|
|
1158
|
+
*
|
|
1159
|
+
* @param {string} candidate
|
|
1160
|
+
*/
|
|
1161
|
+
function markInvalidUtilityCandidate(context, candidate) {
|
|
1162
|
+
if (!context.classCache.has(candidate)) {
|
|
1163
|
+
return
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// Mark this as not being a real utility
|
|
1167
|
+
context.notClassCache.add(candidate)
|
|
1168
|
+
|
|
1169
|
+
// Remove it from any candidate-specific caches
|
|
1170
|
+
context.classCache.delete(candidate)
|
|
1171
|
+
context.applyClassCache.delete(candidate)
|
|
1172
|
+
context.candidateRuleMap.delete(candidate)
|
|
1173
|
+
context.candidateRuleCache.delete(candidate)
|
|
1174
|
+
|
|
1175
|
+
// Ensure the stylesheet gets rebuilt
|
|
1176
|
+
context.stylesheetCache = null
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* Mark as class as retroactively invalid
|
|
1181
|
+
*
|
|
1182
|
+
* @param {import('postcss').Node} node
|
|
1183
|
+
*/
|
|
1184
|
+
function markInvalidUtilityNode(context, node) {
|
|
1185
|
+
let candidate = node.raws.tailwind.candidate
|
|
1186
|
+
|
|
1187
|
+
if (!candidate) {
|
|
1188
|
+
return
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
for (const entry of context.ruleCache) {
|
|
1192
|
+
if (entry[1].raws.tailwind.candidate === candidate) {
|
|
1193
|
+
context.ruleCache.delete(entry)
|
|
1194
|
+
// context.postCssNodeCache.delete(node)
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
markInvalidUtilityCandidate(context, candidate)
|
|
790
1199
|
}
|
|
791
1200
|
|
|
792
1201
|
export function createContext(tailwindConfig, changedContent = [], root = postcss.root()) {
|
|
793
1202
|
let context = {
|
|
794
1203
|
disposables: [],
|
|
795
1204
|
ruleCache: new Set(),
|
|
1205
|
+
candidateRuleCache: new Map(),
|
|
796
1206
|
classCache: new Map(),
|
|
797
1207
|
applyClassCache: new Map(),
|
|
798
|
-
|
|
1208
|
+
// Seed the not class cache with the blocklist (which is only strings)
|
|
1209
|
+
notClassCache: new Set(tailwindConfig.blocklist ?? []),
|
|
799
1210
|
postCssNodeCache: new Map(),
|
|
800
1211
|
candidateRuleMap: new Map(),
|
|
801
1212
|
tailwindConfig,
|
|
802
1213
|
changedContent: changedContent,
|
|
803
1214
|
variantMap: new Map(),
|
|
804
1215
|
stylesheetCache: null,
|
|
1216
|
+
variantOptions: new Map(),
|
|
1217
|
+
|
|
1218
|
+
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
|
|
1219
|
+
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
|
|
805
1220
|
}
|
|
806
1221
|
|
|
807
1222
|
let resolvedPlugins = resolvePlugins(context, root)
|
|
@@ -844,12 +1259,12 @@ export function getContext(
|
|
|
844
1259
|
// If there's already a context in the cache and we don't need to
|
|
845
1260
|
// reset the context, return the cached context.
|
|
846
1261
|
if (existingContext) {
|
|
847
|
-
let contextDependenciesChanged = trackModified(
|
|
1262
|
+
let [contextDependenciesChanged, mtimesToCommit] = trackModified(
|
|
848
1263
|
[...contextDependencies],
|
|
849
1264
|
getFileModifiedMap(existingContext)
|
|
850
1265
|
)
|
|
851
1266
|
if (!contextDependenciesChanged && !cssDidChange) {
|
|
852
|
-
return [existingContext, false]
|
|
1267
|
+
return [existingContext, false, mtimesToCommit]
|
|
853
1268
|
}
|
|
854
1269
|
}
|
|
855
1270
|
|
|
@@ -880,7 +1295,11 @@ export function getContext(
|
|
|
880
1295
|
|
|
881
1296
|
let context = createContext(tailwindConfig, [], root)
|
|
882
1297
|
|
|
883
|
-
|
|
1298
|
+
Object.assign(context, {
|
|
1299
|
+
userConfigPath,
|
|
1300
|
+
})
|
|
1301
|
+
|
|
1302
|
+
let [, mtimesToCommit] = trackModified([...contextDependencies], getFileModifiedMap(context))
|
|
884
1303
|
|
|
885
1304
|
// ---
|
|
886
1305
|
|
|
@@ -895,5 +1314,5 @@ export function getContext(
|
|
|
895
1314
|
|
|
896
1315
|
contextSourcesMap.get(context).add(sourcePath)
|
|
897
1316
|
|
|
898
|
-
return [context, true]
|
|
1317
|
+
return [context, true, mtimesToCommit]
|
|
899
1318
|
}
|