tailwindcss 0.0.0-insiders.ea10bb9 → 0.0.0-insiders.ea4e1cd
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 +1 -1
- package/lib/cli/build/deps.js +17 -9
- package/lib/cli/build/index.js +20 -10
- package/lib/cli/build/plugin.js +86 -70
- package/lib/cli/build/utils.js +18 -8
- package/lib/cli/build/watching.js +16 -12
- package/lib/cli/help/index.js +6 -4
- package/lib/cli/index.js +222 -10
- package/lib/cli/init/index.js +29 -12
- package/lib/cli-peer-dependencies.js +12 -4
- package/lib/cli.js +4 -226
- package/lib/corePluginList.js +7 -1
- package/lib/corePlugins.js +348 -75
- package/lib/css/preflight.css +2 -0
- package/lib/featureFlags.js +27 -15
- package/lib/index.js +1 -47
- package/lib/lib/cacheInvalidation.js +7 -5
- package/lib/lib/collapseAdjacentRules.js +5 -3
- package/lib/lib/collapseDuplicateDeclarations.js +12 -10
- package/lib/lib/content.js +34 -30
- package/lib/lib/defaultExtractor.js +15 -8
- package/lib/lib/detectNesting.js +10 -2
- package/lib/lib/evaluateTailwindFunctions.js +22 -20
- package/lib/lib/expandApplyAtRules.js +43 -35
- package/lib/lib/expandTailwindAtRules.js +46 -19
- package/lib/lib/findAtConfigPath.js +9 -7
- package/lib/lib/generateRules.js +157 -92
- package/lib/lib/getModuleDependencies.js +85 -37
- package/lib/lib/load-config.js +42 -0
- package/lib/lib/normalizeTailwindDirectives.js +5 -3
- package/lib/lib/offsets.js +93 -4
- package/lib/lib/partitionApplyAtRules.js +3 -1
- package/lib/lib/regex.js +21 -7
- package/lib/lib/remap-bitfield.js +89 -0
- package/lib/lib/resolveDefaultsAtRules.js +28 -24
- package/lib/lib/setupContextUtils.js +190 -131
- package/lib/lib/setupTrackingContext.js +49 -26
- package/lib/lib/sharedState.js +37 -10
- package/lib/lib/substituteScreenAtRules.js +5 -3
- package/lib/oxide/cli/build/deps.js +89 -0
- package/lib/oxide/cli/build/index.js +53 -0
- package/lib/oxide/cli/build/plugin.js +375 -0
- package/lib/oxide/cli/build/utils.js +87 -0
- package/lib/oxide/cli/build/watching.js +179 -0
- package/lib/oxide/cli/help/index.js +72 -0
- package/lib/oxide/cli/index.js +214 -0
- package/lib/oxide/cli/init/index.js +52 -0
- package/lib/oxide/cli.js +5 -0
- package/lib/oxide/postcss-plugin.js +2 -0
- package/lib/plugin.js +98 -0
- package/lib/postcss-plugins/nesting/index.js +3 -1
- package/lib/postcss-plugins/nesting/plugin.js +10 -8
- package/lib/processTailwindFeatures.js +14 -12
- package/lib/public/colors.js +49 -25
- 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 +12 -0
- package/lib/public/resolve-config.js +6 -4
- package/lib/util/applyImportantSelector.js +36 -0
- 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 +5 -3
- package/lib/util/color.js +30 -12
- 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 +7 -5
- package/lib/util/dataTypes.js +74 -17
- package/lib/util/defaults.js +9 -7
- package/lib/util/escapeClassName.js +10 -8
- package/lib/util/escapeCommas.js +3 -1
- package/lib/util/flattenColorPalette.js +3 -1
- package/lib/util/formatVariantSelector.js +138 -160
- package/lib/util/getAllConfigs.js +8 -6
- package/lib/util/hashConfig.js +6 -4
- package/lib/util/isKeyframeRule.js +3 -1
- package/lib/util/isPlainObject.js +3 -1
- 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 +4 -2
- package/lib/util/normalizeConfig.js +28 -27
- 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 +54 -54
- package/lib/util/prefixSelector.js +27 -11
- package/lib/util/pseudoElements.js +229 -0
- package/lib/util/removeAlphaVariables.js +3 -1
- package/lib/util/resolveConfig.js +17 -15
- package/lib/util/resolveConfigPath.js +26 -10
- package/lib/util/responsive.js +6 -4
- package/lib/util/splitAtTopLevelOnly.js +10 -2
- 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 +16 -3
- package/lib/util/validateFormalSyntax.js +3 -1
- package/lib/util/withAlphaVariable.js +6 -2
- package/loadConfig.d.ts +4 -0
- package/loadConfig.js +2 -0
- package/package.json +45 -37
- package/peers/index.js +63324 -46417
- package/resolveConfig.d.ts +11 -2
- package/scripts/swap-engines.js +40 -0
- package/src/cli/build/index.js +13 -9
- package/src/cli/build/plugin.js +42 -32
- package/src/cli/build/watching.js +4 -2
- package/src/cli/index.js +216 -3
- package/src/cli/init/index.js +37 -8
- package/src/cli.js +4 -220
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +207 -32
- package/src/css/preflight.css +2 -0
- package/src/featureFlags.js +6 -0
- package/src/index.js +1 -47
- package/src/lib/content.js +12 -17
- package/src/lib/defaultExtractor.js +9 -3
- package/src/lib/detectNesting.js +9 -1
- package/src/lib/expandApplyAtRules.js +8 -1
- package/src/lib/expandTailwindAtRules.js +36 -7
- package/src/lib/generateRules.js +124 -42
- package/src/lib/getModuleDependencies.js +70 -30
- package/src/lib/load-config.ts +31 -0
- package/src/lib/offsets.js +104 -1
- package/src/lib/remap-bitfield.js +82 -0
- package/src/lib/setupContextUtils.js +103 -54
- package/src/lib/setupTrackingContext.js +36 -11
- package/src/lib/sharedState.js +15 -4
- package/src/oxide/cli/build/deps.ts +91 -0
- package/src/oxide/cli/build/index.ts +47 -0
- package/src/oxide/cli/build/plugin.ts +442 -0
- package/src/oxide/cli/build/utils.ts +74 -0
- package/src/oxide/cli/build/watching.ts +225 -0
- package/src/oxide/cli/help/index.ts +69 -0
- package/src/oxide/cli/index.ts +204 -0
- package/src/oxide/cli/init/index.ts +59 -0
- package/src/oxide/cli.ts +1 -0
- package/src/oxide/postcss-plugin.ts +1 -0
- package/src/plugin.js +107 -0
- 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/color.js +18 -3
- package/src/util/colorNames.js +150 -0
- package/src/util/dataTypes.js +33 -4
- package/src/util/formatVariantSelector.js +160 -163
- package/src/util/getAllConfigs.js +2 -2
- package/src/util/negateValue.js +1 -1
- package/src/util/normalizeConfig.js +2 -1
- package/src/util/pluginUtils.js +16 -31
- package/src/util/prefixSelector.js +28 -10
- package/src/util/pseudoElements.js +170 -0
- package/src/util/resolveConfigPath.js +12 -1
- package/src/util/splitAtTopLevelOnly.js +8 -1
- package/src/util/validateConfig.js +13 -0
- package/stubs/.gitignore +1 -0
- package/stubs/.prettierrc.json +6 -0
- package/stubs/{defaultConfig.stub.js → config.full.js} +183 -146
- package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -1
- package/stubs/postcss.config.js +6 -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 +15 -9
- package/types/generated/colors.d.ts +22 -0
- package/types/generated/corePluginList.d.ts +1 -1
- package/types/generated/default-theme.d.ts +108 -79
- package/CHANGELOG.md +0 -2336
- package/lib/cli/shared.js +0 -12
- package/lib/constants.js +0 -44
- package/scripts/install-integrations.js +0 -27
- package/scripts/rebuildFixtures.js +0 -68
- package/src/cli/shared.js +0 -5
- package/src/constants.js +0 -17
- /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
|
@@ -2,31 +2,59 @@ import selectorParser from 'postcss-selector-parser'
|
|
|
2
2
|
import unescape from 'postcss-selector-parser/dist/util/unesc'
|
|
3
3
|
import escapeClassName from '../util/escapeClassName'
|
|
4
4
|
import prefixSelector from '../util/prefixSelector'
|
|
5
|
+
import { movePseudos } from './pseudoElements'
|
|
6
|
+
|
|
7
|
+
/** @typedef {import('postcss-selector-parser').Root} Root */
|
|
8
|
+
/** @typedef {import('postcss-selector-parser').Selector} Selector */
|
|
9
|
+
/** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */
|
|
10
|
+
/** @typedef {import('postcss-selector-parser').Node} Node */
|
|
11
|
+
|
|
12
|
+
/** @typedef {{format: string, isArbitraryVariant: boolean}[]} RawFormats */
|
|
13
|
+
/** @typedef {import('postcss-selector-parser').Root} ParsedFormats */
|
|
14
|
+
/** @typedef {RawFormats | ParsedFormats} AcceptedFormats */
|
|
5
15
|
|
|
6
16
|
let MERGE = ':merge'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {RawFormats} formats
|
|
20
|
+
* @param {{context: any, candidate: string, base: string | null}} options
|
|
21
|
+
* @returns {ParsedFormats | null}
|
|
22
|
+
*/
|
|
23
|
+
export function formatVariantSelector(formats, { context, candidate }) {
|
|
24
|
+
let prefix = context?.tailwindConfig.prefix ?? ''
|
|
25
|
+
|
|
26
|
+
// Parse the format selector into an AST
|
|
27
|
+
let parsedFormats = formats.map((format) => {
|
|
28
|
+
let ast = selectorParser().astSync(format.format)
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
...format,
|
|
32
|
+
ast: format.isArbitraryVariant ? ast : prefixSelector(prefix, ast),
|
|
24
33
|
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// We start with the candidate selector
|
|
37
|
+
let formatAst = selectorParser.root({
|
|
38
|
+
nodes: [
|
|
39
|
+
selectorParser.selector({
|
|
40
|
+
nodes: [selectorParser.className({ value: escapeClassName(candidate) })],
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
})
|
|
25
44
|
|
|
26
|
-
|
|
45
|
+
// And iteratively merge each format selector into the candidate selector
|
|
46
|
+
for (let { ast } of parsedFormats) {
|
|
47
|
+
// 1. Handle :merge() special pseudo-class
|
|
48
|
+
;[formatAst, ast] = handleMergePseudo(formatAst, ast)
|
|
49
|
+
|
|
50
|
+
// 2. Merge the format selector into the current selector AST
|
|
51
|
+
ast.walkNesting((nesting) => nesting.replaceWith(...formatAst.nodes[0].nodes))
|
|
52
|
+
|
|
53
|
+
// 3. Keep going!
|
|
54
|
+
formatAst = ast
|
|
27
55
|
}
|
|
28
56
|
|
|
29
|
-
return
|
|
57
|
+
return formatAst
|
|
30
58
|
}
|
|
31
59
|
|
|
32
60
|
/**
|
|
@@ -35,11 +63,11 @@ export function formatVariantSelector(current, ...others) {
|
|
|
35
63
|
* Technically :is(), :not(), :has(), etc… can have combinators but those are nested
|
|
36
64
|
* inside the relevant node and won't be picked up so they're fine to ignore
|
|
37
65
|
*
|
|
38
|
-
* @param {
|
|
39
|
-
* @returns {
|
|
66
|
+
* @param {Node} node
|
|
67
|
+
* @returns {Node[]}
|
|
40
68
|
**/
|
|
41
69
|
function simpleSelectorForNode(node) {
|
|
42
|
-
/** @type {
|
|
70
|
+
/** @type {Node[]} */
|
|
43
71
|
let nodes = []
|
|
44
72
|
|
|
45
73
|
// Walk backwards until we hit a combinator node (or the start)
|
|
@@ -60,8 +88,8 @@ function simpleSelectorForNode(node) {
|
|
|
60
88
|
* Resorts the nodes in a selector to ensure they're in the correct order
|
|
61
89
|
* Tags go before classes, and pseudo classes go after classes
|
|
62
90
|
*
|
|
63
|
-
* @param {
|
|
64
|
-
* @returns {
|
|
91
|
+
* @param {Selector} sel
|
|
92
|
+
* @returns {Selector}
|
|
65
93
|
**/
|
|
66
94
|
function resortSelector(sel) {
|
|
67
95
|
sel.sort((a, b) => {
|
|
@@ -81,7 +109,19 @@ function resortSelector(sel) {
|
|
|
81
109
|
return sel
|
|
82
110
|
}
|
|
83
111
|
|
|
84
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Remove extraneous selectors that do not include the base class/candidate
|
|
114
|
+
*
|
|
115
|
+
* Example:
|
|
116
|
+
* Given the utility `.a, .b { color: red}`
|
|
117
|
+
* Given the candidate `sm:b`
|
|
118
|
+
*
|
|
119
|
+
* The final selector should be `.sm\:b` and not `.a, .sm\:b`
|
|
120
|
+
*
|
|
121
|
+
* @param {Selector} ast
|
|
122
|
+
* @param {string} base
|
|
123
|
+
*/
|
|
124
|
+
export function eliminateIrrelevantSelectors(sel, base) {
|
|
85
125
|
let hasClassesMatchingCandidate = false
|
|
86
126
|
|
|
87
127
|
sel.walk((child) => {
|
|
@@ -104,41 +144,26 @@ function eliminateIrrelevantSelectors(sel, base) {
|
|
|
104
144
|
// TODO: Can we do this for :matches, :is, and :where?
|
|
105
145
|
}
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
.pop(),
|
|
125
|
-
}
|
|
126
|
-
) {
|
|
127
|
-
let ast = selectorParser().astSync(selector)
|
|
128
|
-
|
|
129
|
-
// We explicitly DO NOT prefix classes in arbitrary variants
|
|
130
|
-
if (context?.tailwindConfig?.prefix && !isArbitraryVariant) {
|
|
131
|
-
format = prefixSelector(context.tailwindConfig.prefix, format)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
format = format.replace(PARENT, `.${escapeClassName(candidate)}`)
|
|
135
|
-
|
|
136
|
-
let formatAst = selectorParser().astSync(format)
|
|
147
|
+
/**
|
|
148
|
+
* @param {string} current
|
|
149
|
+
* @param {AcceptedFormats} formats
|
|
150
|
+
* @param {{context: any, candidate: string, base: string | null}} options
|
|
151
|
+
* @returns {string}
|
|
152
|
+
*/
|
|
153
|
+
export function finalizeSelector(current, formats, { context, candidate, base }) {
|
|
154
|
+
let separator = context?.tailwindConfig?.separator ?? ':'
|
|
155
|
+
|
|
156
|
+
// Split by the separator, but ignore the separator inside square brackets:
|
|
157
|
+
//
|
|
158
|
+
// E.g.: dark:lg:hover:[paint-order:markers]
|
|
159
|
+
// ┬ ┬ ┬ ┬
|
|
160
|
+
// │ │ │ ╰── We will not split here
|
|
161
|
+
// ╰──┴─────┴─────────────── We will split here
|
|
162
|
+
//
|
|
163
|
+
base = base ?? candidate.split(new RegExp(`\\${separator}(?![^[]*\\])`)).pop()
|
|
137
164
|
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
// And the formatted variant is sm:b then we want the final selector to be `.sm\:b` and not `.a, .sm\:b`
|
|
141
|
-
ast.each((sel) => eliminateIrrelevantSelectors(sel, base))
|
|
165
|
+
// Parse the selector into an AST
|
|
166
|
+
let selector = selectorParser().astSync(current)
|
|
142
167
|
|
|
143
168
|
// Normalize escaped classes, e.g.:
|
|
144
169
|
//
|
|
@@ -151,18 +176,31 @@ export function finalizeSelector(
|
|
|
151
176
|
// base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
|
|
152
177
|
// escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
|
|
153
178
|
//
|
|
154
|
-
|
|
179
|
+
selector.walkClasses((node) => {
|
|
155
180
|
if (node.raws && node.value.includes(base)) {
|
|
156
181
|
node.raws.value = escapeClassName(unescape(node.raws.value))
|
|
157
182
|
}
|
|
158
183
|
})
|
|
159
184
|
|
|
185
|
+
// Remove extraneous selectors that do not include the base candidate
|
|
186
|
+
selector.each((sel) => eliminateIrrelevantSelectors(sel, base))
|
|
187
|
+
|
|
188
|
+
// If there are no formats that means there were no variants added to the candidate
|
|
189
|
+
// so we can just return the selector as-is
|
|
190
|
+
let formatAst = Array.isArray(formats)
|
|
191
|
+
? formatVariantSelector(formats, { context, candidate })
|
|
192
|
+
: formats
|
|
193
|
+
|
|
194
|
+
if (formatAst === null) {
|
|
195
|
+
return selector.toString()
|
|
196
|
+
}
|
|
197
|
+
|
|
160
198
|
let simpleStart = selectorParser.comment({ value: '/*__simple__*/' })
|
|
161
199
|
let simpleEnd = selectorParser.comment({ value: '/*__simple__*/' })
|
|
162
200
|
|
|
163
201
|
// We can safely replace the escaped base now, since the `base` section is
|
|
164
202
|
// now in a normalized escaped value.
|
|
165
|
-
|
|
203
|
+
selector.walkClasses((node) => {
|
|
166
204
|
if (node.value !== base) {
|
|
167
205
|
return
|
|
168
206
|
}
|
|
@@ -181,7 +219,7 @@ export function finalizeSelector(
|
|
|
181
219
|
parent.insertAfter(simpleSelector[simpleSelector.length - 1], simpleEnd)
|
|
182
220
|
|
|
183
221
|
for (let child of formatNodes) {
|
|
184
|
-
parent.insertBefore(simpleSelector[0], child)
|
|
222
|
+
parent.insertBefore(simpleSelector[0], child.clone())
|
|
185
223
|
}
|
|
186
224
|
|
|
187
225
|
node.remove()
|
|
@@ -200,120 +238,79 @@ export function finalizeSelector(
|
|
|
200
238
|
simpleEnd.remove()
|
|
201
239
|
})
|
|
202
240
|
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
// E.g.:
|
|
208
|
-
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before`
|
|
209
|
-
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before`
|
|
210
|
-
//
|
|
211
|
-
// `::before:hover` doesn't work, which means that we can make it work for you by flipping the order.
|
|
212
|
-
function collectPseudoElements(selector) {
|
|
213
|
-
let nodes = []
|
|
214
|
-
|
|
215
|
-
for (let node of selector.nodes) {
|
|
216
|
-
if (isPseudoElement(node)) {
|
|
217
|
-
nodes.push(node)
|
|
218
|
-
selector.removeChild(node)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (node?.nodes) {
|
|
222
|
-
nodes.push(...collectPseudoElements(node))
|
|
223
|
-
}
|
|
241
|
+
// Remove unnecessary pseudo selectors that we used as placeholders
|
|
242
|
+
selector.walkPseudos((p) => {
|
|
243
|
+
if (p.value === MERGE) {
|
|
244
|
+
p.replaceWith(p.nodes)
|
|
224
245
|
}
|
|
246
|
+
})
|
|
225
247
|
|
|
226
|
-
|
|
227
|
-
|
|
248
|
+
// Move pseudo elements to the end of the selector (if necessary)
|
|
249
|
+
selector.each((sel) => movePseudos(sel))
|
|
228
250
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
251
|
+
return selector.toString()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
*
|
|
256
|
+
* @param {Selector} selector
|
|
257
|
+
* @param {Selector} format
|
|
258
|
+
*/
|
|
259
|
+
export function handleMergePseudo(selector, format) {
|
|
260
|
+
/** @type {{pseudo: Pseudo, value: string}[]} */
|
|
261
|
+
let merges = []
|
|
262
|
+
|
|
263
|
+
// Find all :merge() pseudo-classes in `selector`
|
|
264
|
+
selector.walkPseudos((pseudo) => {
|
|
265
|
+
if (pseudo.value === MERGE) {
|
|
266
|
+
merges.push({
|
|
267
|
+
pseudo,
|
|
268
|
+
value: pseudo.nodes[0].toString(),
|
|
269
|
+
})
|
|
240
270
|
}
|
|
241
271
|
})
|
|
242
272
|
|
|
243
|
-
|
|
244
|
-
|
|
273
|
+
// Find all :merge() "attachments" in `format` and attach them to the matching selector in `selector`
|
|
274
|
+
format.walkPseudos((pseudo) => {
|
|
275
|
+
if (pseudo.value !== MERGE) {
|
|
276
|
+
return
|
|
277
|
+
}
|
|
245
278
|
|
|
246
|
-
|
|
247
|
-
// (:). This distinguishes pseudo-classes from pseudo-elements. However, since
|
|
248
|
-
// this distinction was not present in older versions of the W3C spec, most
|
|
249
|
-
// browsers support both syntaxes for the original pseudo-elements.
|
|
250
|
-
let pseudoElementsBC = [':before', ':after', ':first-line', ':first-letter']
|
|
251
|
-
|
|
252
|
-
// These pseudo-elements _can_ be combined with other pseudo selectors AND the order does matter.
|
|
253
|
-
let pseudoElementExceptions = ['::file-selector-button']
|
|
254
|
-
|
|
255
|
-
// This will make sure to move pseudo's to the correct spot (the end for
|
|
256
|
-
// pseudo elements) because otherwise the selector will never work
|
|
257
|
-
// anyway.
|
|
258
|
-
//
|
|
259
|
-
// E.g.:
|
|
260
|
-
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before`
|
|
261
|
-
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before`
|
|
262
|
-
//
|
|
263
|
-
// `::before:hover` doesn't work, which means that we can make it work
|
|
264
|
-
// for you by flipping the order.
|
|
265
|
-
function sortSelector(a, z) {
|
|
266
|
-
// Both nodes are non-pseudo's so we can safely ignore them and keep
|
|
267
|
-
// them in the same order.
|
|
268
|
-
if (a.type !== 'pseudo' && z.type !== 'pseudo') {
|
|
269
|
-
return 0
|
|
270
|
-
}
|
|
279
|
+
let value = pseudo.nodes[0].toString()
|
|
271
280
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if ((a.type === 'combinator') ^ (z.type === 'combinator')) {
|
|
275
|
-
return 0
|
|
276
|
-
}
|
|
281
|
+
// Does `selector` contain a :merge() pseudo-class with the same value?
|
|
282
|
+
let existing = merges.find((merge) => merge.value === value)
|
|
277
283
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
284
|
+
// Nope so there's nothing to do
|
|
285
|
+
if (!existing) {
|
|
286
|
+
return
|
|
287
|
+
}
|
|
283
288
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
289
|
+
// Everything after `:merge()` up to the next combinator is what is attached to the merged selector
|
|
290
|
+
let attachments = []
|
|
291
|
+
let next = pseudo.next()
|
|
292
|
+
while (next && next.type !== 'combinator') {
|
|
293
|
+
attachments.push(next)
|
|
294
|
+
next = next.next()
|
|
295
|
+
}
|
|
288
296
|
|
|
289
|
-
|
|
290
|
-
if (node.type !== 'pseudo') return false
|
|
291
|
-
if (pseudoElementExceptions.includes(node.value)) return false
|
|
297
|
+
let combinator = next
|
|
292
298
|
|
|
293
|
-
|
|
294
|
-
|
|
299
|
+
existing.pseudo.parent.insertAfter(
|
|
300
|
+
existing.pseudo,
|
|
301
|
+
selectorParser.selector({ nodes: attachments.map((node) => node.clone()) })
|
|
302
|
+
)
|
|
295
303
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
let count = 0
|
|
305
|
-
|
|
306
|
-
for (let char of haystack.slice(startIdx)) {
|
|
307
|
-
if (char !== '(' && char !== ')') {
|
|
308
|
-
target += char
|
|
309
|
-
} else if (char === '(') {
|
|
310
|
-
target += char
|
|
311
|
-
count++
|
|
312
|
-
} else if (char === ')') {
|
|
313
|
-
if (--count < 0) break // unbalanced
|
|
314
|
-
target += char
|
|
304
|
+
pseudo.remove()
|
|
305
|
+
attachments.forEach((node) => node.remove())
|
|
306
|
+
|
|
307
|
+
// What about this case:
|
|
308
|
+
// :merge(.group):focus > &
|
|
309
|
+
// :merge(.group):hover &
|
|
310
|
+
if (combinator && combinator.type === 'combinator') {
|
|
311
|
+
combinator.remove()
|
|
315
312
|
}
|
|
316
|
-
}
|
|
313
|
+
})
|
|
317
314
|
|
|
318
|
-
return
|
|
315
|
+
return [selector, format]
|
|
319
316
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import defaultFullConfig from '../../stubs/config.full.js'
|
|
2
2
|
import { flagEnabled } from '../featureFlags'
|
|
3
3
|
|
|
4
4
|
export default function getAllConfigs(config) {
|
|
5
|
-
const configs = (config?.presets ?? [
|
|
5
|
+
const configs = (config?.presets ?? [defaultFullConfig])
|
|
6
6
|
.slice()
|
|
7
7
|
.reverse()
|
|
8
8
|
.flatMap((preset) => getAllConfigs(preset instanceof Function ? preset() : preset))
|
package/src/util/negateValue.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { flagEnabled } from '../featureFlags'
|
|
1
2
|
import log, { dim } from './log'
|
|
2
3
|
|
|
3
4
|
export function normalizeConfig(config) {
|
|
@@ -189,7 +190,7 @@ export function normalizeConfig(config) {
|
|
|
189
190
|
return content.relative
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
return config
|
|
193
|
+
return flagEnabled(config, 'relativeContentPathsByDefault')
|
|
193
194
|
})(),
|
|
194
195
|
|
|
195
196
|
files: (() => {
|
package/src/util/pluginUtils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import selectorParser from 'postcss-selector-parser'
|
|
2
1
|
import escapeCommas from './escapeCommas'
|
|
3
2
|
import { withAlphaValue } from './withAlphaVariable'
|
|
4
3
|
import {
|
|
@@ -21,37 +20,19 @@ import negateValue from './negateValue'
|
|
|
21
20
|
import { backgroundSize } from './validateFormalSyntax'
|
|
22
21
|
import { flagEnabled } from '../featureFlags.js'
|
|
23
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @param {import('postcss-selector-parser').Container} selectors
|
|
25
|
+
* @param {(className: string) => string} updateClass
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
24
28
|
export function updateAllClasses(selectors, updateClass) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let updatedClass = updateClass(sel.value)
|
|
28
|
-
sel.value = updatedClass
|
|
29
|
-
if (sel.raws && sel.raws.value) {
|
|
30
|
-
sel.raws.value = escapeCommas(sel.raws.value)
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
let result = parser.processSync(selectors)
|
|
36
|
-
|
|
37
|
-
return result
|
|
38
|
-
}
|
|
29
|
+
selectors.walkClasses((sel) => {
|
|
30
|
+
sel.value = updateClass(sel.value)
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const containsClass = sel.nodes.some(
|
|
44
|
-
(node) => node.type === 'class' && node.value === classCandidate
|
|
45
|
-
)
|
|
46
|
-
if (!containsClass) {
|
|
47
|
-
sel.remove()
|
|
48
|
-
}
|
|
49
|
-
})
|
|
32
|
+
if (sel.raws && sel.raws.value) {
|
|
33
|
+
sel.raws.value = escapeCommas(sel.raws.value)
|
|
34
|
+
}
|
|
50
35
|
})
|
|
51
|
-
|
|
52
|
-
let result = parser.processSync(selectors)
|
|
53
|
-
|
|
54
|
-
return result
|
|
55
36
|
}
|
|
56
37
|
|
|
57
38
|
function resolveArbitraryValue(modifier, validate) {
|
|
@@ -133,6 +114,10 @@ export function parseColorFormat(value) {
|
|
|
133
114
|
return value
|
|
134
115
|
}
|
|
135
116
|
|
|
117
|
+
function unwrapArbitraryModifier(modifier) {
|
|
118
|
+
return normalize(modifier.slice(1, -1))
|
|
119
|
+
}
|
|
120
|
+
|
|
136
121
|
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
|
|
137
122
|
if (options.values?.[modifier] !== undefined) {
|
|
138
123
|
return parseColorFormat(options.values?.[modifier])
|
|
@@ -153,7 +138,7 @@ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
|
|
|
153
138
|
normalizedColor = parseColorFormat(normalizedColor)
|
|
154
139
|
|
|
155
140
|
if (isArbitraryValue(alpha)) {
|
|
156
|
-
return withAlphaValue(normalizedColor, alpha
|
|
141
|
+
return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha))
|
|
157
142
|
}
|
|
158
143
|
|
|
159
144
|
if (tailwindConfig.theme?.opacity?.[alpha] === undefined) {
|
|
@@ -287,7 +272,7 @@ export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
|
|
|
287
272
|
if (configValue !== null) {
|
|
288
273
|
utilityModifier = configValue
|
|
289
274
|
} else if (isArbitraryValue(utilityModifier)) {
|
|
290
|
-
utilityModifier = utilityModifier
|
|
275
|
+
utilityModifier = unwrapArbitraryModifier(utilityModifier)
|
|
291
276
|
}
|
|
292
277
|
}
|
|
293
278
|
}
|
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
import parser from 'postcss-selector-parser'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @template {string | import('postcss-selector-parser').Root} T
|
|
5
|
+
*
|
|
6
|
+
* Prefix all classes in the selector with the given prefix
|
|
7
|
+
*
|
|
8
|
+
* It can take either a string or a selector AST and will return the same type
|
|
9
|
+
*
|
|
10
|
+
* @param {string} prefix
|
|
11
|
+
* @param {T} selector
|
|
12
|
+
* @param {boolean} prependNegative
|
|
13
|
+
* @returns {T}
|
|
14
|
+
*/
|
|
3
15
|
export default function (prefix, selector, prependNegative = false) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
if (prefix === '') {
|
|
17
|
+
return selector
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let ast = typeof selector === 'string' ? parser().astSync(selector) : selector
|
|
21
|
+
|
|
22
|
+
ast.walkClasses((classSelector) => {
|
|
23
|
+
let baseClass = classSelector.value
|
|
24
|
+
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-')
|
|
25
|
+
|
|
26
|
+
classSelector.value = shouldPlaceNegativeBeforePrefix
|
|
27
|
+
? `-${prefix}${baseClass.slice(1)}`
|
|
28
|
+
: `${prefix}${baseClass}`
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return typeof selector === 'string' ? ast.toString() : ast
|
|
14
32
|
}
|