tailwindcss 0.0.0-insiders.ee945bb → 0.0.0-insiders.ef2ebb2
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/colors.d.ts +3 -0
- package/defaultConfig.d.ts +3 -0
- package/defaultTheme.d.ts +4 -0
- package/index.css +5 -0
- package/lib/cli/build/index.js +57 -0
- package/lib/cli/build/plugin.js +433 -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 -751
- package/lib/corePluginList.js +13 -3
- package/lib/corePlugins.js +2323 -1720
- 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 +454 -206
- 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 +687 -301
- 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 +166 -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 +70 -53
- 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 +59 -53
- 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/index.js +53 -0
- package/src/cli/build/plugin.js +476 -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 -825
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +614 -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 +427 -127
- 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 +591 -156
- package/src/lib/setupTrackingContext.js +44 -58
- package/src/lib/sharedState.js +13 -4
- package/src/plugin.js +141 -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 +39 -20
- 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} +218 -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 +369 -0
- package/types/generated/.gitkeep +0 -0
- package/types/generated/colors.d.ts +298 -0
- package/types/generated/corePluginList.d.ts +1 -0
- package/types/generated/default-theme.d.ts +372 -0
- package/types/index.d.ts +7 -0
- package/CHANGELOG.md +0 -2090
- package/lib/cli-peer-dependencies.js +0 -15
- package/lib/constants.js +0 -37
- package/peers/index.js +0 -75077
- 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
|
@@ -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 = [] } = {}) {
|
|
@@ -85,12 +128,18 @@ function parseStyles(styles) {
|
|
|
85
128
|
})
|
|
86
129
|
}
|
|
87
130
|
|
|
88
|
-
function getClasses(selector) {
|
|
131
|
+
function getClasses(selector, mutate) {
|
|
89
132
|
let parser = selectorParser((selectors) => {
|
|
90
133
|
let allClasses = []
|
|
134
|
+
|
|
135
|
+
if (mutate) {
|
|
136
|
+
mutate(selectors)
|
|
137
|
+
}
|
|
138
|
+
|
|
91
139
|
selectors.walkClasses((classNode) => {
|
|
92
140
|
allClasses.push(classNode.value)
|
|
93
141
|
})
|
|
142
|
+
|
|
94
143
|
return allClasses
|
|
95
144
|
})
|
|
96
145
|
return parser.transformSync(selector)
|
|
@@ -101,8 +150,20 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
|
|
|
101
150
|
|
|
102
151
|
// Handle normal rules
|
|
103
152
|
if (node.type === 'rule') {
|
|
153
|
+
// Ignore everything inside a :not(...). This allows you to write code like
|
|
154
|
+
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to
|
|
155
|
+
// not generated it. But now we will ignore everything inside a `:not`, so
|
|
156
|
+
// that it still gets generated.
|
|
157
|
+
function ignoreNot(selectors) {
|
|
158
|
+
selectors.walkPseudos((pseudo) => {
|
|
159
|
+
if (pseudo.value === ':not') {
|
|
160
|
+
pseudo.remove()
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
104
165
|
for (let selector of node.selectors) {
|
|
105
|
-
let classCandidates = getClasses(selector)
|
|
166
|
+
let classCandidates = getClasses(selector, ignoreNot)
|
|
106
167
|
// At least one of the selectors contains non-"on-demandable" candidates.
|
|
107
168
|
if (classCandidates.length === 0) {
|
|
108
169
|
state.containsNonOnDemandable = true
|
|
@@ -117,9 +178,7 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
|
|
|
117
178
|
// Handle at-rules (which contains nested rules)
|
|
118
179
|
else if (node.type === 'atrule') {
|
|
119
180
|
node.walkRules((rule) => {
|
|
120
|
-
for (let classCandidate of rule.selectors.flatMap((selector) =>
|
|
121
|
-
getClasses(selector, state, depth + 1)
|
|
122
|
-
)) {
|
|
181
|
+
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) {
|
|
123
182
|
classes.push(classCandidate)
|
|
124
183
|
}
|
|
125
184
|
})
|
|
@@ -154,6 +213,41 @@ function withIdentifiers(styles) {
|
|
|
154
213
|
})
|
|
155
214
|
}
|
|
156
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
|
+
*/
|
|
157
251
|
function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
|
|
158
252
|
function getConfigValue(path, defaultValue) {
|
|
159
253
|
return path ? dlv(tailwindConfig, path, defaultValue) : tailwindConfig
|
|
@@ -175,51 +269,19 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
175
269
|
return context.tailwindConfig.prefix + identifier
|
|
176
270
|
}
|
|
177
271
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return ({ modifySelectors, container, separator }) => {
|
|
184
|
-
return variantFunction({ modifySelectors, container, separator })
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
variantFunction = variantFunction
|
|
189
|
-
.replace(/\n+/g, '')
|
|
190
|
-
.replace(/\s{1,}/g, ' ')
|
|
191
|
-
.trim()
|
|
192
|
-
|
|
193
|
-
let fns = parseVariantFormatString(variantFunction)
|
|
194
|
-
.map((str) => {
|
|
195
|
-
if (!str.startsWith('@')) {
|
|
196
|
-
return ({ format }) => format(str)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
let [, name, params] = /@(.*?) (.*)/g.exec(str)
|
|
200
|
-
return ({ wrap }) => wrap(postcss.atRule({ name, params }))
|
|
201
|
-
})
|
|
202
|
-
.reverse()
|
|
203
|
-
|
|
204
|
-
return (api) => {
|
|
205
|
-
for (let fn of fns) {
|
|
206
|
-
fn(api)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
})
|
|
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
|
+
}
|
|
210
277
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
},
|
|
278
|
+
let variantIdentifier = 0
|
|
279
|
+
let api = {
|
|
214
280
|
postcss,
|
|
215
281
|
prefix: applyConfiguredPrefix,
|
|
216
282
|
e: escapeClassName,
|
|
217
283
|
config: getConfigValue,
|
|
218
|
-
theme
|
|
219
|
-
const [pathRoot, ...subPaths] = toPath(path)
|
|
220
|
-
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
|
221
|
-
return transformThemeValue(pathRoot)(value)
|
|
222
|
-
},
|
|
284
|
+
theme: resolveThemeValue,
|
|
223
285
|
corePlugins: (path) => {
|
|
224
286
|
if (Array.isArray(tailwindConfig.corePlugins)) {
|
|
225
287
|
return tailwindConfig.corePlugins.includes(path)
|
|
@@ -234,7 +296,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
234
296
|
addBase(base) {
|
|
235
297
|
for (let [identifier, rule] of withIdentifiers(base)) {
|
|
236
298
|
let prefixedIdentifier = prefixIdentifier(identifier, {})
|
|
237
|
-
let offset = offsets.base
|
|
299
|
+
let offset = offsets.create('base')
|
|
238
300
|
|
|
239
301
|
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
240
302
|
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
@@ -263,11 +325,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
263
325
|
|
|
264
326
|
context.candidateRuleMap
|
|
265
327
|
.get(prefixedIdentifier)
|
|
266
|
-
.push([{ sort: offsets.
|
|
328
|
+
.push([{ sort: offsets.create('defaults'), layer: 'defaults' }, rule])
|
|
267
329
|
}
|
|
268
330
|
},
|
|
269
331
|
addComponents(components, options) {
|
|
270
332
|
let defaultOptions = {
|
|
333
|
+
preserveSource: false,
|
|
271
334
|
respectPrefix: true,
|
|
272
335
|
respectImportant: false,
|
|
273
336
|
}
|
|
@@ -285,11 +348,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
285
348
|
|
|
286
349
|
context.candidateRuleMap
|
|
287
350
|
.get(prefixedIdentifier)
|
|
288
|
-
.push([{ sort: offsets.components
|
|
351
|
+
.push([{ sort: offsets.create('components'), layer: 'components', options }, rule])
|
|
289
352
|
}
|
|
290
353
|
},
|
|
291
354
|
addUtilities(utilities, options) {
|
|
292
355
|
let defaultOptions = {
|
|
356
|
+
preserveSource: false,
|
|
293
357
|
respectPrefix: true,
|
|
294
358
|
respectImportant: true,
|
|
295
359
|
}
|
|
@@ -307,18 +371,19 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
307
371
|
|
|
308
372
|
context.candidateRuleMap
|
|
309
373
|
.get(prefixedIdentifier)
|
|
310
|
-
.push([{ sort: offsets.utilities
|
|
374
|
+
.push([{ sort: offsets.create('utilities'), layer: 'utilities', options }, rule])
|
|
311
375
|
}
|
|
312
376
|
},
|
|
313
377
|
matchUtilities: function (utilities, options) {
|
|
314
378
|
let defaultOptions = {
|
|
315
379
|
respectPrefix: true,
|
|
316
380
|
respectImportant: true,
|
|
381
|
+
modifiers: false,
|
|
317
382
|
}
|
|
318
383
|
|
|
319
|
-
options = { ...defaultOptions, ...options }
|
|
384
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
320
385
|
|
|
321
|
-
let offset = offsets.utilities
|
|
386
|
+
let offset = offsets.create('utilities')
|
|
322
387
|
|
|
323
388
|
for (let identifier in utilities) {
|
|
324
389
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
@@ -327,24 +392,49 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
327
392
|
classList.add([prefixedIdentifier, options])
|
|
328
393
|
|
|
329
394
|
function wrapped(modifier, { isOnlyPlugin }) {
|
|
330
|
-
let
|
|
331
|
-
|
|
332
|
-
|
|
395
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
396
|
+
options.types,
|
|
397
|
+
modifier,
|
|
398
|
+
options,
|
|
399
|
+
tailwindConfig
|
|
400
|
+
)
|
|
333
401
|
|
|
334
402
|
if (value === undefined) {
|
|
335
403
|
return []
|
|
336
404
|
}
|
|
337
405
|
|
|
338
|
-
if (!
|
|
339
|
-
|
|
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
|
+
}
|
|
340
418
|
}
|
|
341
419
|
|
|
342
|
-
if (!
|
|
420
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
343
421
|
return []
|
|
344
422
|
}
|
|
345
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
|
+
|
|
346
436
|
let ruleSets = []
|
|
347
|
-
.concat(rule(value))
|
|
437
|
+
.concat(rule(value, extras))
|
|
348
438
|
.filter(Boolean)
|
|
349
439
|
.map((declaration) => ({
|
|
350
440
|
[nameClass(identifier, modifier)]: declaration,
|
|
@@ -366,11 +456,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
366
456
|
let defaultOptions = {
|
|
367
457
|
respectPrefix: true,
|
|
368
458
|
respectImportant: false,
|
|
459
|
+
modifiers: false,
|
|
369
460
|
}
|
|
370
461
|
|
|
371
|
-
options = { ...defaultOptions, ...options }
|
|
462
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
372
463
|
|
|
373
|
-
let offset = offsets.components
|
|
464
|
+
let offset = offsets.create('components')
|
|
374
465
|
|
|
375
466
|
for (let identifier in components) {
|
|
376
467
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
@@ -379,15 +470,18 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
379
470
|
classList.add([prefixedIdentifier, options])
|
|
380
471
|
|
|
381
472
|
function wrapped(modifier, { isOnlyPlugin }) {
|
|
382
|
-
let
|
|
383
|
-
|
|
384
|
-
|
|
473
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
474
|
+
options.types,
|
|
475
|
+
modifier,
|
|
476
|
+
options,
|
|
477
|
+
tailwindConfig
|
|
478
|
+
)
|
|
385
479
|
|
|
386
480
|
if (value === undefined) {
|
|
387
481
|
return []
|
|
388
482
|
}
|
|
389
483
|
|
|
390
|
-
if (!
|
|
484
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
391
485
|
if (isOnlyPlugin) {
|
|
392
486
|
log.warn([
|
|
393
487
|
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
@@ -401,12 +495,24 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
401
495
|
}
|
|
402
496
|
}
|
|
403
497
|
|
|
404
|
-
if (!
|
|
498
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
405
499
|
return []
|
|
406
500
|
}
|
|
407
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
|
+
|
|
408
514
|
let ruleSets = []
|
|
409
|
-
.concat(rule(value))
|
|
515
|
+
.concat(rule(value, extras))
|
|
410
516
|
.filter(Boolean)
|
|
411
517
|
.map((declaration) => ({
|
|
412
518
|
[nameClass(identifier, modifier)]: declaration,
|
|
@@ -424,7 +530,104 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
424
530
|
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
|
|
425
531
|
}
|
|
426
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
|
+
},
|
|
427
628
|
}
|
|
629
|
+
|
|
630
|
+
return api
|
|
428
631
|
}
|
|
429
632
|
|
|
430
633
|
let fileModifiedMapCache = new WeakMap()
|
|
@@ -437,6 +640,7 @@ export function getFileModifiedMap(context) {
|
|
|
437
640
|
|
|
438
641
|
function trackModified(files, fileModifiedMap) {
|
|
439
642
|
let changed = false
|
|
643
|
+
let mtimesToCommit = new Map()
|
|
440
644
|
|
|
441
645
|
for (let file of files) {
|
|
442
646
|
if (!file) continue
|
|
@@ -457,10 +661,10 @@ function trackModified(files, fileModifiedMap) {
|
|
|
457
661
|
changed = true
|
|
458
662
|
}
|
|
459
663
|
|
|
460
|
-
|
|
664
|
+
mtimesToCommit.set(file, newModified)
|
|
461
665
|
}
|
|
462
666
|
|
|
463
|
-
return changed
|
|
667
|
+
return [changed, mtimesToCommit]
|
|
464
668
|
}
|
|
465
669
|
|
|
466
670
|
function extractVariantAtRules(node) {
|
|
@@ -497,14 +701,14 @@ function collectLayerPlugins(root) {
|
|
|
497
701
|
} else if (layerRule.params === 'components') {
|
|
498
702
|
for (let node of layerRule.nodes) {
|
|
499
703
|
layerPlugins.push(function ({ addComponents }) {
|
|
500
|
-
addComponents(node, { respectPrefix: false })
|
|
704
|
+
addComponents(node, { respectPrefix: false, preserveSource: true })
|
|
501
705
|
})
|
|
502
706
|
}
|
|
503
707
|
layerRule.remove()
|
|
504
708
|
} else if (layerRule.params === 'utilities') {
|
|
505
709
|
for (let node of layerRule.nodes) {
|
|
506
710
|
layerPlugins.push(function ({ addUtilities }) {
|
|
507
|
-
addUtilities(node, { respectPrefix: false })
|
|
711
|
+
addUtilities(node, { respectPrefix: false, preserveSource: true })
|
|
508
712
|
})
|
|
509
713
|
}
|
|
510
714
|
layerRule.remove()
|
|
@@ -515,7 +719,7 @@ function collectLayerPlugins(root) {
|
|
|
515
719
|
}
|
|
516
720
|
|
|
517
721
|
function resolvePlugins(context, root) {
|
|
518
|
-
let corePluginList = Object.entries(
|
|
722
|
+
let corePluginList = Object.entries(corePlugins)
|
|
519
723
|
.map(([name, plugin]) => {
|
|
520
724
|
if (!context.tailwindConfig.corePlugins.includes(name)) {
|
|
521
725
|
return null
|
|
@@ -540,10 +744,15 @@ function resolvePlugins(context, root) {
|
|
|
540
744
|
let beforeVariants = [
|
|
541
745
|
variantPlugins['pseudoElementVariants'],
|
|
542
746
|
variantPlugins['pseudoClassVariants'],
|
|
747
|
+
variantPlugins['hasVariants'],
|
|
748
|
+
variantPlugins['ariaVariants'],
|
|
749
|
+
variantPlugins['dataVariants'],
|
|
543
750
|
]
|
|
544
751
|
let afterVariants = [
|
|
752
|
+
variantPlugins['supportsVariants'],
|
|
545
753
|
variantPlugins['directionVariants'],
|
|
546
754
|
variantPlugins['reducedMotionVariants'],
|
|
755
|
+
variantPlugins['prefersContrastVariants'],
|
|
547
756
|
variantPlugins['darkVariants'],
|
|
548
757
|
variantPlugins['printVariant'],
|
|
549
758
|
variantPlugins['screenVariants'],
|
|
@@ -556,13 +765,10 @@ function resolvePlugins(context, root) {
|
|
|
556
765
|
function registerPlugins(plugins, context) {
|
|
557
766
|
let variantList = []
|
|
558
767
|
let variantMap = new Map()
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
utilities: 0n,
|
|
564
|
-
user: 0n,
|
|
565
|
-
}
|
|
768
|
+
context.variantMap = variantMap
|
|
769
|
+
|
|
770
|
+
let offsets = new Offsets()
|
|
771
|
+
context.offsets = offsets
|
|
566
772
|
|
|
567
773
|
let classList = new Set()
|
|
568
774
|
|
|
@@ -583,49 +789,17 @@ function registerPlugins(plugins, context) {
|
|
|
583
789
|
}
|
|
584
790
|
}
|
|
585
791
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
offsets.defaults,
|
|
589
|
-
offsets.components,
|
|
590
|
-
offsets.utilities,
|
|
591
|
-
offsets.user,
|
|
592
|
-
])
|
|
593
|
-
let reservedBits = BigInt(highestOffset.toString(2).length)
|
|
594
|
-
|
|
595
|
-
// A number one less than the top range of the highest offset area
|
|
596
|
-
// so arbitrary properties are always sorted at the end.
|
|
597
|
-
context.arbitraryPropertiesSort = ((1n << reservedBits) << 0n) - 1n
|
|
598
|
-
|
|
599
|
-
context.layerOrder = {
|
|
600
|
-
defaults: (1n << reservedBits) << 0n,
|
|
601
|
-
base: (1n << reservedBits) << 1n,
|
|
602
|
-
components: (1n << reservedBits) << 2n,
|
|
603
|
-
utilities: (1n << reservedBits) << 3n,
|
|
604
|
-
user: (1n << reservedBits) << 4n,
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
reservedBits += 5n
|
|
608
|
-
|
|
609
|
-
let offset = 0
|
|
610
|
-
context.variantOrder = new Map(
|
|
611
|
-
variantList
|
|
612
|
-
.map((variant, i) => {
|
|
613
|
-
let variantFunctions = variantMap.get(variant).length
|
|
614
|
-
let bits = (1n << BigInt(i + offset)) << reservedBits
|
|
615
|
-
offset += variantFunctions - 1
|
|
616
|
-
return [variant, bits]
|
|
617
|
-
})
|
|
618
|
-
.sort(([, a], [, z]) => bigSign(a - z))
|
|
619
|
-
)
|
|
620
|
-
|
|
621
|
-
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)
|
|
622
794
|
|
|
623
795
|
// Build variantMap
|
|
624
796
|
for (let [variantName, variantFunctions] of variantMap.entries()) {
|
|
625
|
-
let sort = context.variantOrder.get(variantName)
|
|
626
797
|
context.variantMap.set(
|
|
627
798
|
variantName,
|
|
628
|
-
variantFunctions.map((variantFunction, idx) => [
|
|
799
|
+
variantFunctions.map((variantFunction, idx) => [
|
|
800
|
+
offsets.forVariant(variantName, idx),
|
|
801
|
+
variantFunction,
|
|
802
|
+
])
|
|
629
803
|
)
|
|
630
804
|
}
|
|
631
805
|
|
|
@@ -654,6 +828,7 @@ function registerPlugins(plugins, context) {
|
|
|
654
828
|
if (checks.length > 0) {
|
|
655
829
|
let patternMatchingCount = new Map()
|
|
656
830
|
let prefixLength = context.tailwindConfig.prefix.length
|
|
831
|
+
let checkImportantUtils = checks.some((check) => check.pattern.source.includes('!'))
|
|
657
832
|
|
|
658
833
|
for (let util of classList) {
|
|
659
834
|
let utils = Array.isArray(util)
|
|
@@ -679,6 +854,21 @@ function registerPlugins(plugins, context) {
|
|
|
679
854
|
]
|
|
680
855
|
}
|
|
681
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
|
+
|
|
682
872
|
return classes
|
|
683
873
|
})()
|
|
684
874
|
: [util]
|
|
@@ -720,26 +910,48 @@ function registerPlugins(plugins, context) {
|
|
|
720
910
|
}
|
|
721
911
|
}
|
|
722
912
|
|
|
913
|
+
let darkClassName = [].concat(context.tailwindConfig.darkMode ?? 'media')[1] ?? 'dark'
|
|
914
|
+
|
|
723
915
|
// A list of utilities that are used by certain Tailwind CSS utilities but
|
|
724
916
|
// that don't exist on their own. This will result in them "not existing" and
|
|
725
917
|
// sorting could be weird since you still require them in order to make the
|
|
726
|
-
// host
|
|
727
|
-
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
|
+
]
|
|
728
924
|
context.getClassOrder = function getClassOrder(classes) {
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
if (
|
|
732
|
-
|
|
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++)
|
|
733
944
|
}
|
|
734
945
|
|
|
735
946
|
return classes.map((className) => {
|
|
736
947
|
let order = sortedClassNames.get(className) ?? null
|
|
948
|
+
let parasiteIndex = parasiteUtilities.indexOf(className)
|
|
737
949
|
|
|
738
|
-
if (order === null &&
|
|
950
|
+
if (order === null && parasiteIndex !== -1) {
|
|
739
951
|
// This will make sure that it is at the very beginning of the
|
|
740
952
|
// `components` layer which technically means 'before any
|
|
741
953
|
// components'.
|
|
742
|
-
order =
|
|
954
|
+
order = BigInt(parasiteIndex)
|
|
743
955
|
}
|
|
744
956
|
|
|
745
957
|
return [className, order]
|
|
@@ -748,18 +960,35 @@ function registerPlugins(plugins, context) {
|
|
|
748
960
|
|
|
749
961
|
// Generate a list of strings for autocompletion purposes, e.g.
|
|
750
962
|
// ['uppercase', 'lowercase', ...]
|
|
751
|
-
context.getClassList = function getClassList() {
|
|
963
|
+
context.getClassList = function getClassList(options = {}) {
|
|
752
964
|
let output = []
|
|
753
965
|
|
|
754
966
|
for (let util of classList) {
|
|
755
967
|
if (Array.isArray(util)) {
|
|
756
|
-
let [utilName,
|
|
968
|
+
let [utilName, utilOptions] = util
|
|
757
969
|
let negativeClasses = []
|
|
758
970
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
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)
|
|
763
992
|
}
|
|
764
993
|
}
|
|
765
994
|
|
|
@@ -771,21 +1000,223 @@ function registerPlugins(plugins, context) {
|
|
|
771
1000
|
|
|
772
1001
|
return output
|
|
773
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)
|
|
774
1199
|
}
|
|
775
1200
|
|
|
776
1201
|
export function createContext(tailwindConfig, changedContent = [], root = postcss.root()) {
|
|
777
1202
|
let context = {
|
|
778
1203
|
disposables: [],
|
|
779
1204
|
ruleCache: new Set(),
|
|
1205
|
+
candidateRuleCache: new Map(),
|
|
780
1206
|
classCache: new Map(),
|
|
781
1207
|
applyClassCache: new Map(),
|
|
782
|
-
|
|
1208
|
+
// Seed the not class cache with the blocklist (which is only strings)
|
|
1209
|
+
notClassCache: new Set(tailwindConfig.blocklist ?? []),
|
|
783
1210
|
postCssNodeCache: new Map(),
|
|
784
1211
|
candidateRuleMap: new Map(),
|
|
785
1212
|
tailwindConfig,
|
|
786
1213
|
changedContent: changedContent,
|
|
787
1214
|
variantMap: new Map(),
|
|
788
1215
|
stylesheetCache: null,
|
|
1216
|
+
variantOptions: new Map(),
|
|
1217
|
+
|
|
1218
|
+
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
|
|
1219
|
+
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
|
|
789
1220
|
}
|
|
790
1221
|
|
|
791
1222
|
let resolvedPlugins = resolvePlugins(context, root)
|
|
@@ -828,12 +1259,12 @@ export function getContext(
|
|
|
828
1259
|
// If there's already a context in the cache and we don't need to
|
|
829
1260
|
// reset the context, return the cached context.
|
|
830
1261
|
if (existingContext) {
|
|
831
|
-
let contextDependenciesChanged = trackModified(
|
|
1262
|
+
let [contextDependenciesChanged, mtimesToCommit] = trackModified(
|
|
832
1263
|
[...contextDependencies],
|
|
833
1264
|
getFileModifiedMap(existingContext)
|
|
834
1265
|
)
|
|
835
1266
|
if (!contextDependenciesChanged && !cssDidChange) {
|
|
836
|
-
return [existingContext, false]
|
|
1267
|
+
return [existingContext, false, mtimesToCommit]
|
|
837
1268
|
}
|
|
838
1269
|
}
|
|
839
1270
|
|
|
@@ -864,7 +1295,11 @@ export function getContext(
|
|
|
864
1295
|
|
|
865
1296
|
let context = createContext(tailwindConfig, [], root)
|
|
866
1297
|
|
|
867
|
-
|
|
1298
|
+
Object.assign(context, {
|
|
1299
|
+
userConfigPath,
|
|
1300
|
+
})
|
|
1301
|
+
|
|
1302
|
+
let [, mtimesToCommit] = trackModified([...contextDependencies], getFileModifiedMap(context))
|
|
868
1303
|
|
|
869
1304
|
// ---
|
|
870
1305
|
|
|
@@ -879,5 +1314,5 @@ export function getContext(
|
|
|
879
1314
|
|
|
880
1315
|
contextSourcesMap.get(context).add(sourcePath)
|
|
881
1316
|
|
|
882
|
-
return [context, true]
|
|
1317
|
+
return [context, true, mtimesToCommit]
|
|
883
1318
|
}
|