tailwindcss 3.0.0-alpha.1 → 3.0.0-alpha.2

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 (60) hide show
  1. package/CHANGELOG.md +67 -1
  2. package/lib/cli.js +66 -62
  3. package/lib/constants.js +1 -1
  4. package/lib/corePluginList.js +7 -1
  5. package/lib/corePlugins.js +264 -203
  6. package/lib/css/preflight.css +12 -0
  7. package/lib/featureFlags.js +10 -7
  8. package/lib/lib/collapseDuplicateDeclarations.js +29 -0
  9. package/lib/lib/evaluateTailwindFunctions.js +3 -3
  10. package/lib/lib/expandApplyAtRules.js +7 -7
  11. package/lib/lib/expandTailwindAtRules.js +2 -1
  12. package/lib/lib/generateRules.js +115 -19
  13. package/lib/lib/resolveDefaultsAtRules.js +44 -47
  14. package/lib/lib/setupContextUtils.js +72 -15
  15. package/lib/lib/setupWatchingContext.js +5 -1
  16. package/lib/lib/sharedState.js +2 -2
  17. package/lib/processTailwindFeatures.js +4 -0
  18. package/lib/util/createUtilityPlugin.js +5 -5
  19. package/lib/util/dataTypes.js +24 -4
  20. package/lib/util/formatVariantSelector.js +102 -0
  21. package/lib/util/nameClass.js +1 -1
  22. package/lib/util/negateValue.js +3 -1
  23. package/lib/util/normalizeConfig.js +22 -8
  24. package/lib/util/parseBoxShadowValue.js +77 -0
  25. package/lib/util/pluginUtils.js +62 -158
  26. package/lib/util/prefixSelector.js +1 -3
  27. package/lib/util/resolveConfig.js +13 -9
  28. package/lib/util/transformThemeValue.js +23 -13
  29. package/package.json +11 -11
  30. package/peers/index.js +873 -2505
  31. package/src/cli.js +9 -2
  32. package/src/corePluginList.js +1 -1
  33. package/src/corePlugins.js +282 -348
  34. package/src/css/preflight.css +12 -0
  35. package/src/featureFlags.js +10 -4
  36. package/src/lib/collapseDuplicateDeclarations.js +28 -0
  37. package/src/lib/expandTailwindAtRules.js +3 -2
  38. package/src/lib/generateRules.js +121 -11
  39. package/src/lib/resolveDefaultsAtRules.js +39 -43
  40. package/src/lib/setupContextUtils.js +71 -9
  41. package/src/lib/setupWatchingContext.js +7 -0
  42. package/src/lib/sharedState.js +1 -1
  43. package/src/processTailwindFeatures.js +5 -0
  44. package/src/util/createUtilityPlugin.js +2 -2
  45. package/src/util/dataTypes.js +32 -5
  46. package/src/util/formatVariantSelector.js +105 -0
  47. package/src/util/nameClass.js +1 -1
  48. package/src/util/negateValue.js +4 -2
  49. package/src/util/normalizeConfig.js +17 -1
  50. package/src/util/parseBoxShadowValue.js +71 -0
  51. package/src/util/pluginUtils.js +50 -146
  52. package/src/util/prefixSelector.js +1 -4
  53. package/src/util/resolveConfig.js +7 -1
  54. package/src/util/transformThemeValue.js +22 -7
  55. package/stubs/defaultConfig.stub.js +101 -58
  56. package/peers/.svgo.yml +0 -75
  57. package/peers/orders/concentric-css.json +0 -299
  58. package/peers/orders/smacss.json +0 -299
  59. package/peers/orders/source.json +0 -295
  60. package/src/.DS_Store +0 -0
@@ -1,4 +1,5 @@
1
1
  import { parseColor } from './color'
2
+ import { parseBoxShadowValue } from './parseBoxShadowValue'
2
3
 
3
4
  // Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
4
5
 
@@ -7,7 +8,22 @@ let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located bet
7
8
 
8
9
  // This is not a data type, but rather a function that can normalize the
9
10
  // correct values.
