tailwindcss 0.0.0-insiders.fda68f7 → 0.0.0-oxide.6bf5e56

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 (195) hide show
  1. package/CHANGELOG.md +603 -2
  2. package/LICENSE +1 -2
  3. package/README.md +14 -6
  4. package/colors.d.ts +3 -0
  5. package/colors.js +2 -304
  6. package/defaultConfig.d.ts +3 -0
  7. package/defaultConfig.js +2 -4
  8. package/defaultTheme.d.ts +4 -0
  9. package/defaultTheme.js +2 -4
  10. package/lib/cli/build/deps.js +54 -0
  11. package/lib/cli/build/index.js +48 -0
  12. package/lib/cli/build/plugin.js +367 -0
  13. package/lib/cli/build/utils.js +78 -0
  14. package/lib/cli/build/watching.js +178 -0
  15. package/lib/cli/help/index.js +71 -0
  16. package/lib/cli/index.js +18 -0
  17. package/lib/cli/init/index.js +46 -0
  18. package/lib/cli/shared.js +13 -0
  19. package/lib/cli-peer-dependencies.js +22 -14
  20. package/lib/cli.js +217 -743
  21. package/lib/constants.js +41 -34
  22. package/lib/corePluginList.js +178 -5
  23. package/lib/corePlugins.js +3879 -2941
  24. package/lib/css/preflight.css +22 -9
  25. package/lib/featureFlags.js +61 -50
  26. package/lib/index.js +45 -28
  27. package/lib/lib/cacheInvalidation.js +90 -0
  28. package/lib/lib/collapseAdjacentRules.js +52 -36
  29. package/lib/lib/collapseDuplicateDeclarations.js +83 -0
  30. package/lib/lib/content.js +176 -0
  31. package/lib/lib/defaultExtractor.js +236 -0
  32. package/lib/lib/detectNesting.js +37 -0
  33. package/lib/lib/evaluateTailwindFunctions.js +203 -161
  34. package/lib/lib/expandApplyAtRules.js +502 -221
  35. package/lib/lib/expandTailwindAtRules.js +258 -243
  36. package/lib/lib/findAtConfigPath.js +44 -0
  37. package/lib/lib/generateRules.js +775 -320
  38. package/lib/lib/getModuleDependencies.js +44 -46
  39. package/lib/lib/normalizeTailwindDirectives.js +79 -60
  40. package/lib/lib/offsets.js +217 -0
  41. package/lib/lib/partitionApplyAtRules.js +56 -0
  42. package/lib/lib/regex.js +60 -0
  43. package/lib/lib/resolveDefaultsAtRules.js +150 -94
  44. package/lib/lib/setupContextUtils.js +1146 -599
  45. package/lib/lib/setupTrackingContext.js +129 -177
  46. package/lib/lib/sharedState.js +53 -21
  47. package/lib/lib/substituteScreenAtRules.js +26 -28
  48. package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
  49. package/lib/postcss-plugins/nesting/index.js +19 -0
  50. package/lib/postcss-plugins/nesting/plugin.js +87 -0
  51. package/lib/processTailwindFeatures.js +58 -53
  52. package/lib/public/colors.js +331 -0
  53. package/lib/public/create-plugin.js +15 -0
  54. package/lib/public/default-config.js +16 -0
  55. package/lib/public/default-theme.js +16 -0
  56. package/lib/public/resolve-config.js +22 -0
  57. package/lib/util/bigSign.js +7 -6
  58. package/lib/util/buildMediaQuery.js +21 -32
  59. package/lib/util/cloneDeep.js +16 -14
  60. package/lib/util/cloneNodes.js +29 -15
  61. package/lib/util/color.js +90 -66
  62. package/lib/util/configurePlugins.js +17 -15
  63. package/lib/util/createPlugin.js +23 -26
  64. package/lib/util/createUtilityPlugin.js +46 -46
  65. package/lib/util/dataTypes.js +242 -0
  66. package/lib/util/defaults.js +20 -15
  67. package/lib/util/escapeClassName.js +18 -17
  68. package/lib/util/escapeCommas.js +7 -6
  69. package/lib/util/flattenColorPalette.js +13 -12
  70. package/lib/util/formatVariantSelector.js +285 -0
  71. package/lib/util/getAllConfigs.js +44 -18
  72. package/lib/util/hashConfig.js +15 -12
  73. package/lib/util/isKeyframeRule.js +7 -6
  74. package/lib/util/isPlainObject.js +11 -11
  75. package/lib/util/isSyntacticallyValidPropertyValue.js +72 -0
  76. package/lib/util/log.js +52 -33
  77. package/lib/util/nameClass.js +37 -26
  78. package/lib/util/negateValue.js +31 -17
  79. package/lib/util/normalizeConfig.js +281 -0
  80. package/lib/util/normalizeScreens.js +170 -0
  81. package/lib/util/parseAnimationValue.js +85 -54
  82. package/lib/util/parseBoxShadowValue.js +84 -0
  83. package/lib/util/parseDependency.js +41 -70
  84. package/lib/util/parseGlob.js +34 -0
  85. package/lib/util/parseObjectStyles.js +30 -24
  86. package/lib/util/pluginUtils.js +252 -287
  87. package/lib/util/prefixSelector.js +20 -20
  88. package/lib/util/removeAlphaVariables.js +29 -0
  89. package/lib/util/resolveConfig.js +221 -256
  90. package/lib/util/resolveConfigPath.js +43 -48
  91. package/lib/util/responsive.js +18 -14
  92. package/lib/util/splitAtTopLevelOnly.js +43 -0
  93. package/lib/util/tap.js +8 -7
  94. package/lib/util/toColorValue.js +7 -6
  95. package/lib/util/toPath.js +27 -8
  96. package/lib/util/transformThemeValue.js +67 -28
  97. package/lib/util/validateConfig.js +24 -0
  98. package/lib/util/validateFormalSyntax.js +24 -0
  99. package/lib/util/withAlphaVariable.js +67 -57
  100. package/nesting/index.js +2 -12
  101. package/package.json +60 -65
  102. package/peers/index.js +76445 -84221
  103. package/plugin.d.ts +11 -0
  104. package/plugin.js +1 -2
  105. package/resolveConfig.d.ts +12 -0
  106. package/resolveConfig.js +2 -7
  107. package/scripts/create-plugin-list.js +2 -2
  108. package/scripts/generate-types.js +105 -0
  109. package/scripts/release-channel.js +18 -0
  110. package/scripts/release-notes.js +21 -0
  111. package/scripts/type-utils.js +27 -0
  112. package/src/cli/build/deps.js +56 -0
  113. package/src/cli/build/index.js +49 -0
  114. package/src/cli/build/plugin.js +439 -0
  115. package/src/cli/build/utils.js +76 -0
  116. package/src/cli/build/watching.js +227 -0
  117. package/src/cli/help/index.js +70 -0
  118. package/src/cli/index.js +3 -0
  119. package/src/cli/init/index.js +50 -0
  120. package/src/cli/shared.js +6 -0
  121. package/src/cli-peer-dependencies.js +7 -1
  122. package/src/cli.js +50 -575
  123. package/src/corePluginList.js +1 -1
  124. package/src/corePlugins.js +2405 -1948
  125. package/src/css/preflight.css +22 -9
  126. package/src/featureFlags.js +26 -10
  127. package/src/index.js +19 -6
  128. package/src/lib/cacheInvalidation.js +52 -0
  129. package/src/lib/collapseAdjacentRules.js +21 -2
  130. package/src/lib/collapseDuplicateDeclarations.js +93 -0
  131. package/src/lib/content.js +212 -0
  132. package/src/lib/defaultExtractor.js +211 -0
  133. package/src/lib/detectNesting.js +39 -0
  134. package/src/lib/evaluateTailwindFunctions.js +84 -10
  135. package/src/lib/expandApplyAtRules.js +508 -153
  136. package/src/lib/expandTailwindAtRules.js +130 -104
  137. package/src/lib/findAtConfigPath.js +48 -0
  138. package/src/lib/generateRules.js +596 -70
  139. package/src/lib/normalizeTailwindDirectives.js +10 -3
  140. package/src/lib/offsets.js +270 -0
  141. package/src/lib/partitionApplyAtRules.js +52 -0
  142. package/src/lib/regex.js +74 -0
  143. package/src/lib/resolveDefaultsAtRules.js +105 -47
  144. package/src/lib/setupContextUtils.js +828 -196
  145. package/src/lib/setupTrackingContext.js +19 -54
  146. package/src/lib/sharedState.js +45 -7
  147. package/src/lib/substituteScreenAtRules.js +6 -3
  148. package/src/postcss-plugins/nesting/README.md +42 -0
  149. package/src/postcss-plugins/nesting/index.js +13 -0
  150. package/src/postcss-plugins/nesting/plugin.js +80 -0
  151. package/src/processTailwindFeatures.js +19 -2
  152. package/src/public/colors.js +300 -0
  153. package/src/public/create-plugin.js +2 -0
  154. package/src/public/default-config.js +4 -0
  155. package/src/public/default-theme.js +4 -0
  156. package/src/public/resolve-config.js +7 -0
  157. package/src/util/buildMediaQuery.js +14 -16
  158. package/src/util/cloneNodes.js +19 -2
  159. package/src/util/color.js +31 -14
  160. package/src/util/createUtilityPlugin.js +2 -11
  161. package/src/util/dataTypes.js +256 -0
  162. package/src/util/defaults.js +6 -0
  163. package/src/util/formatVariantSelector.js +319 -0
  164. package/src/util/getAllConfigs.js +19 -0
  165. package/src/util/isSyntacticallyValidPropertyValue.js +61 -0
  166. package/src/util/log.js +23 -22
  167. package/src/util/nameClass.js +14 -6
  168. package/src/util/negateValue.js +15 -5
  169. package/src/util/normalizeConfig.js +300 -0
  170. package/src/util/normalizeScreens.js +140 -0
  171. package/src/util/parseAnimationValue.js +7 -1
  172. package/src/util/parseBoxShadowValue.js +72 -0
  173. package/src/util/parseDependency.js +37 -38
  174. package/src/util/parseGlob.js +24 -0
  175. package/src/util/pluginUtils.js +216 -197
  176. package/src/util/prefixSelector.js +7 -8
  177. package/src/util/removeAlphaVariables.js +24 -0
  178. package/src/util/resolveConfig.js +86 -91
  179. package/src/util/splitAtTopLevelOnly.js +45 -0
  180. package/src/util/toPath.js +23 -1
  181. package/src/util/transformThemeValue.js +33 -8
  182. package/src/util/validateConfig.js +13 -0
  183. package/src/util/validateFormalSyntax.js +34 -0
  184. package/src/util/withAlphaVariable.js +14 -9
  185. package/stubs/defaultConfig.stub.js +186 -117
  186. package/stubs/simpleConfig.stub.js +1 -1
  187. package/types/config.d.ts +362 -0
  188. package/types/generated/.gitkeep +0 -0
  189. package/types/generated/colors.d.ts +276 -0
  190. package/types/generated/corePluginList.d.ts +1 -0
  191. package/types/generated/default-theme.d.ts +342 -0
  192. package/types/index.d.ts +7 -0
  193. package/lib/lib/setupWatchingContext.js +0 -331
  194. package/nesting/plugin.js +0 -41
  195. package/src/lib/setupWatchingContext.js +0 -306
