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.
Files changed (119) hide show
  1. package/CHANGELOG.md +92 -2
  2. package/colors.d.ts +3 -0
  3. package/defaultConfig.d.ts +3 -0
  4. package/defaultTheme.d.ts +3 -0
  5. package/lib/cli-peer-dependencies.js +10 -5
  6. package/lib/cli.js +266 -203
  7. package/lib/constants.js +8 -8
  8. package/lib/corePluginList.js +1 -0
  9. package/lib/corePlugins.js +1662 -1554
  10. package/lib/css/preflight.css +1 -8
  11. package/lib/featureFlags.js +14 -12
  12. package/lib/index.js +16 -6
  13. package/lib/lib/cacheInvalidation.js +87 -0
  14. package/lib/lib/collapseAdjacentRules.js +30 -15
  15. package/lib/lib/collapseDuplicateDeclarations.js +1 -1
  16. package/lib/lib/defaultExtractor.js +191 -30
  17. package/lib/lib/detectNesting.js +9 -9
  18. package/lib/lib/evaluateTailwindFunctions.js +37 -28
  19. package/lib/lib/expandApplyAtRules.js +379 -189
  20. package/lib/lib/expandTailwindAtRules.js +168 -144
  21. package/lib/lib/generateRules.js +190 -81
  22. package/lib/lib/getModuleDependencies.js +14 -14
  23. package/lib/lib/normalizeTailwindDirectives.js +35 -35
  24. package/lib/lib/partitionApplyAtRules.js +7 -7
  25. package/lib/lib/regex.js +52 -0
  26. package/lib/lib/resolveDefaultsAtRules.js +80 -79
  27. package/lib/lib/setupContextUtils.js +207 -170
  28. package/lib/lib/setupTrackingContext.js +61 -63
  29. package/lib/lib/sharedState.js +11 -8
  30. package/lib/lib/substituteScreenAtRules.js +3 -4
  31. package/lib/postcss-plugins/nesting/README.md +2 -2
  32. package/lib/postcss-plugins/nesting/index.js +1 -1
  33. package/lib/postcss-plugins/nesting/plugin.js +40 -9
  34. package/lib/processTailwindFeatures.js +7 -7
  35. package/lib/public/colors.js +241 -241
  36. package/lib/public/resolve-config.js +5 -5
  37. package/lib/util/buildMediaQuery.js +2 -3
  38. package/lib/util/cloneDeep.js +3 -5
  39. package/lib/util/cloneNodes.js +12 -1
  40. package/lib/util/color.js +42 -51
  41. package/lib/util/createPlugin.js +1 -2
  42. package/lib/util/createUtilityPlugin.js +6 -7
  43. package/lib/util/dataTypes.js +85 -81
  44. package/lib/util/escapeClassName.js +5 -5
  45. package/lib/util/escapeCommas.js +1 -1
  46. package/lib/util/flattenColorPalette.js +4 -7
  47. package/lib/util/formatVariantSelector.js +82 -75
  48. package/lib/util/getAllConfigs.js +15 -10
  49. package/lib/util/hashConfig.js +5 -5
  50. package/lib/util/isKeyframeRule.js +1 -1
  51. package/lib/util/isPlainObject.js +1 -1
  52. package/lib/util/isValidArbitraryValue.js +26 -27
  53. package/lib/util/log.js +9 -10
  54. package/lib/util/nameClass.js +7 -7
  55. package/lib/util/negateValue.js +4 -5
  56. package/lib/util/normalizeConfig.js +68 -58
  57. package/lib/util/normalizeScreens.js +5 -6
  58. package/lib/util/parseAnimationValue.js +56 -57
  59. package/lib/util/parseBoxShadowValue.js +19 -20
  60. package/lib/util/parseDependency.js +32 -32
  61. package/lib/util/parseObjectStyles.js +6 -6
  62. package/lib/util/pluginUtils.js +20 -12
  63. package/lib/util/prefixSelector.js +1 -1
  64. package/lib/util/resolveConfig.js +81 -58
  65. package/lib/util/resolveConfigPath.js +16 -16
  66. package/lib/util/responsive.js +6 -6
  67. package/lib/util/splitAtTopLevelOnly.js +90 -0
  68. package/lib/util/toColorValue.js +1 -1
  69. package/lib/util/toPath.js +2 -2
  70. package/lib/util/transformThemeValue.js +30 -28
  71. package/lib/util/validateConfig.js +21 -0
  72. package/lib/util/withAlphaVariable.js +23 -23
  73. package/package.json +33 -27
  74. package/peers/index.js +7728 -5848
  75. package/plugin.d.ts +11 -0
  76. package/scripts/generate-types.js +52 -0
  77. package/src/cli-peer-dependencies.js +7 -1
  78. package/src/cli.js +118 -24
  79. package/src/corePluginList.js +1 -1
  80. package/src/corePlugins.js +142 -30
  81. package/src/css/preflight.css +1 -8
  82. package/src/featureFlags.js +4 -4
  83. package/src/index.js +15 -1
  84. package/src/lib/cacheInvalidation.js +52 -0
  85. package/src/lib/collapseAdjacentRules.js +21 -2
  86. package/src/lib/defaultExtractor.js +177 -33
  87. package/src/lib/evaluateTailwindFunctions.js +20 -4
  88. package/src/lib/expandApplyAtRules.js +418 -186
  89. package/src/lib/expandTailwindAtRules.js +30 -10
  90. package/src/lib/generateRules.js +142 -51
  91. package/src/lib/regex.js +74 -0
  92. package/src/lib/resolveDefaultsAtRules.js +7 -3
  93. package/src/lib/setupContextUtils.js +142 -87
  94. package/src/lib/setupTrackingContext.js +7 -3
  95. package/src/lib/sharedState.js +2 -0
  96. package/src/postcss-plugins/nesting/README.md +2 -2
  97. package/src/postcss-plugins/nesting/plugin.js +36 -0
  98. package/src/util/cloneNodes.js +14 -1
  99. package/src/util/color.js +25 -21
  100. package/src/util/dataTypes.js +14 -6
  101. package/src/util/formatVariantSelector.js +79 -62
  102. package/src/util/getAllConfigs.js +7 -0
  103. package/src/util/log.js +8 -8
  104. package/src/util/normalizeConfig.js +0 -8
  105. package/src/util/parseBoxShadowValue.js +3 -2
  106. package/src/util/pluginUtils.js +13 -1
  107. package/src/util/resolveConfig.js +66 -22
  108. package/src/util/splitAtTopLevelOnly.js +71 -0
  109. package/src/util/toPath.js +1 -1
  110. package/src/util/transformThemeValue.js +4 -2
  111. package/src/util/validateConfig.js +13 -0
  112. package/src/util/withAlphaVariable.js +1 -1
  113. package/stubs/defaultConfig.stub.js +5 -1
  114. package/stubs/simpleConfig.stub.js +1 -0
  115. package/types/config.d.ts +325 -0
  116. package/types/generated/.gitkeep +0 -0
  117. package/types/generated/colors.d.ts +276 -0
  118. package/types/generated/corePluginList.d.ts +1 -0
  119. 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(format, { selector, candidate, context }) {
33
- let separator = context?.tailwindConfig?.separator ?? ':'
34
-
35
- // Split by the separator, but ignore the separator inside square brackets:
36
- //
37
- // E.g.: dark:lg:hover:[paint-order:markers]
38
- // ┬ ┬ ┬ ┬
39
- // │ │ │ ╰── We will not split here
40
- // ╰──┴─────┴─────────────── We will split here
41
- //
42
- let splitter = new RegExp(`\\${separator}(?![^[]*\\])`)
43
- let base = candidate.split(splitter).pop()
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
- selector = selectorParser((selectors) => {
63
- return selectors.walkClasses((node) => {
64
- if (node.raws && node.value.includes(base)) {
65
- node.raws.value = escapeClassName(unescape(node.raws.value))
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
- selector = selector.replace(`.${escapeClassName(base)}`, format)
91
+ ast.walkClasses((node) => {
92
+ if (node.value === base) {
93
+ node.replaceWith(...formatAst.nodes)
94
+ }
95
+ })
75
96
 
76
- // Remove unnecessary pseudo selectors that we used as placeholders
77
- return selectorParser((selectors) => {
78
- return selectors.map((selector) => {
79
- selector.walkPseudos((p) => {
80
- if (selectorFunctions.has(p.value)) {
81
- p.replaceWith(p.nodes)
82
- }
83
-
84
- return p
85
- })
86
-
87
- // This will make sure to move pseudo's to the correct spot (the end for
88
- // pseudo elements) because otherwise the selector will never work
89
- // anyway.
90
- //
91
- // E.g.:
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
- let pseudoElements = collectPseudoElements(selector)
114
- if (pseudoElements.length > 0) {
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
- return selector
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
- }).processSync(selector)
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 chalk from 'chalk'
1
+ import colors from 'picocolors'
2
2
 
3
3
  let alreadyShown = new Set()
4
4
 
5
- function log(chalk, messages, key) {
6
- if (process.env.JEST_WORKER_ID !== undefined) return
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(chalk, '-', message))
12
+ messages.forEach((message) => console.warn(type, '-', message))
13
13
  }
14
14
 
15
15
  export function dim(input) {
16
- return chalk.dim(input)
16
+ return colors.dim(input)
17
17
  }
18
18
 
19
19
  export default {
20
20
  info(key, messages) {
21
- log(chalk.bold.cyan('info'), ...(Array.isArray(key) ? [key] : [messages, key]))
21
+ log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
22
22
  },
23
23
  warn(key, messages) {
24
- log(chalk.bold.yellow('warn'), ...(Array.isArray(key) ? [key] : [messages, key]))
24
+ log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
25
25
  },
26
26
  risk(key, messages) {
27
- log(chalk.bold.magenta('risk'), ...(Array.isArray(key) ? [key] : [messages, key]))
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 = input.split(COMMA)
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 }
@@ -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 = toPath(key)
175
+ for (const path of toPaths(key)) {
176
+ let index = 0
177
+ let val = object
140
178
 
141
- let index = 0
142
- let val = object
179
+ while (val !== undefined && val !== null && index < path.length) {
180
+ val = val[path[index++]]
143
181
 
144
- while (val !== undefined && val !== null && index < path.length) {
145
- val = val[path[index++]]
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
- if (val === undefined) {
150
- return defaultValue
151
- }
185
+ val = shouldResolveAsFn ? val(resolvePath, configUtils) : val
186
+ }
152
187
 
153
- if (isPlainObject(val)) {
154
- return cloneDeep(val)
155
- }
188
+ if (val !== undefined) {
189
+ if (path.alpha !== undefined) {
190
+ let normalized = parseColorFormat(val)
156
191
 
157
- return val
158
- }
192
+ return withAlphaValue(normalized, path.alpha, toColorValue(normalized))
193
+ }
159
194
 
160
- resolvePath.theme = resolvePath
195
+ if (isPlainObject(val)) {
196
+ return cloneDeep(val)
197
+ }
161
198
 
162
- for (let key in configUtils) {
163
- resolvePath[key] = configUtils[key]
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
- return {
168
- ...resolved,
169
- [key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key],
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
+ }
@@ -4,7 +4,7 @@
4
4
  * Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
5
5
  *
6
6
  * Example:
7
- * a -> ['a]
7
+ * a -> ['a']
8
8
  * a.b.c -> ['a', 'b', 'c']
9
9
  * a[b].c -> ['a', 'b', 'c']
10
10
  * a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
@@ -44,8 +44,10 @@ export default function transformThemeValue(themeSection) {
44
44
  }
45
45
  }
46
46
 
47
- return (value) => {
48
- if (typeof value === 'function') value = value({})
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
+ }
@@ -5,7 +5,7 @@ export function withAlphaValue(color, alphaValue, defaultValue) {
5
5
  return color({ opacityValue: alphaValue })
6
6
  }
7
7
 
8
- let parsed = parseColor(color)
8
+ let parsed = parseColor(color, { loose: true })
9
9
 
10
10
  if (parsed === null) {
11
11
  return defaultValue
@@ -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('colors.blue.500', '#3b82f6'),
724
+ DEFAULT: theme(`colors.blue.500`, '#3b82f6'),
721
725
  ...theme('colors'),
722
726
  }),
723
727
  ringOffsetColor: ({ theme }) => theme('colors'),
@@ -1,3 +1,4 @@
1
+ /** @type {import('tailwindcss').Config} */
1
2
  module.exports = {
2
3
  content: [],
3
4
  theme: {