10
- export function normalize(value) {
11
+ export function normalize(value, isRoot = true) {
12
+ // Keep raw strings if it starts with `url(`
13
+ if (value.includes('url(')) {
14
+ return value
15
+ .split(/(url\(.*?\))/g)
16
+ .filter(Boolean)
17
+ .map((part) => {
18
+ if (/^url\(.*?\)$/.test(part)) {
19
+ return part
20
+ }
21
+
22
+ return normalize(part, false)
23
+ })
24
+ .join('')
25
+ }
26
+
11
27
  // Convert `_` to ` `, except for escaped underscores `\_`
12
28
  value = value
13
29
  .replace(
@@ -18,10 +34,9 @@ export function normalize(value) {
18
34
  .replace(/\\_/g, '_')
19
35
 
20
36
  // Remove leftover whitespace
21
- value = value.trim()
22
-
23
- // Keep raw strings if it starts with `url(`
24
- if (value.startsWith('url(')) return value
37
+ if (isRoot) {
38
+ value = value.trim()
39
+ }
25
40
 
26
41
  // Add spaces around operators inside calc() that do not follow an operator
27
42
  // or '('.
@@ -74,6 +89,18 @@ export function lineWidth(value) {
74
89
  return lineWidths.has(value)
75
90
  }
76
91
 
92
+ export function shadow(value) {
93
+ let parsedShadows = parseBoxShadowValue(normalize(value))
94
+
95
+ for (let parsedShadow of parsedShadows) {
96
+ if (!parsedShadow.valid) {
97
+ return false
98
+ }
99
+ }
100
+
101
+ return true
102
+ }
103
+
77
104
  export function color(value) {
78
105
  let colors = 0
79
106
 
@@ -0,0 +1,105 @@
1
+ import selectorParser from 'postcss-selector-parser'
2
+ import unescape from 'postcss-selector-parser/dist/util/unesc'
3
+ import escapeClassName from '../util/escapeClassName'
4
+ import prefixSelector from '../util/prefixSelector'
5
+
6
+ let MERGE = ':merge'
7
+ let PARENT = '&'
8
+
9
+ export let selectorFunctions = new Set([MERGE])
10
+
11
+ export function formatVariantSelector(current, ...others) {
12
+ for (let other of others) {
13
+ let incomingValue = resolveFunctionArgument(other, MERGE)
14
+ if (incomingValue !== null) {
15
+ let existingValue = resolveFunctionArgument(current, MERGE, incomingValue)
16
+ if (existingValue !== null) {
17
+ let existingTarget = `${MERGE}(${incomingValue})`
18
+ let splitIdx = other.indexOf(existingTarget)
19
+ let addition = other.slice(splitIdx + existingTarget.length).split(' ')[0]
20
+
21
+ current = current.replace(existingTarget, existingTarget + addition)
22
+ continue
23
+ }
24
+ }
25
+
26
+ current = other.replace(PARENT, current)
27
+ }
28
+
29
+ return current
30
+ }
31
+
32
+ export function finalizeSelector(format, { selector, candidate, context }) {
33
+ let base = candidate.split(context?.tailwindConfig?.separator ?? ':').pop()
34
+
35
+ if (context?.tailwindConfig?.prefix) {
36
+ format = prefixSelector(context.tailwindConfig.prefix, format)
37
+ }
38
+
39
+ format = format.replace(PARENT, `.${escapeClassName(candidate)}`)
40
+
41
+ // Normalize escaped classes, e.g.:
42
+ //
43
+ // The idea would be to replace the escaped `base` in the selector with the
44
+ // `format`. However, in css you can escape the same selector in a few
45
+ // different ways. This would result in different strings and therefore we
46
+ // can't replace it properly.
47
+ //
48
+ // base: bg-[rgb(255,0,0)]
49
+ // base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
50
+ // escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
51
+ //
52
+ selector = selectorParser((selectors) => {
53
+ return selectors.walkClasses((node) => {
54
+ if (node.raws && node.value.includes(base)) {
55
+ node.raws.value = escapeClassName(unescape(node.raws.value))
56
+ }
57
+
58
+ return node
59
+ })
60
+ }).processSync(selector)
61
+
62
+ // We can safely replace the escaped base now, since the `base` section is
63
+ // now in a normalized escaped value.
64
+ selector = selector.replace(`.${escapeClassName(base)}`, format)
65
+
66
+ // Remove unnecessary pseudo selectors that we used as placeholders
67
+ return selectorParser((selectors) => {
68
+ return selectors.map((selector) => {
69
+ selector.walkPseudos((p) => {
70
+ if (selectorFunctions.has(p.value)) {
71
+ p.replaceWith(p.nodes)
72
+ }
73
+
74
+ return p
75
+ })
76
+
77
+ return selector
78
+ })
79
+ }).processSync(selector)
80
+ }
81
+
82
+ function resolveFunctionArgument(haystack, needle, arg) {
83
+ let startIdx = haystack.indexOf(arg ? `${needle}(${arg})` : needle)
84
+ if (startIdx === -1) return null
85
+
86
+ // Start inside the `(`
87
+ startIdx += needle.length + 1
88
+
89
+ let target = ''
90
+ let count = 0
91
+
92
+ for (let char of haystack.slice(startIdx)) {
93
+ if (char !== '(' && char !== ')') {
94
+ target += char
95
+ } else if (char === '(') {
96
+ target += char
97
+ count++
98
+ } else if (char === ')') {
99
+ if (--count < 0) break // unbalanced
100
+ target += char
101
+ }
102
+ }
103
+
104
+ return target
105
+ }
@@ -14,7 +14,7 @@ export function formatClass(classPrefix, key) {
14
14
  return classPrefix
15
15
  }
16
16
 
17
- if (key === '-') {
17
+ if (key === '-' || key === '-DEFAULT') {
18
18
  return `-${classPrefix}`
19
19
  }
20
20
 
@@ -1,6 +1,10 @@
1
1
  export default function (value) {
2
2
  value = `${value}`
3
3
 
4
+ if (value === '0') {
5
+ return '0'
6
+ }
7
+
4
8
  // Flip sign of numbers
5
9
  if (/^[+-]?(\d+|\d*\.\d+)(e[+-]?\d+)?(%|\w+)?$/.test(value)) {
6
10
  return value.replace(/^[+-]?/, (sign) => (sign === '-' ? '' : '-'))
@@ -9,6 +13,4 @@ export default function (value) {
9
13
  if (value.includes('var(') || value.includes('calc(')) {
10
14
  return `calc(${value} * -1)`
11
15
  }
12
-
13
- return value
14
16
  }
@@ -140,6 +140,18 @@ export function normalizeConfig(config) {
140
140
  return []
141
141
  })()
142
142
 
143
+ // Normalize prefix option
144
+ if (typeof config.prefix === 'function') {
145
+ log.warn('prefix-function', [
146
+ 'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
147
+ 'Update `prefix` in your configuration to be a string to eliminate this warning.',
148
+ // TODO: Add https://tw.wtf/prefix-function
149
+ ])
150
+ config.prefix = ''
151
+ } else {
152
+ config.prefix = config.prefix ?? ''
153
+ }
154
+
143
155
  // Normalize the `content`
144
156
  config.content = {
145
157
  files: (() => {
@@ -170,7 +182,7 @@ export function normalizeConfig(config) {
170
182
 
171
183
  let extractors = {}
172
184
 
173
- extractors.DEFAULT = (() => {
185
+ let defaultExtractor = (() => {
174
186
  if (config.purge?.options?.defaultExtractor) {
175
187
  return config.purge.options.defaultExtractor
176
188
  }
@@ -182,6 +194,10 @@ export function normalizeConfig(config) {
182
194
  return undefined
183
195
  })()
184
196
 
197
+ if (defaultExtractor !== undefined) {
198
+ extractors.DEFAULT = defaultExtractor
199
+ }
200
+
185
201
  // Functions
186
202
  if (typeof extract === 'function') {
187
203
  extractors.DEFAULT = extract
@@ -0,0 +1,71 @@
1
+ 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
+ let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
4
+ let LENGTH = /^-?(\d+)(.*?)$/g
5
+
6
+ export function parseBoxShadowValue(input) {
7
+ let shadows = input.split(COMMA)
8
+ return shadows.map((shadow) => {
9
+ let value = shadow.trim()
10
+ let result = { raw: value }
11
+ let parts = value.split(SPACE)
12
+ let seen = new Set()
13
+
14
+ for (let part of parts) {
15
+ // Reset index, since the regex is stateful.
16
+ LENGTH.lastIndex = 0
17
+
18
+ // Keyword
19
+ if (!seen.has('KEYWORD') && KEYWORDS.has(part)) {
20
+ result.keyword = part
21
+ seen.add('KEYWORD')
22
+ }
23
+
24
+ // Length value
25
+ else if (LENGTH.test(part)) {
26
+ if (!seen.has('X')) {
27
+ result.x = part
28
+ seen.add('X')
29
+ } else if (!seen.has('Y')) {
30
+ result.y = part
31
+ seen.add('Y')
32
+ } else if (!seen.has('BLUR')) {
33
+ result.blur = part
34
+ seen.add('BLUR')
35
+ } else if (!seen.has('SPREAD')) {
36
+ result.spread = part
37
+ seen.add('SPREAD')
38
+ }
39
+ }
40
+
41
+ // Color or unknown
42
+ else {
43
+ if (!result.color) {
44
+ result.color = part
45
+ } else {
46
+ if (!result.unknown) result.unknown = []
47
+ result.unknown.push(part)
48
+ }
49
+ }
50
+ }
51
+
52
+ // Check if valid
53
+ result.valid = result.x !== undefined && result.y !== undefined
54
+
55
+ return result
56
+ })
57
+ }
58
+
59
+ export function formatBoxShadowValue(shadows) {
60
+ return shadows
61
+ .map((shadow) => {
62
+ if (!shadow.valid) {
63
+ return shadow.raw
64
+ }
65
+
66
+ return [shadow.keyword, shadow.x, shadow.y, shadow.blur, shadow.spread, shadow.color]
67
+ .filter(Boolean)
68
+ .join(' ')
69
+ })
70
+ .join(', ')
71
+ }
@@ -1,7 +1,6 @@
1
1
  import selectorParser from 'postcss-selector-parser'
2
2
  import escapeCommas from './escapeCommas'
3
3
  import { withAlphaValue } from './withAlphaVariable'
4
- import isKeyframeRule from './isKeyframeRule'
5
4
  import {
6
5
  normalize,
7
6
  length,
@@ -16,36 +15,14 @@ import {
16
15
  relativeSize,
17
16
  position,
18
17
  lineWidth,
18
+ shadow,
19
19
  } from './dataTypes'
20
-
21
- export function applyStateToMarker(selector, marker, state, join) {
22
- let markerIdx = selector.search(new RegExp(`${marker}[:[]`))
23
-
24
- if (markerIdx === -1) {
25
- return join(marker + state, selector)
26
- }
27
-
28
- let markerSelector = selector.slice(markerIdx, selector.indexOf(' ', markerIdx))
29
-
30
- return join(
31
- marker + state + markerSelector.slice(markerIdx + marker.length),
32
- selector.replace(markerSelector, '')
33
- )
34
- }
20
+ import negateValue from './negateValue'
35
21
 
36
22
  export function updateAllClasses(selectors, updateClass) {
37
23
  let parser = selectorParser((selectors) => {
38
24
  selectors.walkClasses((sel) => {
39
- let updatedClass = updateClass(sel.value, {
40
- withAttr(className, attr) {
41
- sel.parent.insertAfter(sel, selectorParser.attribute({ attribute: attr.slice(1, -1) }))
42
- return className
43
- },
44
- withPseudo(className, pseudo) {
45
- sel.parent.insertAfter(sel, selectorParser.pseudo({ value: pseudo }))
46
- return className
47
- },
48
- })
25
+ let updatedClass = updateClass(sel.value)
49
26
  sel.value = updatedClass
50
27
  if (sel.raws && sel.raws.value) {
51
28
  sel.raws.value = escapeCommas(sel.raws.value)
@@ -58,133 +35,50 @@ export function updateAllClasses(selectors, updateClass) {
58
35
  return result
59
36
  }
60
37
 
61
- export function updateLastClasses(selectors, updateClass) {
62
- let parser = selectorParser((selectors) => {
63
- selectors.each((sel) => {
64
- let lastClass = sel.filter(({ type }) => type === 'class').pop()
65
-
66
- if (lastClass === undefined) {
67
- return
68
- }
69
-
70
- let updatedClass = updateClass(lastClass.value, {
71
- withPseudo(className, pseudo) {
72
- lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `${pseudo}` }))
73
- return className
74
- },
75
- })
76
- lastClass.value = updatedClass
77
- if (lastClass.raws && lastClass.raws.value) {
78
- lastClass.raws.value = escapeCommas(lastClass.raws.value)
79
- }
80
- })
81
- })
82
- let result = parser.processSync(selectors)
83
-
84
- return result
85
- }
86
-
87
- function splitByNotEscapedCommas(str) {
88
- let chunks = []
89
- let currentChunk = ''
90
- for (let i = 0; i < str.length; i++) {
91
- if (str[i] === ',' && str[i - 1] !== '\\') {
92
- chunks.push(currentChunk)
93
- currentChunk = ''
94
- } else {
95
- currentChunk += str[i]
96
- }
38
+ function resolveArbitraryValue(modifier, validate) {
39
+ if (!isArbitraryValue(modifier)) {
40
+ return undefined
97
41
  }
98
- chunks.push(currentChunk)
99
- return chunks
100
- }
101
42
 
102
- export function transformAllSelectors(transformSelector, { wrap, withRule } = {}) {
103
- return ({ container }) => {
104
- container.walkRules((rule) => {
105
- if (isKeyframeRule(rule)) {
106
- return rule
107
- }
108
- let transformed = splitByNotEscapedCommas(rule.selector).map(transformSelector).join(',')
109
- rule.selector = transformed
110
- if (withRule) {
111
- withRule(rule)
112
- }
113
- return rule
114
- })
43
+ let value = modifier.slice(1, -1)
115
44
 
116
- if (wrap) {
117
- let wrapper = wrap()
118
- let nodes = container.nodes
119
- container.removeAll()
120
- wrapper.append(nodes)
121
- container.append(wrapper)
122
- }
45
+ if (!validate(value)) {
46
+ return undefined
123
47
  }
48
+
49
+ return normalize(value)
124
50
  }
125
51
 
126
- export function transformAllClasses(transformClass, { wrap, withRule } = {}) {
127
- return ({ container }) => {
128
- container.walkRules((rule) => {
129
- let selector = rule.selector
130
- let variantSelector = updateAllClasses(selector, transformClass)
131
- rule.selector = variantSelector
132
- if (withRule) {
133
- withRule(rule)
134
- }
135
- return rule
136
- })
52
+ function asNegativeValue(modifier, lookup = {}, validate) {
53
+ let positiveValue = lookup[modifier]
137
54
 
138
- if (wrap) {
139
- let wrapper = wrap()
140
- let nodes = container.nodes
141
- container.removeAll()
142
- wrapper.append(nodes)
143
- container.append(wrapper)
144
- }
55
+ if (positiveValue !== undefined) {
56
+ return negateValue(positiveValue)
145
57
  }
146
- }
147
58
 
148
- export function transformLastClasses(transformClass, { wrap, withRule } = {}) {
149
- return ({ container }) => {
150
- container.walkRules((rule) => {
151
- let selector = rule.selector
152
- let variantSelector = updateLastClasses(selector, transformClass)
153
- rule.selector = variantSelector
154
- if (withRule) {
155
- withRule(rule)
156
- }
157
- return rule
158
- })
59
+ if (isArbitraryValue(modifier)) {
60
+ let resolved = resolveArbitraryValue(modifier, validate)
159
61
 
160
- if (wrap) {
161
- let wrapper = wrap()
162
- let nodes = container.nodes
163
- container.removeAll()
164
- wrapper.append(nodes)
165
- container.append(wrapper)
62
+ if (resolved === undefined) {
63
+ return undefined
166
64
  }
65
+
66
+ return negateValue(resolved)
167
67
  }
168
68
  }
169
69
 
170
- export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
171
- let value = lookup[modifier]
70
+ export function asValue(modifier, options = {}, { validate = () => true } = {}) {
71
+ let value = options.values?.[modifier]
172
72
 
173
73
  if (value !== undefined) {
174
74
  return value
175
75
  }
176
76
 
177
- if (!isArbitraryValue(modifier)) {
178
- return undefined
179
- }
180
-
181
- value = modifier.slice(1, -1)
182
-
183
- if (!validate(value)) {
184
- return undefined
77
+ if (options.supportsNegativeValues && modifier.startsWith('-')) {
78
+ return asNegativeValue(modifier.slice(1), options.values, validate)
185
79
  }
186
80
 
187
- return normalize(value)
81
+ return resolveArbitraryValue(modifier, validate)
188
82
  }
189
83
 
190
84
  function isArbitraryValue(input) {
@@ -201,16 +95,16 @@ function splitAlpha(modifier) {
201
95
  return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
202
96
  }
203
97
 
204
- export function asColor(modifier, lookup = {}, tailwindConfig = {}) {
205
- if (lookup[modifier] !== undefined) {
206
- return lookup[modifier]
98
+ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
99
+ if (options.values?.[modifier] !== undefined) {
100
+ return options.values?.[modifier]
207
101
  }
208
102
 
209
103
  let [color, alpha] = splitAlpha(modifier)
210
104
 
211
105
  if (alpha !== undefined) {
212
106
  let normalizedColor =
213
- lookup[color] ?? (isArbitraryValue(color) ? color.slice(1, -1) : undefined)
107
+ options.values?.[color] ?? (isArbitraryValue(color) ? color.slice(1, -1) : undefined)
214
108
 
215
109
  if (normalizedColor === undefined) {
216
110
  return undefined
@@ -227,16 +121,16 @@ export function asColor(modifier, lookup = {}, tailwindConfig = {}) {
227
121
  return withAlphaValue(normalizedColor, tailwindConfig.theme.opacity[alpha])
228
122
  }
229
123
 
230
- return asValue(modifier, lookup, { validate: validateColor })
124
+ return asValue(modifier, options, { validate: validateColor })
231
125
  }
232
126
 
233
- export function asLookupValue(modifier, lookup = {}) {
234
- return lookup[modifier]
127
+ export function asLookupValue(modifier, options = {}) {
128
+ return options.values?.[modifier]
235
129
  }
236
130
 
237
131
  function guess(validate) {
238
- return (modifier, lookup) => {
239
- return asValue(modifier, lookup, { validate })
132
+ return (modifier, options) => {
133
+ return asValue(modifier, options, { validate })
240
134
  }
241
135
  }
242
136
 
@@ -255,6 +149,7 @@ let typeMap = {
255
149
  'line-width': guess(lineWidth),
256
150
  'absolute-size': guess(absoluteSize),
257
151
  'relative-size': guess(relativeSize),
152
+ shadow: guess(shadow),
258
153
  }
259
154
 
260
155
  let supportedTypes = Object.keys(typeMap)
@@ -265,22 +160,31 @@ function splitAtFirst(input, delim) {
265
160
  return [input.slice(0, idx), input.slice(idx + 1)]
266
161
  }
267
162
 
268
- export function coerceValue(types, modifier, values, tailwindConfig) {
163
+ export function coerceValue(types, modifier, options, tailwindConfig) {
269
164
  if (isArbitraryValue(modifier)) {
270
- let [explicitType, value] = splitAtFirst(modifier.slice(1, -1), ':')
165
+ let arbitraryValue = modifier.slice(1, -1)
166
+ let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
167
+
168
+ // It could be that this resolves to `url(https` which is not a valid
169
+ // identifier. We currently only support "simple" words with dashes or
170
+ // underscores. E.g.: family-name
171
+ if (!/^[\w-_]+$/g.test(explicitType)) {
172
+ value = arbitraryValue
173
+ }
271
174
 
272
- if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
175
+ //
176
+ else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
273
177
  return []
274
178
  }
275
179
 
276
180
  if (value.length > 0 && supportedTypes.includes(explicitType)) {
277
- return [asValue(`[${value}]`, values, tailwindConfig), explicitType]
181
+ return [asValue(`[${value}]`, options), explicitType]
278
182
  }
279
183
  }
280
184
 
281
185
  // Find first matching type
282
186
  for (let type of [].concat(types)) {
283
- let result = typeMap[type](modifier, values, tailwindConfig)
187
+ let result = typeMap[type](modifier, options, { tailwindConfig })
284
188
  if (result) return [result, type]
285
189
  }
286
190
 
@@ -2,13 +2,10 @@ import parser from 'postcss-selector-parser'
2
2
  import { tap } from './tap'
3
3
 
4
4
  export default function (prefix, selector) {
5
- const getPrefix =
6
- typeof prefix === 'function' ? prefix : () => (prefix === undefined ? '' : prefix)
7
-
8
5
  return parser((selectors) => {
9
6
  selectors.walkClasses((classSelector) => {
10
7
  tap(classSelector.value, (baseClass) => {
11
- classSelector.value = `${getPrefix('.' + baseClass)}${baseClass}`
8
+ classSelector.value = `${prefix}${baseClass}`
12
9
  })
13
10
  })
14
11
  }).processSync(selector)
@@ -40,10 +40,16 @@ function mergeWith(target, ...sources) {
40
40
  const configUtils = {
41
41
  colors,
42
42
  negative(scale) {
43
+ // TODO: Log that this function isn't really needed anymore?
43
44
  return Object.keys(scale)
44
45
  .filter((key) => scale[key] !== '0')
45
46
  .reduce((negativeScale, key) => {
46
- negativeScale[`-${key}`] = negateValue(scale[key])
47
+ let negativeValue = negateValue(scale[key])
48
+
49
+ if (negativeValue !== undefined) {
50
+ negativeScale[`-${key}`] = negativeValue
51
+ }
52
+
47
53
  return negativeScale
48
54
  }, {})
49
55
  },
@@ -2,7 +2,12 @@ import postcss from 'postcss'
2
2
 
3
3
  export default function transformThemeValue(themeSection) {
4
4
  if (['fontSize', 'outline'].includes(themeSection)) {
5
- return (value) => (Array.isArray(value) ? value[0] : value)
5
+ return (value) => {
6
+ if (typeof value === 'function') value = value({})
7
+ if (Array.isArray(value)) value = value[0]
8
+
9
+ return value
10
+ }
6
11
  }
7
12
 
8
13
  if (
@@ -20,18 +25,28 @@ export default function transformThemeValue(themeSection) {
20
25
  'animation',
21
26
  ].includes(themeSection)
22
27
  ) {
23
- return (value) => (Array.isArray(value) ? value.join(', ') : value)
28
+ return (value) => {
29
+ if (typeof value === 'function') value = value({})
30
+ if (Array.isArray(value)) value = value.join(', ')
31
+
32
+ return value
33
+ }
24
34
  }
25
35
 
26
36
  // For backwards compatibility reasons, before we switched to underscores
27
37
  // instead of commas for arbitrary values.
28
38
  if (['gridTemplateColumns', 'gridTemplateRows', 'objectPosition'].includes(themeSection)) {
29
- return (value) => (typeof value === 'string' ? postcss.list.comma(value).join(' ') : value)
30
- }
39
+ return (value) => {
40
+ if (typeof value === 'function') value = value({})
41
+ if (typeof value === 'string') value = postcss.list.comma(value).join(' ')
31
42
 
32
- if (themeSection === 'colors') {
33
- return (value) => (typeof value === 'function' ? value({}) : value)
43
+ return value
44
+ }
34
45
  }
35
46
 
36
- return (value) => value
47
+ return (value) => {
48
+ if (typeof value === 'function') value = value({})
49
+
50
+ return value
51
+ }
37
52
  }