@@ -1,45 +1,44 @@
1
- import isGlob from 'is-glob'
2
- import globParent from 'glob-parent'
3
- import path from 'path'
4
-
5
- // Based on `glob-base`
6
- // https://github.com/micromatch/glob-base/blob/master/index.js
7
- function parseGlob(pattern) {
8
- let glob = pattern
9
- let base = globParent(pattern)
10
-
11
- if (base !== '.') {
12
- glob = pattern.substr(base.length)
13
- if (glob.charAt(0) === '/') {
14
- glob = glob.substr(1)
15
- }
16
- }
17
-
18
- if (glob.substr(0, 2) === './') {
19
- glob = glob.substr(2)
1
+ // @ts-check
2
+
3
+ /**
4
+ * @typedef {{type: 'dependency', file: string} | {type: 'dir-dependency', dir: string, glob: string}} Dependency
5
+ */
6
+
7
+ /**
8
+ *
9
+ * @param {import('../lib/content.js').ContentPath} contentPath
10
+ * @returns {Dependency[]}
11
+ */
12
+ export default function parseDependency(contentPath) {
13
+ if (contentPath.ignore) {
14
+ return []
20
15
  }
21
- if (glob.charAt(0) === '/') {
22
- glob = glob.substr(1)
23
- }
24
-
25
- return { base, glob }
26
- }
27
-
28
- export default function parseDependency(normalizedFileOrGlob) {
29
- let message
30
16
 
31
- if (isGlob(normalizedFileOrGlob)) {
32
- let { base, glob } = parseGlob(normalizedFileOrGlob)
33
- message = { type: 'dir-dependency', dir: path.resolve(base), glob }
34
- } else {
35
- message = { type: 'dependency', file: path.resolve(normalizedFileOrGlob) }
17
+ if (!contentPath.glob) {
18
+ return [
19
+ {
20
+ type: 'dependency',
21
+ file: contentPath.base,
22
+ },
23
+ ]
36
24
  }
37
25
 
38
- // rollup-plugin-postcss does not support dir-dependency messages
39
- // but directories can be watched in the same way as files
40
- if (message.type === 'dir-dependency' && process.env.ROLLUP_WATCH === 'true') {
41
- message = { type: 'dependency', file: message.dir }
26
+ if (process.env.ROLLUP_WATCH === 'true') {
27
+ // rollup-plugin-postcss does not support dir-dependency messages
28
+ // but directories can be watched in the same way as files
29
+ return [
30
+ {
31
+ type: 'dependency',
32
+ file: contentPath.base,
33
+ },
34
+ ]
42
35
  }
43
36
 
44
- return message
37
+ return [
38
+ {
39
+ type: 'dir-dependency',
40
+ dir: contentPath.base,
41
+ glob: contentPath.glob,
42
+ },
43
+ ]
45
44
  }
@@ -0,0 +1,24 @@
1
+ import globParent from 'glob-parent'
2
+
3
+ // Based on `glob-base`
4
+ // https://github.com/micromatch/glob-base/blob/master/index.js
5
+ export function parseGlob(pattern) {
6
+ let glob = pattern
7
+ let base = globParent(pattern)
8
+
9
+ if (base !== '.') {
10
+ glob = pattern.substr(base.length)
11
+ if (glob.charAt(0) === '/') {
12
+ glob = glob.substr(1)
13
+ }
14
+ }
15
+
16
+ if (glob.substr(0, 2) === './') {
17
+ glob = glob.substr(2)
18
+ }
19
+ if (glob.charAt(0) === '/') {
20
+ glob = glob.substr(1)
21
+ }
22
+
23
+ return { base, glob }
24
+ }
@@ -1,36 +1,30 @@
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
- import { parseColor } from './color'
6
-
7
- export function applyPseudoToMarker(selector, marker, state, join) {
8
- let states = [state]
9
-
10
- let markerIdx = selector.indexOf(marker + ':')
11
-
12
- if (markerIdx !== -1) {
13
- let existingMarker = selector.slice(markerIdx, selector.indexOf(' ', markerIdx))
14
-
15
- states = states.concat(
16
- selector.slice(markerIdx + marker.length + 1, existingMarker.length).split(':')
17
- )
18
-
19
- selector = selector.replace(existingMarker, '')
20
- }
21
-
22
- return join(`${[marker, ...states].join(':')}`, selector)
23
- }
4
+ import {
5
+ normalize,
6
+ length,
7
+ number,
8
+ percentage,
9
+ url,
10
+ color as validateColor,
11
+ genericName,
12
+ familyName,
13
+ image,
14
+ absoluteSize,
15
+ relativeSize,
16
+ position,
17
+ lineWidth,
18
+ shadow,
19
+ } from './dataTypes'
20
+ import negateValue from './negateValue'
21
+ import { backgroundSize } from './validateFormalSyntax'
22
+ import { flagEnabled } from '../featureFlags.js'
24
23
 
25
24
  export function updateAllClasses(selectors, updateClass) {
26
25
  let parser = selectorParser((selectors) => {
27
26
  selectors.walkClasses((sel) => {
28
- let updatedClass = updateClass(sel.value, {
29
- withPseudo(className, pseudo) {
30
- sel.parent.insertAfter(sel, selectorParser.pseudo({ value: `${pseudo}` }))
31
- return className
32
- },
33
- })
27
+ let updatedClass = updateClass(sel.value)
34
28
  sel.value = updatedClass
35
29
  if (sel.raws && sel.raws.value) {
36
30
  sel.raws.value = escapeCommas(sel.raws.value)
@@ -43,253 +37,278 @@ export function updateAllClasses(selectors, updateClass) {
43
37
  return result
44
38
  }
45
39
 
46
- export function updateLastClasses(selectors, updateClass) {
40
+ export function filterSelectorsForClass(selectors, classCandidate) {
47
41
  let parser = selectorParser((selectors) => {
48
42
  selectors.each((sel) => {
49
- let lastClass = sel.filter(({ type }) => type === 'class').pop()
50
-
51
- if (lastClass === undefined) {
52
- return
53
- }
54
-
55
- let updatedClass = updateClass(lastClass.value, {
56
- withPseudo(className, pseudo) {
57
- lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `${pseudo}` }))
58
- return className
59
- },
60
- })
61
- lastClass.value = updatedClass
62
- if (lastClass.raws && lastClass.raws.value) {
63
- lastClass.raws.value = escapeCommas(lastClass.raws.value)
43
+ const containsClass = sel.nodes.some(
44
+ (node) => node.type === 'class' && node.value === classCandidate
45
+ )
46
+ if (!containsClass) {
47
+ sel.remove()
64
48
  }
65
49
  })
66
50
  })
51
+
67
52
  let result = parser.processSync(selectors)
68
53
 
69
54
  return result
70
55
  }
71
56
 
72
- function splitByNotEscapedCommas(str) {
73
- let chunks = []
74
- let currentChunk = ''
75
- for (let i = 0; i < str.length; i++) {
76
- if (str[i] === ',' && str[i - 1] !== '\\') {
77
- chunks.push(currentChunk)
78
- currentChunk = ''
79
- } else {
80
- currentChunk += str[i]
81
- }
57
+ function resolveArbitraryValue(modifier, validate) {
58
+ if (!isArbitraryValue(modifier)) {
59
+ return undefined
82
60
  }
83
- chunks.push(currentChunk)
84
- return chunks
85
- }
86
61
 
87
- export function transformAllSelectors(transformSelector, { wrap, withRule } = {}) {
88
- return ({ container }) => {
89
- container.walkRules((rule) => {
90
- if (isKeyframeRule(rule)) {
91
- return rule
92
- }
93
- let transformed = splitByNotEscapedCommas(rule.selector).map(transformSelector).join(',')
94
- rule.selector = transformed
95
- if (withRule) {
96
- withRule(rule)
97
- }
98
- return rule
99
- })
62
+ let value = modifier.slice(1, -1)
100
63
 
101
- if (wrap) {
102
- let wrapper = wrap()
103
- let nodes = container.nodes
104
- container.removeAll()
105
- wrapper.append(nodes)
106
- container.append(wrapper)
107
- }
64
+ if (!validate(value)) {
65
+ return undefined
108
66
  }
67
+
68
+ return normalize(value)
109
69
  }
110
70
 
111
- export function transformAllClasses(transformClass, { wrap, withRule } = {}) {
112
- return ({ container }) => {
113
- container.walkRules((rule) => {
114
- let selector = rule.selector
115
- let variantSelector = updateAllClasses(selector, transformClass)
116
- rule.selector = variantSelector
117
- if (withRule) {
118
- withRule(rule)
119
- }
120
- return rule
121
- })
71
+ function asNegativeValue(modifier, lookup = {}, validate) {
72
+ let positiveValue = lookup[modifier]
122
73
 
123
- if (wrap) {
124
- let wrapper = wrap()
125
- let nodes = container.nodes
126
- container.removeAll()
127
- wrapper.append(nodes)
128
- container.append(wrapper)
129
- }
74
+ if (positiveValue !== undefined) {
75
+ return negateValue(positiveValue)
130
76
  }
131
- }
132
77
 
133
- export function transformLastClasses(transformClass, { wrap, withRule } = {}) {
134
- return ({ container }) => {
135
- container.walkRules((rule) => {
136
- let selector = rule.selector
137
- let variantSelector = updateLastClasses(selector, transformClass)
138
- rule.selector = variantSelector
139
- if (withRule) {
140
- withRule(rule)
141
- }
142
- return rule
143
- })
78
+ if (isArbitraryValue(modifier)) {
79
+ let resolved = resolveArbitraryValue(modifier, validate)
144
80
 
145
- if (wrap) {
146
- let wrapper = wrap()
147
- let nodes = container.nodes
148
- container.removeAll()
149
- wrapper.append(nodes)
150
- container.append(wrapper)
81
+ if (resolved === undefined) {
82
+ return undefined
151
83
  }
84
+
85
+ return negateValue(resolved)
152
86
  }
153
87
  }
154
88
 
155
- export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
156
- let value = lookup[modifier]
89
+ export function asValue(modifier, options = {}, { validate = () => true } = {}) {
90
+ let value = options.values?.[modifier]
157
91
 
158
92
  if (value !== undefined) {
159
93
  return value
160
94
  }
161
95
 
162
- if (modifier[0] !== '[' || modifier[modifier.length - 1] !== ']') {
163
- return undefined
96
+ if (options.supportsNegativeValues && modifier.startsWith('-')) {
97
+ return asNegativeValue(modifier.slice(1), options.values, validate)
164
98
  }
165
99
 
166
- value = modifier.slice(1, -1)
167
-
168
- if (!validate(value)) {
169
- return undefined
170
- }
171
-
172
- // convert `_` to ` `, escept for escaped underscores `\_`
173
- value = value
174
- .replace(/([^\\])_/g, '$1 ')
175
- .replace(/^_/g, ' ')
176
- .replace(/\\_/g, '_')
177
-
178
- // add spaces around operators inside calc() that do not follow an operator or (
179
- return value.replace(
180
- /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
181
- '$1 $2 '
182
- )
183
- }
184
-
185
- export function asUnit(modifier, units, lookup = {}) {
186
- return asValue(modifier, lookup, {
187
- validate: (value) => {
188
- let unitsPattern = `(?:${units.join('|')})`
189
- return (
190
- new RegExp(`${unitsPattern}$`).test(value) ||
191
- new RegExp(`^calc\\(.+?${unitsPattern}`).test(value)
192
- )
193
- },
194
- })
100
+ return resolveArbitraryValue(modifier, validate)
195
101
  }
196
102
 
197
103
  function isArbitraryValue(input) {
198
104
  return input.startsWith('[') && input.endsWith(']')
199
105
  }
200
106
 
201
- function splitAlpha(modifier) {
107
+ function splitUtilityModifier(modifier) {
202
108
  let slashIdx = modifier.lastIndexOf('/')
203
109
 
204
110
  if (slashIdx === -1 || slashIdx === modifier.length - 1) {
205
- return [modifier]
111
+ return [modifier, undefined]
112
+ }
113
+
114
+ let arbitrary = isArbitraryValue(modifier)
115
+
116
+ // The modifier could be of the form `[foo]/[bar]`
117
+ // We want to handle this case properly
118
+ // without affecting `[foo/bar]`
119
+ if (arbitrary && !modifier.includes(']/[')) {
120
+ return [modifier, undefined]
206
121
  }
207
122
 
208
123
  return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
209
124
  }
210
125
 
211
- export function asColor(modifier, lookup = {}, tailwindConfig = {}) {
212
- if (lookup[modifier] !== undefined) {
213
- return lookup[modifier]
126
+ export function parseColorFormat(value) {
127
+ if (typeof value === 'string' && value.includes('<alpha-value>')) {
128
+ let oldValue = value
129
+
130
+ return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
131
+ }
132
+
133
+ return value
134
+ }
135
+
136
+ function unwrapArbitraryModifier(modifier) {
137
+ modifier = modifier.slice(1, -1)
138
+ if (modifier.startsWith('--')) {
139
+ modifier = `var(${modifier})`
140
+ }
141
+ return modifier
142
+ }
143
+
144
+ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
145
+ if (options.values?.[modifier] !== undefined) {
146
+ return parseColorFormat(options.values?.[modifier])
214
147
  }
215
148
 
216
- let [color, alpha] = splitAlpha(modifier)
149
+ // TODO: Hoist this up to getMatchingTypes or something
150
+ // We do this here because we need the alpha value (if any)
151
+ let [color, alpha] = splitUtilityModifier(modifier)
152
+
153
+ if (alpha !== undefined) {
154
+ let normalizedColor =
155
+ options.values?.[color] ?? (isArbitraryValue(color) ? color.slice(1, -1) : undefined)
156
+
157
+ if (normalizedColor === undefined) {
158
+ return undefined
159
+ }
160
+
161
+ normalizedColor = parseColorFormat(normalizedColor)
217
162
 
218
- if (lookup[color] !== undefined) {
219
163
  if (isArbitraryValue(alpha)) {
220
- return withAlphaValue(lookup[color], alpha.slice(1, -1))
164
+ return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha))
221
165
  }
222
166
 
223
167
  if (tailwindConfig.theme?.opacity?.[alpha] === undefined) {
224
168
  return undefined
225
169
  }
226
170
 
227
- return withAlphaValue(lookup[color], tailwindConfig.theme.opacity[alpha])
171
+ return withAlphaValue(normalizedColor, tailwindConfig.theme.opacity[alpha])
228
172
  }
229
173
 
230
- return asValue(modifier, lookup, {
231
- validate: (value) => parseColor(value) !== null,
232
- })
233
- }
234
-
235
- export function asAngle(modifier, lookup = {}) {
236
- return asUnit(modifier, ['deg', 'grad', 'rad', 'turn'], lookup)
174
+ return asValue(modifier, options, { validate: validateColor })
237
175
  }
238
176
 
239
- export function asLength(modifier, lookup = {}) {
240
- return asUnit(
241
- modifier,
242
- [
243
- 'cm',
244
- 'mm',
245
- 'Q',
246
- 'in',
247
- 'pc',
248
- 'pt',
249
- 'px',
250
- 'em',
251
- 'ex',
252
- 'ch',
253
- 'rem',
254
- 'lh',
255
- 'vw',
256
- 'vh',
257
- 'vmin',
258
- 'vmax',
259
- '%',
260
- ],
261
- lookup
262
- )
177
+ export function asLookupValue(modifier, options = {}) {
178
+ return options.values?.[modifier]
263
179
  }
264
180
 
265
- export function asLookupValue(modifier, lookup = {}) {
266
- return lookup[modifier]
181
+ function guess(validate) {
182
+ return (modifier, options) => {
183
+ return asValue(modifier, options, { validate })
184
+ }
267
185
  }
268
186
 
269
- let typeMap = {
187
+ export let typeMap = {
270
188
  any: asValue,
271
189
  color: asColor,
272
- angle: asAngle,
273
- length: asLength,
190
+ url: guess(url),
191
+ image: guess(image),
192
+ length: guess(length),
193
+ percentage: guess(percentage),
194
+ position: guess(position),
274
195
  lookup: asLookupValue,
196
+ 'generic-name': guess(genericName),
197
+ 'family-name': guess(familyName),
198
+ number: guess(number),
199
+ 'line-width': guess(lineWidth),
200
+ 'absolute-size': guess(absoluteSize),
201
+ 'relative-size': guess(relativeSize),
202
+ shadow: guess(shadow),
203
+ size: guess(backgroundSize),
275
204
  }
276
205
 
206
+ let supportedTypes = Object.keys(typeMap)
207
+
277
208
  function splitAtFirst(input, delim) {
278
- return (([first, ...rest]) => [first, rest.join(delim)])(input.split(delim))
209
+ let idx = input.indexOf(delim)
210
+ if (idx === -1) return [undefined, input]
211
+ return [input.slice(0, idx), input.slice(idx + 1)]
279
212
  }
280
213
 
281
- export function coerceValue(type, modifier, values, tailwindConfig) {
282
- let [scaleType, arbitraryType = scaleType] = [].concat(type)
214
+ export function coerceValue(types, modifier, options, tailwindConfig) {
215
+ if (options.values && modifier in options.values) {
216
+ for (let { type } of types ?? []) {
217
+ let result = typeMap[type](modifier, options, {
218
+ tailwindConfig,
219
+ })
220
+
221
+ if (result === undefined) {
222
+ continue
223
+ }
224
+
225
+ return [result, type, null]
226
+ }
227
+ }
283
228
 
284
229
  if (isArbitraryValue(modifier)) {
285
- let [explicitType, value] = splitAtFirst(modifier.slice(1, -1), ':')
230
+ let arbitraryValue = modifier.slice(1, -1)
231
+ let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
232
+
233
+ // It could be that this resolves to `url(https` which is not a valid
234
+ // identifier. We currently only support "simple" words with dashes or
235
+ // underscores. E.g.: family-name
236
+ if (!/^[\w-_]+$/g.test(explicitType)) {
237
+ value = arbitraryValue
238
+ }
286
239
 
287
- if (value.length > 0 && Object.keys(typeMap).includes(explicitType)) {
288
- return [asValue(`[${value}]`, values, tailwindConfig), explicitType]
240
+ //
241
+ else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
242
+ return []
289
243
  }
290
244
 
291
- return [typeMap[arbitraryType](modifier, values, tailwindConfig), arbitraryType]
245
+ if (value.length > 0 && supportedTypes.includes(explicitType)) {
246
+ return [asValue(`[${value}]`, options), explicitType, null]
247
+ }
248
+ }
249
+
250
+ let matches = getMatchingTypes(types, modifier, options, tailwindConfig)
251
+
252
+ // Find first matching type
253
+ for (let match of matches) {
254
+ return match
255
+ }
256
+
257
+ return []
258
+ }
259
+
260
+ /**
261
+ *
262
+ * @param {{type: string}[]} types
263
+ * @param {string} rawModifier
264
+ * @param {any} options
265
+ * @param {any} tailwindConfig
266
+ * @returns {Iterator<[value: string, type: string, modifier: string | null]>}
267
+ */
268
+ export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
269
+ let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
270
+
271
+ let [modifier, utilityModifier] = splitUtilityModifier(rawModifier)
272
+
273
+ let canUseUtilityModifier =
274
+ modifiersEnabled &&
275
+ options.modifiers != null &&
276
+ (options.modifiers === 'any' ||
277
+ (typeof options.modifiers === 'object' &&
278
+ ((utilityModifier && isArbitraryValue(utilityModifier)) ||
279
+ utilityModifier in options.modifiers)))
280
+
281
+ if (!canUseUtilityModifier) {
282
+ modifier = rawModifier
283
+ utilityModifier = undefined
292
284
  }
293
285
 
294
- return [typeMap[scaleType](modifier, values, tailwindConfig), scaleType]
286
+ if (utilityModifier !== undefined && modifier === '') {
287
+ modifier = 'DEFAULT'
288
+ }
289
+
290
+ // Check the full value first
291
+ // TODO: Move to asValue… somehow
292
+ if (utilityModifier !== undefined) {
293
+ if (typeof options.modifiers === 'object') {
294
+ let configValue = options.modifiers?.[utilityModifier] ?? null
295
+ if (configValue !== null) {
296
+ utilityModifier = configValue
297
+ } else if (isArbitraryValue(utilityModifier)) {
298
+ utilityModifier = unwrapArbitraryModifier(utilityModifier)
299
+ }
300
+ }
301
+ }
302
+
303
+ for (let { type } of types ?? []) {
304
+ let result = typeMap[type](modifier, options, {
305
+ tailwindConfig,
306
+ })
307
+
308
+ if (result === undefined) {
309
+ continue
310
+ }
311
+
312
+ yield [result, type, utilityModifier ?? null]
313
+ }
295
314
  }
@@ -1,15 +1,14 @@
1
1
  import parser from 'postcss-selector-parser'
2
- import { tap } from './tap'
3
-
4
- export default function (prefix, selector) {
5
- const getPrefix =
6
- typeof prefix === 'function' ? prefix : () => (prefix === undefined ? '' : prefix)
7
2
 
3
+ export default function (prefix, selector, prependNegative = false) {
8
4
  return parser((selectors) => {
9
5
  selectors.walkClasses((classSelector) => {
10
- tap(classSelector.value, (baseClass) => {
11
- classSelector.value = `${getPrefix('.' + baseClass)}${baseClass}`
12
- })
6
+ let baseClass = classSelector.value
7
+ let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-')
8
+
9
+ classSelector.value = shouldPlaceNegativeBeforePrefix
10
+ ? `-${prefix}${baseClass.slice(1)}`
11
+ : `${prefix}${baseClass}`
13
12
  })
14
13
  }).processSync(selector)
15
14
  }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * This function removes any uses of CSS variables used as an alpha channel
3
+ *
4
+ * This is required for selectors like `:visited` which do not allow
5
+ * changes in opacity or external control using CSS variables.
6
+ *
7
+ * @param {import('postcss').Container} container
8
+ * @param {string[]} toRemove
9
+ */
10
+ export function removeAlphaVariables(container, toRemove) {
11
+ container.walkDecls((decl) => {
12
+ if (toRemove.includes(decl.prop)) {
13
+ decl.remove()
14
+
15
+ return
16
+ }
17
+
18
+ for (let varName of toRemove) {
19
+ if (decl.value.includes(`/ var(${varName})`)) {
20
+ decl.value = decl.value.replace(`/ var(${varName})`, '')
21
+ }
22
+ }
23
+ })
24
+ }