tailwindcss 0.0.0-insiders.dddaded → 0.0.0-insiders.de00a62
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/lib/cli/build/deps.js +17 -9
- package/lib/cli/build/index.js +10 -8
- package/lib/cli/build/plugin.js +31 -29
- package/lib/cli/build/utils.js +18 -8
- package/lib/cli/build/watching.js +13 -11
- package/lib/cli/help/index.js +6 -4
- package/lib/cli/index.js +4 -4
- package/lib/cli/init/index.js +8 -6
- package/lib/cli-peer-dependencies.js +12 -4
- package/lib/cli.js +1 -1
- package/lib/corePluginList.js +8 -2
- package/lib/corePlugins.js +211 -48
- package/lib/css/preflight.css +24 -8
- package/lib/featureFlags.js +14 -9
- package/lib/index.js +1 -5
- package/lib/lib/cacheInvalidation.js +7 -5
- package/lib/lib/collapseAdjacentRules.js +3 -1
- package/lib/lib/collapseDuplicateDeclarations.js +10 -8
- package/lib/lib/content.js +51 -14
- package/lib/lib/defaultExtractor.js +38 -28
- package/lib/lib/detectNesting.js +3 -1
- package/lib/lib/evaluateTailwindFunctions.js +20 -16
- package/lib/lib/expandApplyAtRules.js +41 -33
- package/lib/lib/expandTailwindAtRules.js +38 -19
- package/lib/lib/findAtConfigPath.js +6 -4
- package/lib/lib/generateRules.js +83 -55
- package/lib/lib/getModuleDependencies.js +10 -8
- package/lib/lib/load-config.js +18 -5
- package/lib/lib/normalizeTailwindDirectives.js +5 -3
- package/lib/lib/offsets.js +58 -7
- package/lib/lib/partitionApplyAtRules.js +3 -1
- package/lib/lib/regex.js +21 -7
- package/lib/lib/remap-bitfield.js +3 -1
- package/lib/lib/resolveDefaultsAtRules.js +27 -21
- package/lib/lib/setupContextUtils.js +143 -94
- package/lib/lib/setupTrackingContext.js +27 -24
- package/lib/lib/sharedState.js +28 -24
- package/lib/lib/substituteScreenAtRules.js +5 -3
- package/lib/oxide/cli/build/deps.js +16 -8
- package/lib/oxide/cli/build/index.js +6 -4
- package/lib/oxide/cli/build/plugin.js +25 -23
- package/lib/oxide/cli/build/utils.js +18 -8
- package/lib/oxide/cli/build/watching.js +10 -8
- package/lib/oxide/cli/help/index.js +6 -4
- package/lib/oxide/cli/index.js +4 -4
- package/lib/oxide/cli/init/index.js +6 -4
- package/lib/plugin.js +9 -9
- package/lib/postcss-plugins/nesting/index.js +3 -1
- package/lib/postcss-plugins/nesting/plugin.js +8 -6
- package/lib/processTailwindFeatures.js +16 -14
- package/lib/public/colors.js +5 -3
- package/lib/public/create-plugin.js +5 -3
- package/lib/public/default-config.js +6 -4
- package/lib/public/default-theme.js +6 -4
- package/lib/public/load-config.js +5 -3
- package/lib/public/resolve-config.js +6 -4
- package/lib/util/applyImportantSelector.js +7 -5
- package/lib/util/bigSign.js +3 -1
- package/lib/util/buildMediaQuery.js +3 -1
- package/lib/util/cloneDeep.js +3 -1
- package/lib/util/cloneNodes.js +36 -14
- package/lib/util/color.js +11 -7
- package/lib/util/colorNames.js +752 -0
- package/lib/util/configurePlugins.js +3 -1
- package/lib/util/createPlugin.js +3 -1
- package/lib/util/createUtilityPlugin.js +5 -3
- package/lib/util/dataTypes.js +180 -31
- package/lib/util/defaults.js +6 -4
- package/lib/util/escapeClassName.js +7 -5
- package/lib/util/escapeCommas.js +3 -1
- package/lib/util/flattenColorPalette.js +3 -1
- package/lib/util/formatVariantSelector.js +36 -21
- package/lib/util/getAllConfigs.js +6 -4
- package/lib/util/hashConfig.js +6 -4
- package/lib/util/isKeyframeRule.js +3 -1
- package/lib/util/isPlainObject.js +4 -2
- package/lib/util/isSyntacticallyValidPropertyValue.js +3 -1
- package/lib/util/log.js +8 -4
- package/lib/util/nameClass.js +12 -6
- package/lib/util/negateValue.js +3 -1
- package/lib/util/normalizeConfig.js +7 -5
- package/lib/util/normalizeScreens.js +12 -4
- package/lib/util/parseAnimationValue.js +3 -1
- package/lib/util/parseBoxShadowValue.js +6 -2
- package/lib/util/parseDependency.js +3 -1
- package/lib/util/parseGlob.js +6 -4
- package/lib/util/parseObjectStyles.js +9 -7
- package/lib/util/pluginUtils.js +43 -18
- package/lib/util/prefixSelector.js +6 -4
- package/lib/util/pseudoElements.js +24 -35
- package/lib/util/removeAlphaVariables.js +3 -1
- package/lib/util/resolveConfig.js +10 -8
- package/lib/util/resolveConfigPath.js +9 -5
- package/lib/util/responsive.js +6 -4
- package/lib/util/splitAtTopLevelOnly.js +3 -1
- package/lib/util/tap.js +3 -1
- package/lib/util/toColorValue.js +3 -1
- package/lib/util/toPath.js +3 -1
- package/lib/util/transformThemeValue.js +6 -4
- package/lib/util/validateConfig.js +5 -3
- package/lib/util/validateFormalSyntax.js +3 -1
- package/lib/util/withAlphaVariable.js +6 -2
- 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/nesting/index.d.ts +4 -0
- package/package.json +31 -36
- package/peers/index.js +65266 -48224
- package/resolveConfig.d.ts +22 -3
- package/scripts/generate-types.js +1 -2
- package/src/cli/build/plugin.js +7 -7
- package/src/cli/build/watching.js +1 -1
- package/src/cli.js +1 -1
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +165 -29
- package/src/css/preflight.css +24 -8
- package/src/featureFlags.js +3 -8
- package/src/index.js +1 -5
- package/src/lib/content.js +42 -1
- package/src/lib/defaultExtractor.js +30 -17
- package/src/lib/evaluateTailwindFunctions.js +4 -1
- package/src/lib/expandApplyAtRules.js +7 -0
- package/src/lib/expandTailwindAtRules.js +26 -9
- package/src/lib/generateRules.js +50 -26
- package/src/lib/load-config.ts +8 -0
- package/src/lib/offsets.js +61 -2
- package/src/lib/resolveDefaultsAtRules.js +5 -1
- package/src/lib/setupContextUtils.js +77 -38
- package/src/lib/setupTrackingContext.js +2 -4
- package/src/lib/sharedState.js +0 -15
- package/src/oxide/cli/build/plugin.ts +7 -7
- package/src/plugin.js +4 -4
- package/src/processTailwindFeatures.js +3 -2
- package/src/util/cloneNodes.js +35 -14
- package/src/util/color.js +2 -2
- package/src/util/colorNames.js +150 -0
- package/src/util/dataTypes.js +143 -18
- package/src/util/formatVariantSelector.js +11 -3
- package/src/util/isPlainObject.js +1 -1
- package/src/util/pluginUtils.js +17 -5
- package/src/util/prefixSelector.js +1 -0
- package/src/util/pseudoElements.js +18 -17
- 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/config.full.js +86 -14
- package/types/config.d.ts +17 -9
- package/types/generated/corePluginList.d.ts +1 -1
- package/types/generated/default-theme.d.ts +35 -9
- package/types/index.d.ts +7 -3
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { flagEnabled } from '../featureFlags'
|
|
2
1
|
import * as regex from './regex'
|
|
3
2
|
|
|
4
3
|
export function defaultExtractor(context) {
|
|
@@ -12,16 +11,17 @@ export function defaultExtractor(context) {
|
|
|
12
11
|
let results = []
|
|
13
12
|
|
|
14
13
|
for (let pattern of patterns) {
|
|
15
|
-
|
|
14
|
+
for (let result of content.match(pattern) ?? []) {
|
|
15
|
+
results.push(clipAtBalancedParens(result))
|
|
16
|
+
}
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
return results
|
|
19
|
+
return results
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
function* buildRegExps(context) {
|
|
23
24
|
let separator = context.tailwindConfig.separator
|
|
24
|
-
let variantGroupingEnabled = flagEnabled(context.tailwindConfig, 'variantGrouping')
|
|
25
25
|
let prefix =
|
|
26
26
|
context.tailwindConfig.prefix !== ''
|
|
27
27
|
? regex.optional(regex.pattern([/-?/, regex.escape(context.tailwindConfig.prefix)]))
|
|
@@ -35,19 +35,29 @@ function* buildRegExps(context) {
|
|
|
35
35
|
// This is a targeted fix to continue to allow theme()
|
|
36
36
|
// with square brackets to work in arbitrary properties
|
|
37
37
|
// while fixing a problem with the regex matching too much
|
|
38
|
-
/\[[^\s:'"
|
|
38
|
+
/\[[^\s:'"`\]]+:[^\s]+?\[[^\s]+\][^\s]+?\]/,
|
|
39
39
|
|
|
40
40
|
// Utilities
|
|
41
41
|
regex.pattern([
|
|
42
42
|
// Utility Name / Group Name
|
|
43
|
-
|
|
43
|
+
regex.any([
|
|
44
|
+
/-?(?:\w+)/,
|
|
45
|
+
|
|
46
|
+
// This is here to make sure @container supports everything that other utilities do
|
|
47
|
+
/@(?:\w+)/,
|
|
48
|
+
]),
|
|
44
49
|
|
|
45
50
|
// Normal/Arbitrary values
|
|
46
51
|
regex.optional(
|
|
47
52
|
regex.any([
|
|
48
53
|
regex.pattern([
|
|
49
54
|
// Arbitrary values
|
|
50
|
-
|
|
55
|
+
regex.any([
|
|
56
|
+
/-(?:\w+-)*\['[^\s]+'\]/,
|
|
57
|
+
/-(?:\w+-)*\["[^\s]+"\]/,
|
|
58
|
+
/-(?:\w+-)*\[`[^\s]+`\]/,
|
|
59
|
+
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/,
|
|
60
|
+
]),
|
|
51
61
|
|
|
52
62
|
// Not immediately followed by an `{[(`
|
|
53
63
|
/(?![{([]])/,
|
|
@@ -58,7 +68,12 @@ function* buildRegExps(context) {
|
|
|
58
68
|
|
|
59
69
|
regex.pattern([
|
|
60
70
|
// Arbitrary values
|
|
61
|
-
|
|
71
|
+
regex.any([
|
|
72
|
+
/-(?:\w+-)*\['[^\s]+'\]/,
|
|
73
|
+
/-(?:\w+-)*\["[^\s]+"\]/,
|
|
74
|
+
/-(?:\w+-)*\[`[^\s]+`\]/,
|
|
75
|
+
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/,
|
|
76
|
+
]),
|
|
62
77
|
|
|
63
78
|
// Not immediately followed by an `{[(`
|
|
64
79
|
/(?![{([]])/,
|
|
@@ -80,12 +95,18 @@ function* buildRegExps(context) {
|
|
|
80
95
|
// This is here to provide special support for the `@` variant
|
|
81
96
|
regex.pattern([/@\[[^\s"'`]+\](\/[^\s"'`]+)?/, separator]),
|
|
82
97
|
|
|
98
|
+
// With variant modifier (e.g.: group-[..]/modifier)
|
|
99
|
+
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/, separator]),
|
|
100
|
+
|
|
83
101
|
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]),
|
|
84
102
|
regex.pattern([/[^\s"'`\[\\]+/, separator]),
|
|
85
103
|
]),
|
|
86
104
|
|
|
87
105
|
// With quotes allowed
|
|
88
106
|
regex.any([
|
|
107
|
+
// With variant modifier (e.g.: group-[..]/modifier)
|
|
108
|
+
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/, separator]),
|
|
109
|
+
|
|
89
110
|
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, separator]),
|
|
90
111
|
regex.pattern([/[^\s`\[\\]+/, separator]),
|
|
91
112
|
]),
|
|
@@ -103,15 +124,7 @@ function* buildRegExps(context) {
|
|
|
103
124
|
|
|
104
125
|
prefix,
|
|
105
126
|
|
|
106
|
-
|
|
107
|
-
? regex.any([
|
|
108
|
-
// Or any of those things but grouped separated by commas
|
|
109
|
-
regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]),
|
|
110
|
-
|
|
111
|
-
// Arbitrary properties, constrained utilities, arbitrary values, etc…
|
|
112
|
-
utility,
|
|
113
|
-
])
|
|
114
|
-
: utility,
|
|
127
|
+
utility,
|
|
115
128
|
])
|
|
116
129
|
}
|
|
117
130
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dlv from 'dlv'
|
|
2
2
|
import didYouMean from 'didyoumean'
|
|
3
3
|
import transformThemeValue from '../util/transformThemeValue'
|
|
4
|
-
import parseValue from '
|
|
4
|
+
import parseValue from '../value-parser/index'
|
|
5
5
|
import { normalizeScreens } from '../util/normalizeScreens'
|
|
6
6
|
import buildMediaQuery from '../util/buildMediaQuery'
|
|
7
7
|
import { toPath } from '../util/toPath'
|
|
@@ -146,6 +146,9 @@ function resolveVNode(node, vNode, functions) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
function resolveFunctions(node, input, functions) {
|
|
149
|
+
let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`))
|
|
150
|
+
if (!hasAnyFn) return input
|
|
151
|
+
|
|
149
152
|
return parseValue(input)
|
|
150
153
|
.walk((vNode) => {
|
|
151
154
|
resolveVNode(node, vNode, functions)
|
|
@@ -553,6 +553,13 @@ function processApply(root, context, localCache) {
|
|
|
553
553
|
? parent.selector.slice(importantSelector.length)
|
|
554
554
|
: parent.selector
|
|
555
555
|
|
|
556
|
+
// If the selector becomes empty after replacing the important selector
|
|
557
|
+
// This means that it's the same as the parent selector and we don't want to replace it
|
|
558
|
+
// Otherwise we'll crash
|
|
559
|
+
if (parentSelector === '') {
|
|
560
|
+
parentSelector = parent.selector
|
|
561
|
+
}
|
|
562
|
+
|
|
556
563
|
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate)
|
|
557
564
|
|
|
558
565
|
// And then re-add it if it was removed
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
|
-
import LRU from 'quick-lru'
|
|
2
|
+
import LRU from '@alloc/quick-lru'
|
|
3
3
|
import * as sharedState from './sharedState'
|
|
4
4
|
import { generateRules } from './generateRules'
|
|
5
5
|
import log from '../util/log'
|
|
@@ -98,7 +98,7 @@ function buildStylesheet(rules, context) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export default function expandTailwindAtRules(context) {
|
|
101
|
-
return (root) => {
|
|
101
|
+
return async (root) => {
|
|
102
102
|
let layerNodes = {
|
|
103
103
|
base: null,
|
|
104
104
|
components: null,
|
|
@@ -130,7 +130,7 @@ export default function expandTailwindAtRules(context) {
|
|
|
130
130
|
|
|
131
131
|
env.DEBUG && console.time('Reading changed files')
|
|
132
132
|
|
|
133
|
-
if (
|
|
133
|
+
if (__OXIDE__) {
|
|
134
134
|
// TODO: Pass through or implement `extractor`
|
|
135
135
|
for (let candidate of require('@tailwindcss/oxide').parseCandidateStringsFromFiles(
|
|
136
136
|
context.changedContent
|
|
@@ -145,11 +145,25 @@ export default function expandTailwindAtRules(context) {
|
|
|
145
145
|
// getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen)
|
|
146
146
|
// }
|
|
147
147
|
} else {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
/** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */
|
|
149
|
+
let regexParserContent = []
|
|
150
|
+
|
|
151
|
+
for (let item of context.changedContent) {
|
|
152
|
+
let transformer = getTransformer(context.tailwindConfig, item.extension)
|
|
153
|
+
let extractor = getExtractor(context, item.extension)
|
|
154
|
+
regexParserContent.push([item, { transformer, extractor }])
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const BATCH_SIZE = 500
|
|
158
|
+
|
|
159
|
+
for (let i = 0; i < regexParserContent.length; i += BATCH_SIZE) {
|
|
160
|
+
let batch = regexParserContent.slice(i, i + BATCH_SIZE)
|
|
161
|
+
await Promise.all(
|
|
162
|
+
batch.map(async ([{ file, content }, { transformer, extractor }]) => {
|
|
163
|
+
content = file ? await fs.promises.readFile(file, 'utf8') : content
|
|
164
|
+
getClassCandidates(transformer(content), extractor, candidates, seen)
|
|
165
|
+
})
|
|
166
|
+
)
|
|
153
167
|
}
|
|
154
168
|
}
|
|
155
169
|
|
|
@@ -162,7 +176,7 @@ export default function expandTailwindAtRules(context) {
|
|
|
162
176
|
|
|
163
177
|
env.DEBUG && console.time('Generate rules')
|
|
164
178
|
env.DEBUG && console.time('Sorting candidates')
|
|
165
|
-
let sortedCandidates =
|
|
179
|
+
let sortedCandidates = __OXIDE__
|
|
166
180
|
? candidates
|
|
167
181
|
: new Set(
|
|
168
182
|
[...candidates].sort((a, z) => {
|
|
@@ -251,6 +265,9 @@ export default function expandTailwindAtRules(context) {
|
|
|
251
265
|
)
|
|
252
266
|
}
|
|
253
267
|
|
|
268
|
+
// TODO: Why is the root node having no source location for `end` possible?
|
|
269
|
+
root.source.end = root.source.end ?? root.source.start
|
|
270
|
+
|
|
254
271
|
// If we've got a utility layer and no utilities are generated there's likely something wrong
|
|
255
272
|
const hasUtilityVariants = variantNodes.some(
|
|
256
273
|
(node) => node.raws.tailwind?.parentLayer === 'utilities'
|
package/src/lib/generateRules.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from '../util/formatVariantSelector'
|
|
14
14
|
import { asClass } from '../util/nameClass'
|
|
15
15
|
import { normalize } from '../util/dataTypes'
|
|
16
|
-
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
|
|
16
|
+
import { isValidVariantFormatString, parseVariant, INTERNAL_FEATURES } from './setupContextUtils'
|
|
17
17
|
import isValidArbitraryValue from '../util/isSyntacticallyValidPropertyValue'
|
|
18
18
|
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
|
|
19
19
|
import { flagEnabled } from '../featureFlags'
|
|
@@ -119,10 +119,20 @@ function applyImportant(matches, classCandidate) {
|
|
|
119
119
|
|
|
120
120
|
let result = []
|
|
121
121
|
|
|
122
|
+
function isInKeyframes(rule) {
|
|
123
|
+
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes'
|
|
124
|
+
}
|
|
125
|
+
|
|
122
126
|
for (let [meta, rule] of matches) {
|
|
123
127
|
let container = postcss.root({ nodes: [rule.clone()] })
|
|
124
128
|
|
|
125
129
|
container.walkRules((r) => {
|
|
130
|
+
// Declarations inside keyframes cannot be marked as important
|
|
131
|
+
// They will be ignored by the browser
|
|
132
|
+
if (isInKeyframes(r)) {
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
126
136
|
let ast = selectorParser().astSync(r.selector)
|
|
127
137
|
|
|
128
138
|
// Remove extraneous selectors that do not include the base candidate
|
|
@@ -193,13 +203,13 @@ function applyVariant(variant, matches, context) {
|
|
|
193
203
|
// group[:hover] (`-` is missing)
|
|
194
204
|
let match = /(.)(-?)\[(.*)\]/g.exec(variant)
|
|
195
205
|
if (match) {
|
|
196
|
-
let [, char,
|
|
206
|
+
let [, char, separator, value] = match
|
|
197
207
|
// @-[200px] case
|
|
198
|
-
if (char === '@' &&
|
|
208
|
+
if (char === '@' && separator === '-') return []
|
|
199
209
|
// group[:hover] case
|
|
200
|
-
if (char !== '@' &&
|
|
210
|
+
if (char !== '@' && separator === '') return []
|
|
201
211
|
|
|
202
|
-
variant = variant.replace(`${
|
|
212
|
+
variant = variant.replace(`${separator}[${value}]`, '')
|
|
203
213
|
args.value = value
|
|
204
214
|
}
|
|
205
215
|
}
|
|
@@ -230,9 +240,16 @@ function applyVariant(variant, matches, context) {
|
|
|
230
240
|
|
|
231
241
|
if (context.variantMap.has(variant)) {
|
|
232
242
|
let isArbitraryVariant = isArbitraryValue(variant)
|
|
243
|
+
let internalFeatures = context.variantOptions.get(variant)?.[INTERNAL_FEATURES] ?? {}
|
|
233
244
|
let variantFunctionTuples = context.variantMap.get(variant).slice()
|
|
234
245
|
let result = []
|
|
235
246
|
|
|
247
|
+
let respectPrefix = (() => {
|
|
248
|
+
if (isArbitraryVariant) return false
|
|
249
|
+
if (internalFeatures.respectPrefix === false) return false
|
|
250
|
+
return true
|
|
251
|
+
})()
|
|
252
|
+
|
|
236
253
|
for (let [meta, rule] of matches) {
|
|
237
254
|
// Don't generate variants for user css
|
|
238
255
|
if (meta.layer === 'user') {
|
|
@@ -293,7 +310,7 @@ function applyVariant(variant, matches, context) {
|
|
|
293
310
|
format(selectorFormat) {
|
|
294
311
|
collectedFormats.push({
|
|
295
312
|
format: selectorFormat,
|
|
296
|
-
|
|
313
|
+
respectPrefix,
|
|
297
314
|
})
|
|
298
315
|
},
|
|
299
316
|
args,
|
|
@@ -322,7 +339,7 @@ function applyVariant(variant, matches, context) {
|
|
|
322
339
|
if (typeof ruleWithVariant === 'string') {
|
|
323
340
|
collectedFormats.push({
|
|
324
341
|
format: ruleWithVariant,
|
|
325
|
-
|
|
342
|
+
respectPrefix,
|
|
326
343
|
})
|
|
327
344
|
}
|
|
328
345
|
|
|
@@ -366,7 +383,7 @@ function applyVariant(variant, matches, context) {
|
|
|
366
383
|
// format: .foo &
|
|
367
384
|
collectedFormats.push({
|
|
368
385
|
format: modified.replace(rebuiltBase, '&'),
|
|
369
|
-
|
|
386
|
+
respectPrefix,
|
|
370
387
|
})
|
|
371
388
|
rule.selector = before
|
|
372
389
|
})
|
|
@@ -489,13 +506,13 @@ function extractArbitraryProperty(classCandidate, context) {
|
|
|
489
506
|
return null
|
|
490
507
|
}
|
|
491
508
|
|
|
492
|
-
let normalized = normalize(value)
|
|
509
|
+
let normalized = normalize(value, { property })
|
|
493
510
|
|
|
494
511
|
if (!isParsableCssValue(property, normalized)) {
|
|
495
512
|
return null
|
|
496
513
|
}
|
|
497
514
|
|
|
498
|
-
let sort = context.offsets.arbitraryProperty()
|
|
515
|
+
let sort = context.offsets.arbitraryProperty(classCandidate)
|
|
499
516
|
|
|
500
517
|
return [
|
|
501
518
|
[
|
|
@@ -566,7 +583,7 @@ function* recordCandidates(matches, classCandidate) {
|
|
|
566
583
|
}
|
|
567
584
|
}
|
|
568
585
|
|
|
569
|
-
function* resolveMatches(candidate, context
|
|
586
|
+
function* resolveMatches(candidate, context) {
|
|
570
587
|
let separator = context.tailwindConfig.separator
|
|
571
588
|
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
|
|
572
589
|
let important = false
|
|
@@ -576,15 +593,6 @@ function* resolveMatches(candidate, context, original = candidate) {
|
|
|
576
593
|
classCandidate = classCandidate.slice(1)
|
|
577
594
|
}
|
|
578
595
|
|
|
579
|
-
if (flagEnabled(context.tailwindConfig, 'variantGrouping')) {
|
|
580
|
-
if (classCandidate.startsWith('(') && classCandidate.endsWith(')')) {
|
|
581
|
-
let base = variants.slice().reverse().join(separator)
|
|
582
|
-
for (let part of splitAtTopLevelOnly(classCandidate.slice(1, -1), ',')) {
|
|
583
|
-
yield* resolveMatches(base + separator + part, context, original)
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
596
|
// TODO: Reintroduce this in ways that doesn't break on false positives
|
|
589
597
|
// function sortAgainst(toSort, against) {
|
|
590
598
|
// return toSort.slice().sort((a, z) => {
|
|
@@ -773,7 +781,7 @@ function* resolveMatches(candidate, context, original = candidate) {
|
|
|
773
781
|
match[1].raws.tailwind = { ...match[1].raws.tailwind, candidate }
|
|
774
782
|
|
|
775
783
|
// Apply final format selector
|
|
776
|
-
match = applyFinalFormat(match, { context, candidate
|
|
784
|
+
match = applyFinalFormat(match, { context, candidate })
|
|
777
785
|
|
|
778
786
|
// Skip rules with invalid selectors
|
|
779
787
|
// This will cause the candidate to be added to the "not class"
|
|
@@ -787,7 +795,7 @@ function* resolveMatches(candidate, context, original = candidate) {
|
|
|
787
795
|
}
|
|
788
796
|
}
|
|
789
797
|
|
|
790
|
-
function applyFinalFormat(match, { context, candidate
|
|
798
|
+
function applyFinalFormat(match, { context, candidate }) {
|
|
791
799
|
if (!match[0].collectedFormats) {
|
|
792
800
|
return match
|
|
793
801
|
}
|
|
@@ -822,10 +830,19 @@ function applyFinalFormat(match, { context, candidate, original }) {
|
|
|
822
830
|
}
|
|
823
831
|
|
|
824
832
|
try {
|
|
825
|
-
|
|
826
|
-
candidate
|
|
833
|
+
let selector = finalizeSelector(rule.selector, finalFormat, {
|
|
834
|
+
candidate,
|
|
827
835
|
context,
|
|
828
836
|
})
|
|
837
|
+
|
|
838
|
+
// Finalize Selector determined that this candidate is irrelevant
|
|
839
|
+
// TODO: This elimination should happen earlier so this never happens
|
|
840
|
+
if (selector === null) {
|
|
841
|
+
rule.remove()
|
|
842
|
+
return
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
rule.selector = selector
|
|
829
846
|
} catch {
|
|
830
847
|
// If this selector is invalid we also want to skip it
|
|
831
848
|
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content
|
|
@@ -838,6 +855,11 @@ function applyFinalFormat(match, { context, candidate, original }) {
|
|
|
838
855
|
return null
|
|
839
856
|
}
|
|
840
857
|
|
|
858
|
+
// If all rules have been eliminated we can skip this candidate entirely
|
|
859
|
+
if (container.nodes.length === 0) {
|
|
860
|
+
return null
|
|
861
|
+
}
|
|
862
|
+
|
|
841
863
|
match[1] = container.nodes[0]
|
|
842
864
|
|
|
843
865
|
return match
|
|
@@ -875,7 +897,7 @@ function getImportantStrategy(important) {
|
|
|
875
897
|
}
|
|
876
898
|
}
|
|
877
899
|
|
|
878
|
-
function generateRules(candidates, context) {
|
|
900
|
+
function generateRules(candidates, context, isSorting = false) {
|
|
879
901
|
let allRules = []
|
|
880
902
|
let strategy = getImportantStrategy(context.tailwindConfig.important)
|
|
881
903
|
|
|
@@ -910,7 +932,9 @@ function generateRules(candidates, context) {
|
|
|
910
932
|
rule = container.nodes[0]
|
|
911
933
|
}
|
|
912
934
|
|
|
913
|
-
|
|
935
|
+
// Note: We have to clone rules during sorting
|
|
936
|
+
// so we eliminate some shared mutable state
|
|
937
|
+
let newEntry = [sort, isSorting ? rule.clone() : rule]
|
|
914
938
|
rules.add(newEntry)
|
|
915
939
|
context.ruleCache.add(newEntry)
|
|
916
940
|
allRules.push(newEntry)
|
package/src/lib/load-config.ts
CHANGED
|
@@ -4,6 +4,14 @@ import { transform } from 'sucrase'
|
|
|
4
4
|
import { Config } from '../../types/config'
|
|
5
5
|
|
|
6
6
|
let jiti: ReturnType<typeof jitiFactory> | null = null
|
|
7
|
+
|
|
8
|
+
// @internal
|
|
9
|
+
// This WILL be removed in some future release
|
|
10
|
+
// If you rely on this your stuff WILL break
|
|
11
|
+
export function useCustomJiti(_jiti: () => ReturnType<typeof jitiFactory>) {
|
|
12
|
+
jiti = _jiti()
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
function lazyJiti() {
|
|
8
16
|
return (
|
|
9
17
|
jiti ??
|
package/src/lib/offsets.js
CHANGED
|
@@ -23,7 +23,9 @@ import { remapBitfield } from './remap-bitfield.js'
|
|
|
23
23
|
* @property {bigint} arbitrary 0n if false, 1n if true
|
|
24
24
|
* @property {bigint} variants Dynamic size. 1 bit per registered variant. 0n means no variants
|
|
25
25
|
* @property {bigint} parallelIndex Rule index for the parallel variant. 0 if not applicable.
|
|
26
|
-
* @property {bigint} index Index of the rule / utility in
|
|
26
|
+
* @property {bigint} index Index of the rule / utility in its given *parent* layer. Monotonically increasing.
|
|
27
|
+
* @property {bigint} propertyOffset Offset for the arbitrary property. Only valid after sorting.
|
|
28
|
+
* @property {string} property Name/Value of the arbitrary property.
|
|
27
29
|
* @property {VariantOption[]} options Some information on how we can sort arbitrary variants
|
|
28
30
|
*/
|
|
29
31
|
|
|
@@ -88,17 +90,21 @@ export class Offsets {
|
|
|
88
90
|
variants: 0n,
|
|
89
91
|
parallelIndex: 0n,
|
|
90
92
|
index: this.offsets[layer]++,
|
|
93
|
+
propertyOffset: 0n,
|
|
94
|
+
property: '',
|
|
91
95
|
options: [],
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
/**
|
|
100
|
+
* @param {string} name
|
|
96
101
|
* @returns {RuleOffset}
|
|
97
102
|
*/
|
|
98
|
-
arbitraryProperty() {
|
|
103
|
+
arbitraryProperty(name) {
|
|
99
104
|
return {
|
|
100
105
|
...this.create('utilities'),
|
|
101
106
|
arbitrary: 1n,
|
|
107
|
+
property: name,
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
|
|
@@ -262,6 +268,11 @@ export class Offsets {
|
|
|
262
268
|
return a.arbitrary - b.arbitrary
|
|
263
269
|
}
|
|
264
270
|
|
|
271
|
+
// Always sort arbitrary properties alphabetically
|
|
272
|
+
if (a.propertyOffset !== b.propertyOffset) {
|
|
273
|
+
return a.propertyOffset - b.propertyOffset
|
|
274
|
+
}
|
|
275
|
+
|
|
265
276
|
// Sort utilities, components, etc… in the order they were registered
|
|
266
277
|
return a.index - b.index
|
|
267
278
|
}
|
|
@@ -320,14 +331,62 @@ export class Offsets {
|
|
|
320
331
|
})
|
|
321
332
|
}
|
|
322
333
|
|
|
334
|
+
/**
|
|
335
|
+
* @template T
|
|
336
|
+
* @param {[RuleOffset, T][]} list
|
|
337
|
+
* @returns {[RuleOffset, T][]}
|
|
338
|
+
*/
|
|
339
|
+
sortArbitraryProperties(list) {
|
|
340
|
+
// Collect all known arbitrary properties
|
|
341
|
+
let known = new Set()
|
|
342
|
+
|
|
343
|
+
for (let [offset] of list) {
|
|
344
|
+
if (offset.arbitrary === 1n) {
|
|
345
|
+
known.add(offset.property)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// No arbitrary properties? Nothing to do.
|
|
350
|
+
if (known.size === 0) {
|
|
351
|
+
return list
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Sort the properties alphabetically
|
|
355
|
+
let properties = Array.from(known).sort()
|
|
356
|
+
|
|
357
|
+
// Create a map from the property name to its offset
|
|
358
|
+
let offsets = new Map()
|
|
359
|
+
|
|
360
|
+
let offset = 1n
|
|
361
|
+
for (let property of properties) {
|
|
362
|
+
offsets.set(property, offset++)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Apply the sorted offsets to the list
|
|
366
|
+
return list.map((item) => {
|
|
367
|
+
let [offset, rule] = item
|
|
368
|
+
|
|
369
|
+
offset = {
|
|
370
|
+
...offset,
|
|
371
|
+
propertyOffset: offsets.get(offset.property) ?? 0n,
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return [offset, rule]
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
|
|
323
378
|
/**
|
|
324
379
|
* @template T
|
|
325
380
|
* @param {[RuleOffset, T][]} list
|
|
326
381
|
* @returns {[RuleOffset, T][]}
|
|
327
382
|
*/
|
|
328
383
|
sort(list) {
|
|
384
|
+
// Sort arbitrary variants so they're in alphabetical order
|
|
329
385
|
list = this.remapArbitraryVariantOffsets(list)
|
|
330
386
|
|
|
387
|
+
// Sort arbitrary properties so they're in alphabetical order
|
|
388
|
+
list = this.sortArbitraryProperties(list)
|
|
389
|
+
|
|
331
390
|
return list.sort(([a], [b]) => bigSign(this.compare(a, b)))
|
|
332
391
|
}
|
|
333
392
|
}
|
|
@@ -104,8 +104,12 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) {
|
|
|
104
104
|
// we consider them separately because merging the declarations into
|
|
105
105
|
// a single rule will cause browsers that do not understand the
|
|
106
106
|
// vendor prefix to throw out the whole rule
|
|
107
|
+
// Additionally if a selector contains `:has` we also consider
|
|
108
|
+
// it separately because FF only recently gained support for it
|
|
107
109
|
let selectorGroupName =
|
|
108
|
-
selector.includes(':-') || selector.includes('::-')
|
|
110
|
+
selector.includes(':-') || selector.includes('::-') || selector.includes(':has')
|
|
111
|
+
? selector
|
|
112
|
+
: '__DEFAULT__'
|
|
109
113
|
|
|
110
114
|
let selectors = selectorGroups.get(selectorGroupName) ?? new Set()
|
|
111
115
|
selectorGroups.set(selectorGroupName, selectors)
|