tailwindcss 3.0.22 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -2
- package/colors.d.ts +3 -0
- package/defaultConfig.d.ts +3 -0
- package/defaultTheme.d.ts +3 -0
- package/lib/cli-peer-dependencies.js +10 -5
- package/lib/cli.js +266 -203
- package/lib/constants.js +8 -8
- package/lib/corePluginList.js +1 -0
- package/lib/corePlugins.js +1662 -1554
- package/lib/css/preflight.css +1 -8
- package/lib/featureFlags.js +14 -12
- package/lib/index.js +16 -6
- package/lib/lib/cacheInvalidation.js +87 -0
- package/lib/lib/collapseAdjacentRules.js +30 -15
- package/lib/lib/collapseDuplicateDeclarations.js +1 -1
- package/lib/lib/defaultExtractor.js +191 -30
- package/lib/lib/detectNesting.js +9 -9
- package/lib/lib/evaluateTailwindFunctions.js +37 -28
- package/lib/lib/expandApplyAtRules.js +379 -189
- package/lib/lib/expandTailwindAtRules.js +168 -144
- package/lib/lib/generateRules.js +190 -81
- package/lib/lib/getModuleDependencies.js +14 -14
- package/lib/lib/normalizeTailwindDirectives.js +35 -35
- package/lib/lib/partitionApplyAtRules.js +7 -7
- package/lib/lib/regex.js +52 -0
- package/lib/lib/resolveDefaultsAtRules.js +80 -79
- package/lib/lib/setupContextUtils.js +207 -170
- package/lib/lib/setupTrackingContext.js +61 -63
- package/lib/lib/sharedState.js +11 -8
- package/lib/lib/substituteScreenAtRules.js +3 -4
- package/lib/postcss-plugins/nesting/README.md +2 -2
- package/lib/postcss-plugins/nesting/index.js +1 -1
- package/lib/postcss-plugins/nesting/plugin.js +40 -9
- package/lib/processTailwindFeatures.js +7 -7
- package/lib/public/colors.js +241 -241
- package/lib/public/resolve-config.js +5 -5
- package/lib/util/buildMediaQuery.js +2 -3
- package/lib/util/cloneDeep.js +3 -5
- package/lib/util/cloneNodes.js +12 -1
- package/lib/util/color.js +42 -51
- package/lib/util/createPlugin.js +1 -2
- package/lib/util/createUtilityPlugin.js +6 -7
- package/lib/util/dataTypes.js +85 -81
- package/lib/util/escapeClassName.js +5 -5
- package/lib/util/escapeCommas.js +1 -1
- package/lib/util/flattenColorPalette.js +4 -7
- package/lib/util/formatVariantSelector.js +82 -75
- package/lib/util/getAllConfigs.js +15 -10
- package/lib/util/hashConfig.js +5 -5
- package/lib/util/isKeyframeRule.js +1 -1
- package/lib/util/isPlainObject.js +1 -1
- package/lib/util/isValidArbitraryValue.js +26 -27
- package/lib/util/log.js +9 -10
- package/lib/util/nameClass.js +7 -7
- package/lib/util/negateValue.js +4 -5
- package/lib/util/normalizeConfig.js +68 -58
- package/lib/util/normalizeScreens.js +5 -6
- package/lib/util/parseAnimationValue.js +56 -57
- package/lib/util/parseBoxShadowValue.js +19 -20
- package/lib/util/parseDependency.js +32 -32
- package/lib/util/parseObjectStyles.js +6 -6
- package/lib/util/pluginUtils.js +20 -12
- package/lib/util/prefixSelector.js +1 -1
- package/lib/util/resolveConfig.js +81 -58
- package/lib/util/resolveConfigPath.js +16 -16
- package/lib/util/responsive.js +6 -6
- package/lib/util/splitAtTopLevelOnly.js +90 -0
- package/lib/util/toColorValue.js +1 -1
- package/lib/util/toPath.js +2 -2
- package/lib/util/transformThemeValue.js +30 -28
- package/lib/util/validateConfig.js +21 -0
- package/lib/util/withAlphaVariable.js +23 -23
- package/package.json +33 -27
- package/peers/index.js +7728 -5848
- package/plugin.d.ts +11 -0
- package/scripts/generate-types.js +52 -0
- package/src/cli-peer-dependencies.js +7 -1
- package/src/cli.js +118 -24
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +142 -30
- package/src/css/preflight.css +1 -8
- package/src/featureFlags.js +4 -4
- package/src/index.js +15 -1
- package/src/lib/cacheInvalidation.js +52 -0
- package/src/lib/collapseAdjacentRules.js +21 -2
- package/src/lib/defaultExtractor.js +177 -33
- package/src/lib/evaluateTailwindFunctions.js +20 -4
- package/src/lib/expandApplyAtRules.js +418 -186
- package/src/lib/expandTailwindAtRules.js +30 -10
- package/src/lib/generateRules.js +142 -51
- package/src/lib/regex.js +74 -0
- package/src/lib/resolveDefaultsAtRules.js +7 -3
- package/src/lib/setupContextUtils.js +142 -87
- package/src/lib/setupTrackingContext.js +7 -3
- package/src/lib/sharedState.js +2 -0
- package/src/postcss-plugins/nesting/README.md +2 -2
- package/src/postcss-plugins/nesting/plugin.js +36 -0
- package/src/util/cloneNodes.js +14 -1
- package/src/util/color.js +25 -21
- package/src/util/dataTypes.js +14 -6
- package/src/util/formatVariantSelector.js +79 -62
- package/src/util/getAllConfigs.js +7 -0
- package/src/util/log.js +8 -8
- package/src/util/normalizeConfig.js +0 -8
- package/src/util/parseBoxShadowValue.js +3 -2
- package/src/util/pluginUtils.js +13 -1
- package/src/util/resolveConfig.js +66 -22
- package/src/util/splitAtTopLevelOnly.js +71 -0
- package/src/util/toPath.js +1 -1
- package/src/util/transformThemeValue.js +4 -2
- package/src/util/validateConfig.js +13 -0
- package/src/util/withAlphaVariable.js +1 -1
- package/stubs/defaultConfig.stub.js +5 -1
- package/stubs/simpleConfig.stub.js +1 -0
- package/types/config.d.ts +325 -0
- package/types/generated/.gitkeep +0 -0
- package/types/generated/colors.d.ts +276 -0
- package/types/generated/corePluginList.d.ts +1 -0
- package/types/index.d.ts +1 -0
|
@@ -29,18 +29,26 @@ export function formatVariantSelector(current, ...others) {
|
|
|
29
29
|
return current
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function finalizeSelector(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
export function finalizeSelector(
|
|
33
|
+
format,
|
|
34
|
+
{
|
|
35
|
+
selector,
|
|
36
|
+
candidate,
|
|
37
|
+
context,
|
|
38
|
+
|
|
39
|
+
// Split by the separator, but ignore the separator inside square brackets:
|
|
40
|
+
//
|
|
41
|
+
// E.g.: dark:lg:hover:[paint-order:markers]
|
|
42
|
+
// ┬ ┬ ┬ ┬
|
|
43
|
+
// │ │ │ ╰── We will not split here
|
|
44
|
+
// ╰──┴─────┴─────────────── We will split here
|
|
45
|
+
//
|
|
46
|
+
base = candidate
|
|
47
|
+
.split(new RegExp(`\\${context?.tailwindConfig?.separator ?? ':'}(?![^[]*\\])`))
|
|
48
|
+
.pop(),
|
|
49
|
+
}
|
|
50
|
+
) {
|
|
51
|
+
let ast = selectorParser().astSync(selector)
|
|
44
52
|
|
|
45
53
|
if (context?.tailwindConfig?.prefix) {
|
|
46
54
|
format = prefixSelector(context.tailwindConfig.prefix, format)
|
|
@@ -48,6 +56,19 @@ export function finalizeSelector(format, { selector, candidate, context }) {
|
|
|
48
56
|
|
|
49
57
|
format = format.replace(PARENT, `.${escapeClassName(candidate)}`)
|
|
50
58
|
|
|
59
|
+
let formatAst = selectorParser().astSync(format)
|
|
60
|
+
|
|
61
|
+
// Remove extraneous selectors that do not include the base class/candidate being matched against
|
|
62
|
+
// For example if we have a utility defined `.a, .b { color: red}`
|
|
63
|
+
// And the formatted variant is sm:b then we want the final selector to be `.sm\:b` and not `.a, .sm\:b`
|
|
64
|
+
ast.each((node) => {
|
|
65
|
+
let hasClassesMatchingCandidate = node.some((n) => n.type === 'class' && n.value === base)
|
|
66
|
+
|
|
67
|
+
if (!hasClassesMatchingCandidate) {
|
|
68
|
+
node.remove()
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
51
72
|
// Normalize escaped classes, e.g.:
|
|
52
73
|
//
|
|
53
74
|
// The idea would be to replace the escaped `base` in the selector with the
|
|
@@ -59,65 +80,61 @@ export function finalizeSelector(format, { selector, candidate, context }) {
|
|
|
59
80
|
// base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
|
|
60
81
|
// escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
|
|
61
82
|
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return node
|
|
69
|
-
})
|
|
70
|
-
}).processSync(selector)
|
|
83
|
+
ast.walkClasses((node) => {
|
|
84
|
+
if (node.raws && node.value.includes(base)) {
|
|
85
|
+
node.raws.value = escapeClassName(unescape(node.raws.value))
|
|
86
|
+
}
|
|
87
|
+
})
|
|
71
88
|
|
|
72
89
|
// We can safely replace the escaped base now, since the `base` section is
|
|
73
90
|
// now in a normalized escaped value.
|
|
74
|
-
|
|
91
|
+
ast.walkClasses((node) => {
|
|
92
|
+
if (node.value === base) {
|
|
93
|
+
node.replaceWith(...formatAst.nodes)
|
|
94
|
+
}
|
|
95
|
+
})
|
|
75
96
|
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before`
|
|
93
|
-
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before`
|
|
94
|
-
//
|
|
95
|
-
// `::before:hover` doesn't work, which means that we can make it work for you by flipping the order.
|
|
96
|
-
function collectPseudoElements(selector) {
|
|
97
|
-
let nodes = []
|
|
98
|
-
|
|
99
|
-
for (let node of selector.nodes) {
|
|
100
|
-
if (isPseudoElement(node)) {
|
|
101
|
-
nodes.push(node)
|
|
102
|
-
selector.removeChild(node)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (node?.nodes) {
|
|
106
|
-
nodes.push(...collectPseudoElements(node))
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return nodes
|
|
97
|
+
// This will make sure to move pseudo's to the correct spot (the end for
|
|
98
|
+
// pseudo elements) because otherwise the selector will never work
|
|
99
|
+
// anyway.
|
|
100
|
+
//
|
|
101
|
+
// E.g.:
|
|
102
|
+
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before`
|
|
103
|
+
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before`
|
|
104
|
+
//
|
|
105
|
+
// `::before:hover` doesn't work, which means that we can make it work for you by flipping the order.
|
|
106
|
+
function collectPseudoElements(selector) {
|
|
107
|
+
let nodes = []
|
|
108
|
+
|
|
109
|
+
for (let node of selector.nodes) {
|
|
110
|
+
if (isPseudoElement(node)) {
|
|
111
|
+
nodes.push(node)
|
|
112
|
+
selector.removeChild(node)
|
|
111
113
|
}
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
selector.nodes.push(pseudoElements.sort(sortSelector))
|
|
115
|
+
if (node?.nodes) {
|
|
116
|
+
nodes.push(...collectPseudoElements(node))
|
|
116
117
|
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return nodes
|
|
121
|
+
}
|
|
117
122
|
|
|
118
|
-
|
|
123
|
+
// Remove unnecessary pseudo selectors that we used as placeholders
|
|
124
|
+
ast.each((selector) => {
|
|
125
|
+
selector.walkPseudos((p) => {
|
|
126
|
+
if (selectorFunctions.has(p.value)) {
|
|
127
|
+
p.replaceWith(p.nodes)
|
|
128
|
+
}
|
|
119
129
|
})
|
|
120
|
-
|
|
130
|
+
|
|
131
|
+
let pseudoElements = collectPseudoElements(selector)
|
|
132
|
+
if (pseudoElements.length > 0) {
|
|
133
|
+
selector.nodes.push(pseudoElements.sort(sortSelector))
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return ast.toString()
|
|
121
138
|
}
|
|
122
139
|
|
|
123
140
|
// Note: As a rule, double colons (::) should be used instead of a single colon
|
|
@@ -9,6 +9,13 @@ export default function getAllConfigs(config) {
|
|
|
9
9
|
|
|
10
10
|
const features = {
|
|
11
11
|
// Add experimental configs here...
|
|
12
|
+
respectDefaultRingColorOpacity: {
|
|
13
|
+
theme: {
|
|
14
|
+
ringColor: {
|
|
15
|
+
DEFAULT: '#3b82f67f',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
const experimentals = Object.keys(features)
|
package/src/util/log.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import
|
|
1
|
+
import colors from 'picocolors'
|
|
2
2
|
|
|
3
3
|
let alreadyShown = new Set()
|
|
4
4
|
|
|
5
|
-
function log(
|
|
6
|
-
if (process.env.JEST_WORKER_ID
|
|
5
|
+
function log(type, messages, key) {
|
|
6
|
+
if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return
|
|
7
7
|
|
|
8
8
|
if (key && alreadyShown.has(key)) return
|
|
9
9
|
if (key) alreadyShown.add(key)
|
|
10
10
|
|
|
11
11
|
console.warn('')
|
|
12
|
-
messages.forEach((message) => console.warn(
|
|
12
|
+
messages.forEach((message) => console.warn(type, '-', message))
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function dim(input) {
|
|
16
|
-
return
|
|
16
|
+
return colors.dim(input)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export default {
|
|
20
20
|
info(key, messages) {
|
|
21
|
-
log(
|
|
21
|
+
log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
|
|
22
22
|
},
|
|
23
23
|
warn(key, messages) {
|
|
24
|
-
log(
|
|
24
|
+
log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
|
|
25
25
|
},
|
|
26
26
|
risk(key, messages) {
|
|
27
|
-
log(
|
|
27
|
+
log(colors.bold(colors.magenta('risk')), ...(Array.isArray(key) ? [key] : [messages, key]))
|
|
28
28
|
},
|
|
29
29
|
}
|
|
@@ -258,13 +258,5 @@ export function normalizeConfig(config) {
|
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
if (config.content.files.length === 0) {
|
|
262
|
-
log.warn('content-problems', [
|
|
263
|
-
'The `content` option in your Tailwind CSS configuration is missing or empty.',
|
|
264
|
-
'Configure your content sources or your generated CSS will be missing styles.',
|
|
265
|
-
'https://tailwindcss.com/docs/content-configuration',
|
|
266
|
-
])
|
|
267
|
-
}
|
|
268
|
-
|
|
269
261
|
return config
|
|
270
262
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
|
|
2
|
+
|
|
1
3
|
let KEYWORDS = new Set(['inset', 'inherit', 'initial', 'revert', 'unset'])
|
|
2
|
-
let COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
|
|
3
4
|
let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
|
|
4
5
|
let LENGTH = /^-?(\d+|\.\d+)(.*?)$/g
|
|
5
6
|
|
|
6
7
|
export function parseBoxShadowValue(input) {
|
|
7
|
-
let shadows =
|
|
8
|
+
let shadows = Array.from(splitAtTopLevelOnly(input, ','))
|
|
8
9
|
return shadows.map((shadow) => {
|
|
9
10
|
let value = shadow.trim()
|
|
10
11
|
let result = { raw: value }
|
package/src/util/pluginUtils.js
CHANGED
|
@@ -95,9 +95,19 @@ function splitAlpha(modifier) {
|
|
|
95
95
|
return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
export function parseColorFormat(value) {
|
|
99
|
+
if (typeof value === 'string' && value.includes('<alpha-value>')) {
|
|
100
|
+
let oldValue = value
|
|
101
|
+
|
|
102
|
+
return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return value
|
|
106
|
+
}
|
|
107
|
+
|
|
98
108
|
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
|
|
99
109
|
if (options.values?.[modifier] !== undefined) {
|
|
100
|
-
return options.values?.[modifier]
|
|
110
|
+
return parseColorFormat(options.values?.[modifier])
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
let [color, alpha] = splitAlpha(modifier)
|
|
@@ -110,6 +120,8 @@ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
|
|
|
110
120
|
return undefined
|
|
111
121
|
}
|
|
112
122
|
|
|
123
|
+
normalizedColor = parseColorFormat(normalizedColor)
|
|
124
|
+
|
|
113
125
|
if (isArbitraryValue(alpha)) {
|
|
114
126
|
return withAlphaValue(normalizedColor, alpha.slice(1, -1))
|
|
115
127
|
}
|
|
@@ -8,6 +8,9 @@ import { toPath } from './toPath'
|
|
|
8
8
|
import { normalizeConfig } from './normalizeConfig'
|
|
9
9
|
import isPlainObject from './isPlainObject'
|
|
10
10
|
import { cloneDeep } from './cloneDeep'
|
|
11
|
+
import { parseColorFormat } from './pluginUtils'
|
|
12
|
+
import { withAlphaValue } from './withAlphaVariable'
|
|
13
|
+
import toColorValue from './toColorValue'
|
|
11
14
|
|
|
12
15
|
function isFunction(input) {
|
|
13
16
|
return typeof input === 'function'
|
|
@@ -134,40 +137,81 @@ function mergeExtensions({ extend, ...theme }) {
|
|
|
134
137
|
})
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
/**
|
|
141
|
+
*
|
|
142
|
+
* @param {string} key
|
|
143
|
+
* @return {Iterable<string[] & {alpha: string | undefined}>}
|
|
144
|
+
*/
|
|
145
|
+
function* toPaths(key) {
|
|
146
|
+
let path = toPath(key)
|
|
147
|
+
|
|
148
|
+
if (path.length === 0) {
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
yield path
|
|
153
|
+
|
|
154
|
+
if (Array.isArray(key)) {
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let pattern = /^(.*?)\s*\/\s*([^/]+)$/
|
|
159
|
+
let matches = key.match(pattern)
|
|
160
|
+
|
|
161
|
+
if (matches !== null) {
|
|
162
|
+
let [, prefix, alpha] = matches
|
|
163
|
+
|
|
164
|
+
let newPath = toPath(prefix)
|
|
165
|
+
newPath.alpha = alpha
|
|
166
|
+
|
|
167
|
+
yield newPath
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
137
171
|
function resolveFunctionKeys(object) {
|
|
172
|
+
// theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
|
|
173
|
+
|
|
138
174
|
const resolvePath = (key, defaultValue) => {
|
|
139
|
-
const path
|
|
175
|
+
for (const path of toPaths(key)) {
|
|
176
|
+
let index = 0
|
|
177
|
+
let val = object
|
|
140
178
|
|
|
141
|
-
|
|
142
|
-
|
|
179
|
+
while (val !== undefined && val !== null && index < path.length) {
|
|
180
|
+
val = val[path[index++]]
|
|
143
181
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
val = isFunction(val) ? val(resolvePath, configUtils) : val
|
|
147
|
-
}
|
|
182
|
+
let shouldResolveAsFn =
|
|
183
|
+
isFunction(val) && (path.alpha === undefined || index < path.length - 1)
|
|
148
184
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
185
|
+
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val
|
|
186
|
+
}
|
|
152
187
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
188
|
+
if (val !== undefined) {
|
|
189
|
+
if (path.alpha !== undefined) {
|
|
190
|
+
let normalized = parseColorFormat(val)
|
|
156
191
|
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
return withAlphaValue(normalized, path.alpha, toColorValue(normalized))
|
|
193
|
+
}
|
|
159
194
|
|
|
160
|
-
|
|
195
|
+
if (isPlainObject(val)) {
|
|
196
|
+
return cloneDeep(val)
|
|
197
|
+
}
|
|
161
198
|
|
|
162
|
-
|
|
163
|
-
|
|
199
|
+
return val
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return defaultValue
|
|
164
204
|
}
|
|
165
205
|
|
|
206
|
+
Object.assign(resolvePath, {
|
|
207
|
+
theme: resolvePath,
|
|
208
|
+
...configUtils,
|
|
209
|
+
})
|
|
210
|
+
|
|
166
211
|
return Object.keys(object).reduce((resolved, key) => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
212
|
+
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key]
|
|
213
|
+
|
|
214
|
+
return resolved
|
|
171
215
|
}, {})
|
|
172
216
|
}
|
|
173
217
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as regex from '../lib/regex'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This splits a string on a top-level character.
|
|
5
|
+
*
|
|
6
|
+
* Regex doesn't support recursion (at least not the JS-flavored version).
|
|
7
|
+
* So we have to use a tiny state machine to keep track of paren placement.
|
|
8
|
+
*
|
|
9
|
+
* Expected behavior using commas:
|
|
10
|
+
* var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0)
|
|
11
|
+
* ─┬─ ┬ ┬ ┬
|
|
12
|
+
* x x x ╰──────── Split because top-level
|
|
13
|
+
* ╰──────────────┴──┴───────────── Ignored b/c inside >= 1 levels of parens
|
|
14
|
+
*
|
|
15
|
+
* @param {string} input
|
|
16
|
+
* @param {string} separator
|
|
17
|
+
*/
|
|
18
|
+
export function* splitAtTopLevelOnly(input, separator) {
|
|
19
|
+
let SPECIALS = new RegExp(`[(){}\\[\\]${regex.escape(separator)}]`, 'g')
|
|
20
|
+
|
|
21
|
+
let depth = 0
|
|
22
|
+
let lastIndex = 0
|
|
23
|
+
let found = false
|
|
24
|
+
let separatorIndex = 0
|
|
25
|
+
let separatorStart = 0
|
|
26
|
+
let separatorLength = separator.length
|
|
27
|
+
|
|
28
|
+
// Find all paren-like things & character
|
|
29
|
+
// And only split on commas if they're top-level
|
|
30
|
+
for (let match of input.matchAll(SPECIALS)) {
|
|
31
|
+
let matchesSeparator = match[0] === separator[separatorIndex]
|
|
32
|
+
let atEndOfSeparator = separatorIndex === separatorLength - 1
|
|
33
|
+
let matchesFullSeparator = matchesSeparator && atEndOfSeparator
|
|
34
|
+
|
|
35
|
+
if (match[0] === '(') depth++
|
|
36
|
+
if (match[0] === ')') depth--
|
|
37
|
+
if (match[0] === '[') depth++
|
|
38
|
+
if (match[0] === ']') depth--
|
|
39
|
+
if (match[0] === '{') depth++
|
|
40
|
+
if (match[0] === '}') depth--
|
|
41
|
+
|
|
42
|
+
if (matchesSeparator && depth === 0) {
|
|
43
|
+
if (separatorStart === 0) {
|
|
44
|
+
separatorStart = match.index
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
separatorIndex++
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (matchesFullSeparator && depth === 0) {
|
|
51
|
+
found = true
|
|
52
|
+
|
|
53
|
+
yield input.substring(lastIndex, separatorStart)
|
|
54
|
+
lastIndex = separatorStart + separatorLength
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (separatorIndex === separatorLength) {
|
|
58
|
+
separatorIndex = 0
|
|
59
|
+
separatorStart = 0
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Provide the last segment of the string if available
|
|
64
|
+
// Otherwise the whole string since no `char`s were found
|
|
65
|
+
// This mirrors the behavior of string.split()
|
|
66
|
+
if (found) {
|
|
67
|
+
yield input.substring(lastIndex)
|
|
68
|
+
} else {
|
|
69
|
+
yield input
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/util/toPath.js
CHANGED
|
@@ -44,8 +44,10 @@ export default function transformThemeValue(themeSection) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
return (value) => {
|
|
48
|
-
if (typeof value === 'function')
|
|
47
|
+
return (value, opts = {}) => {
|
|
48
|
+
if (typeof value === 'function') {
|
|
49
|
+
value = value(opts)
|
|
50
|
+
}
|
|
49
51
|
|
|
50
52
|
return value
|
|
51
53
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import log from './log'
|
|
2
|
+
|
|
3
|
+
export function validateConfig(config) {
|
|
4
|
+
if (config.content.files.length === 0) {
|
|
5
|
+
log.warn('content-problems', [
|
|
6
|
+
'The `content` option in your Tailwind CSS configuration is missing or empty.',
|
|
7
|
+
'Configure your content sources or your generated CSS will be missing styles.',
|
|
8
|
+
'https://tailwindcss.com/docs/content-configuration',
|
|
9
|
+
])
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return config
|
|
13
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
1
2
|
module.exports = {
|
|
2
3
|
content: [],
|
|
3
4
|
presets: [],
|
|
@@ -194,6 +195,9 @@ module.exports = {
|
|
|
194
195
|
'3xl': '1.5rem',
|
|
195
196
|
full: '9999px',
|
|
196
197
|
},
|
|
198
|
+
borderSpacing: ({ theme }) => ({
|
|
199
|
+
...theme('spacing'),
|
|
200
|
+
}),
|
|
197
201
|
borderWidth: {
|
|
198
202
|
DEFAULT: '1px',
|
|
199
203
|
0: '0px',
|
|
@@ -717,7 +721,7 @@ module.exports = {
|
|
|
717
721
|
8: '8px',
|
|
718
722
|
},
|
|
719
723
|
ringColor: ({ theme }) => ({
|
|
720
|
-
DEFAULT: theme(
|
|
724
|
+
DEFAULT: theme(`colors.blue.500`, '#3b82f6'),
|
|
721
725
|
...theme('colors'),
|
|
722
726
|
}),
|
|
723
727
|
ringOffsetColor: ({ theme }) => theme('colors'),
|