tailwindcss 0.0.0-insiders.ea139f2 → 0.0.0-insiders.ea4e1cd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +15 -7
  3. package/colors.d.ts +3 -0
  4. package/colors.js +2 -1
  5. package/defaultConfig.d.ts +3 -0
  6. package/defaultConfig.js +2 -1
  7. package/defaultTheme.d.ts +4 -0
  8. package/defaultTheme.js +2 -1
  9. package/lib/cli/build/deps.js +62 -0
  10. package/lib/cli/build/index.js +54 -0
  11. package/lib/cli/build/plugin.js +378 -0
  12. package/lib/cli/build/utils.js +88 -0
  13. package/lib/cli/build/watching.js +182 -0
  14. package/lib/cli/help/index.js +73 -0
  15. package/lib/cli/index.js +230 -0
  16. package/lib/cli/init/index.js +63 -0
  17. package/lib/cli-peer-dependencies.js +28 -7
  18. package/lib/cli.js +4 -703
  19. package/lib/corePluginList.js +12 -3
  20. package/lib/corePlugins.js +2373 -1863
  21. package/lib/css/preflight.css +10 -8
  22. package/lib/featureFlags.js +49 -26
  23. package/lib/index.js +1 -31
  24. package/lib/lib/cacheInvalidation.js +92 -0
  25. package/lib/lib/collapseAdjacentRules.js +30 -10
  26. package/lib/lib/collapseDuplicateDeclarations.js +60 -4
  27. package/lib/lib/content.js +181 -0
  28. package/lib/lib/defaultExtractor.js +243 -0
  29. package/lib/lib/detectNesting.js +21 -10
  30. package/lib/lib/evaluateTailwindFunctions.js +115 -50
  31. package/lib/lib/expandApplyAtRules.js +467 -161
  32. package/lib/lib/expandTailwindAtRules.js +160 -133
  33. package/lib/lib/findAtConfigPath.js +46 -0
  34. package/lib/lib/generateRules.js +553 -200
  35. package/lib/lib/getModuleDependencies.js +88 -37
  36. package/lib/lib/load-config.js +42 -0
  37. package/lib/lib/normalizeTailwindDirectives.js +46 -33
  38. package/lib/lib/offsets.js +306 -0
  39. package/lib/lib/partitionApplyAtRules.js +58 -0
  40. package/lib/lib/regex.js +74 -0
  41. package/lib/lib/remap-bitfield.js +89 -0
  42. package/lib/lib/resolveDefaultsAtRules.js +98 -58
  43. package/lib/lib/setupContextUtils.js +773 -321
  44. package/lib/lib/setupTrackingContext.js +70 -75
  45. package/lib/lib/sharedState.js +78 -10
  46. package/lib/lib/substituteScreenAtRules.js +14 -10
  47. package/lib/oxide/cli/build/deps.js +89 -0
  48. package/lib/oxide/cli/build/index.js +53 -0
  49. package/lib/oxide/cli/build/plugin.js +375 -0
  50. package/lib/oxide/cli/build/utils.js +87 -0
  51. package/lib/oxide/cli/build/watching.js +179 -0
  52. package/lib/oxide/cli/help/index.js +72 -0
  53. package/lib/oxide/cli/index.js +214 -0
  54. package/lib/oxide/cli/init/index.js +52 -0
  55. package/lib/oxide/cli.js +5 -0
  56. package/lib/oxide/postcss-plugin.js +2 -0
  57. package/lib/plugin.js +98 -0
  58. package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
  59. package/lib/postcss-plugins/nesting/index.js +21 -0
  60. package/lib/postcss-plugins/nesting/plugin.js +89 -0
  61. package/lib/processTailwindFeatures.js +39 -26
  62. package/lib/public/colors.js +272 -246
  63. package/lib/public/create-plugin.js +9 -5
  64. package/lib/public/default-config.js +10 -6
  65. package/lib/public/default-theme.js +10 -6
  66. package/lib/public/load-config.js +12 -0
  67. package/lib/public/resolve-config.js +11 -6
  68. package/lib/util/applyImportantSelector.js +36 -0
  69. package/lib/util/bigSign.js +6 -1
  70. package/lib/util/buildMediaQuery.js +13 -6
  71. package/lib/util/cloneDeep.js +9 -6
  72. package/lib/util/cloneNodes.js +23 -3
  73. package/lib/util/color.js +70 -38
  74. package/lib/util/colorNames.js +752 -0
  75. package/lib/util/configurePlugins.js +7 -2
  76. package/lib/util/createPlugin.js +8 -6
  77. package/lib/util/createUtilityPlugin.js +16 -16
  78. package/lib/util/dataTypes.js +173 -108
  79. package/lib/util/defaults.js +14 -3
  80. package/lib/util/escapeClassName.js +13 -8
  81. package/lib/util/escapeCommas.js +7 -2
  82. package/lib/util/flattenColorPalette.js +11 -12
  83. package/lib/util/formatVariantSelector.js +228 -151
  84. package/lib/util/getAllConfigs.js +33 -12
  85. package/lib/util/hashConfig.js +9 -4
  86. package/lib/util/isKeyframeRule.js +7 -2
  87. package/lib/util/isPlainObject.js +7 -2
  88. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +25 -15
  89. package/lib/util/log.js +27 -13
  90. package/lib/util/nameClass.js +27 -10
  91. package/lib/util/negateValue.js +25 -8
  92. package/lib/util/normalizeConfig.js +139 -65
  93. package/lib/util/normalizeScreens.js +131 -11
  94. package/lib/util/parseAnimationValue.js +44 -40
  95. package/lib/util/parseBoxShadowValue.js +34 -23
  96. package/lib/util/parseDependency.js +39 -55
  97. package/lib/util/parseGlob.js +36 -0
  98. package/lib/util/parseObjectStyles.js +15 -10
  99. package/lib/util/pluginUtils.js +159 -69
  100. package/lib/util/prefixSelector.js +30 -12
  101. package/lib/util/pseudoElements.js +229 -0
  102. package/lib/util/removeAlphaVariables.js +31 -0
  103. package/lib/util/resolveConfig.js +97 -75
  104. package/lib/util/resolveConfigPath.js +30 -12
  105. package/lib/util/responsive.js +11 -6
  106. package/lib/util/splitAtTopLevelOnly.js +51 -0
  107. package/lib/util/tap.js +6 -1
  108. package/lib/util/toColorValue.js +7 -3
  109. package/lib/util/toPath.js +26 -3
  110. package/lib/util/transformThemeValue.js +40 -30
  111. package/lib/util/validateConfig.js +37 -0
  112. package/lib/util/validateFormalSyntax.js +26 -0
  113. package/lib/util/withAlphaVariable.js +27 -15
  114. package/loadConfig.d.ts +4 -0
  115. package/loadConfig.js +2 -0
  116. package/nesting/index.js +2 -12
  117. package/package.json +66 -57
  118. package/peers/index.js +75964 -55560
  119. package/plugin.d.ts +11 -0
  120. package/plugin.js +2 -1
  121. package/resolveConfig.d.ts +12 -0
  122. package/resolveConfig.js +2 -1
  123. package/scripts/generate-types.js +105 -0
  124. package/scripts/release-channel.js +18 -0
  125. package/scripts/release-notes.js +21 -0
  126. package/scripts/swap-engines.js +40 -0
  127. package/scripts/type-utils.js +27 -0
  128. package/src/cli/build/deps.js +56 -0
  129. package/src/cli/build/index.js +49 -0
  130. package/src/cli/build/plugin.js +444 -0
  131. package/src/cli/build/utils.js +76 -0
  132. package/src/cli/build/watching.js +229 -0
  133. package/src/cli/help/index.js +70 -0
  134. package/src/cli/index.js +216 -0
  135. package/src/cli/init/index.js +79 -0
  136. package/src/cli-peer-dependencies.js +7 -1
  137. package/src/cli.js +4 -765
  138. package/src/corePluginList.js +1 -1
  139. package/src/corePlugins.js +786 -306
  140. package/src/css/preflight.css +10 -8
  141. package/src/featureFlags.js +21 -5
  142. package/src/index.js +1 -34
  143. package/src/lib/cacheInvalidation.js +52 -0
  144. package/src/lib/collapseAdjacentRules.js +21 -2
  145. package/src/lib/collapseDuplicateDeclarations.js +66 -1
  146. package/src/lib/content.js +208 -0
  147. package/src/lib/defaultExtractor.js +217 -0
  148. package/src/lib/detectNesting.js +9 -1
  149. package/src/lib/evaluateTailwindFunctions.js +79 -8
  150. package/src/lib/expandApplyAtRules.js +515 -153
  151. package/src/lib/expandTailwindAtRules.js +115 -86
  152. package/src/lib/findAtConfigPath.js +48 -0
  153. package/src/lib/generateRules.js +545 -147
  154. package/src/lib/getModuleDependencies.js +70 -30
  155. package/src/lib/load-config.ts +31 -0
  156. package/src/lib/normalizeTailwindDirectives.js +7 -1
  157. package/src/lib/offsets.js +373 -0
  158. package/src/lib/partitionApplyAtRules.js +52 -0
  159. package/src/lib/regex.js +74 -0
  160. package/src/lib/remap-bitfield.js +82 -0
  161. package/src/lib/resolveDefaultsAtRules.js +59 -17
  162. package/src/lib/setupContextUtils.js +701 -175
  163. package/src/lib/setupTrackingContext.js +51 -62
  164. package/src/lib/sharedState.js +58 -7
  165. package/src/oxide/cli/build/deps.ts +91 -0
  166. package/src/oxide/cli/build/index.ts +47 -0
  167. package/src/oxide/cli/build/plugin.ts +442 -0
  168. package/src/oxide/cli/build/utils.ts +74 -0
  169. package/src/oxide/cli/build/watching.ts +225 -0
  170. package/src/oxide/cli/help/index.ts +69 -0
  171. package/src/oxide/cli/index.ts +204 -0
  172. package/src/oxide/cli/init/index.ts +59 -0
  173. package/src/oxide/cli.ts +1 -0
  174. package/src/oxide/postcss-plugin.ts +1 -0
  175. package/src/plugin.js +107 -0
  176. package/src/postcss-plugins/nesting/README.md +42 -0
  177. package/src/postcss-plugins/nesting/index.js +13 -0
  178. package/src/postcss-plugins/nesting/plugin.js +80 -0
  179. package/src/processTailwindFeatures.js +12 -2
  180. package/src/public/colors.js +22 -0
  181. package/src/public/default-config.js +1 -1
  182. package/src/public/default-theme.js +2 -2
  183. package/src/public/load-config.js +2 -0
  184. package/src/util/applyImportantSelector.js +27 -0
  185. package/src/util/buildMediaQuery.js +5 -3
  186. package/src/util/cloneNodes.js +19 -2
  187. package/src/util/color.js +44 -12
  188. package/src/util/colorNames.js +150 -0
  189. package/src/util/dataTypes.js +51 -16
  190. package/src/util/defaults.js +6 -0
  191. package/src/util/formatVariantSelector.js +264 -144
  192. package/src/util/getAllConfigs.js +21 -2
  193. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  194. package/src/util/log.js +11 -7
  195. package/src/util/nameClass.js +4 -0
  196. package/src/util/negateValue.js +11 -3
  197. package/src/util/normalizeConfig.js +57 -5
  198. package/src/util/normalizeScreens.js +105 -7
  199. package/src/util/parseBoxShadowValue.js +4 -3
  200. package/src/util/parseDependency.js +37 -42
  201. package/src/util/parseGlob.js +24 -0
  202. package/src/util/pluginUtils.js +123 -24
  203. package/src/util/prefixSelector.js +30 -10
  204. package/src/util/pseudoElements.js +170 -0
  205. package/src/util/removeAlphaVariables.js +24 -0
  206. package/src/util/resolveConfig.js +74 -26
  207. package/src/util/resolveConfigPath.js +12 -1
  208. package/src/util/splitAtTopLevelOnly.js +52 -0
  209. package/src/util/toPath.js +23 -1
  210. package/src/util/transformThemeValue.js +13 -3
  211. package/src/util/validateConfig.js +26 -0
  212. package/src/util/validateFormalSyntax.js +34 -0
  213. package/src/util/withAlphaVariable.js +1 -1
  214. package/stubs/.gitignore +1 -0
  215. package/stubs/.prettierrc.json +6 -0
  216. package/stubs/{defaultConfig.stub.js → config.full.js} +206 -166
  217. package/stubs/postcss.config.js +6 -0
  218. package/stubs/tailwind.config.cjs +2 -0
  219. package/stubs/tailwind.config.js +2 -0
  220. package/stubs/tailwind.config.ts +3 -0
  221. package/types/config.d.ts +368 -0
  222. package/types/generated/.gitkeep +0 -0
  223. package/types/generated/colors.d.ts +298 -0
  224. package/types/generated/corePluginList.d.ts +1 -0
  225. package/types/generated/default-theme.d.ts +371 -0
  226. package/types/index.d.ts +7 -0
  227. package/CHANGELOG.md +0 -1843
  228. package/lib/constants.js +0 -37
  229. package/lib/lib/setupWatchingContext.js +0 -288
  230. package/nesting/plugin.js +0 -41
  231. package/scripts/install-integrations.js +0 -27
  232. package/scripts/rebuildFixtures.js +0 -68
  233. package/src/constants.js +0 -17
  234. package/src/lib/setupWatchingContext.js +0 -311
  235. /package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -0
  236. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
package/src/util/log.js CHANGED
@@ -1,25 +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
+ }
14
+
15
+ export function dim(input) {
16
+ return colors.dim(input)
13
17
  }
14
18
 
15
19
  export default {
16
20
  info(key, messages) {
17
- log(chalk.bold.cyan('info'), ...(Array.isArray(key) ? [key] : [messages, key]))
21
+ log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
18
22
  },
19
23
  warn(key, messages) {
20
- log(chalk.bold.yellow('warn'), ...(Array.isArray(key) ? [key] : [messages, key]))
24
+ log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
21
25
  },
22
26
  risk(key, messages) {
23
- log(chalk.bold.magenta('risk'), ...(Array.isArray(key) ? [key] : [messages, key]))
27
+ log(colors.bold(colors.magenta('risk')), ...(Array.isArray(key) ? [key] : [messages, key]))
24
28
  },
25
29
  }
@@ -22,5 +22,9 @@ export function formatClass(classPrefix, key) {
22
22
  return `-${classPrefix}${key}`
23
23
  }
24
24
 
25
+ if (key.startsWith('/')) {
26
+ return `${classPrefix}${key}`
27
+ }
28
+
25
29
  return `${classPrefix}-${key}`
26
30
  }
@@ -1,4 +1,4 @@
1
- export default function (value) {
1
+ export default function negateValue(value) {
2
2
  value = `${value}`
3
3
 
4
4
  if (value === '0') {
@@ -10,7 +10,15 @@ export default function (value) {
10
10
  return value.replace(/^[+-]?/, (sign) => (sign === '-' ? '' : '-'))
11
11
  }
12
12
 
13
- if (value.includes('var(') || value.includes('calc(')) {
14
- return `calc(${value} * -1)`
13
+ // What functions we support negating numeric values for
14
+ // var() isn't inherently a numeric function but we support it anyway
15
+ // The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_
16
+ // to produce generally useful results and that will be covered already
17
+ let numericFunctions = ['var', 'calc', 'min', 'max', 'clamp']
18
+
19
+ for (const fn of numericFunctions) {
20
+ if (value.includes(`${fn}(`)) {
21
+ return `calc(${value} * -1)`
22
+ }
15
23
  }
16
24
  }
@@ -1,4 +1,5 @@
1
- import log from './log'
1
+ import { flagEnabled } from '../featureFlags'
2
+ import log, { dim } from './log'
2
3
 
3
4
  export function normalizeConfig(config) {
4
5
  // Quick structure validation
@@ -56,9 +57,11 @@ export function normalizeConfig(config) {
56
57
 
57
58
  // When `config.content` is an object
58
59
  if (typeof config.content === 'object' && config.content !== null) {
59
- // Only `files`, `extract` and `transform` can exist in `config.content`
60
+ // Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
60
61
  if (
61
- Object.keys(config.content).some((key) => !['files', 'extract', 'transform'].includes(key))
62
+ Object.keys(config.content).some(
63
+ (key) => !['files', 'relative', 'extract', 'transform'].includes(key)
64
+ )
62
65
  ) {
63
66
  return false
64
67
  }
@@ -112,6 +115,14 @@ export function normalizeConfig(config) {
112
115
  ) {
113
116
  return false
114
117
  }
118
+
119
+ // `config.content.relative` is optional and can be a boolean
120
+ if (
121
+ typeof config.content.relative !== 'boolean' &&
122
+ typeof config.content.relative !== 'undefined'
123
+ ) {
124
+ return false
125
+ }
115
126
  }
116
127
 
117
128
  return true
@@ -124,7 +135,7 @@ export function normalizeConfig(config) {
124
135
  log.warn('purge-deprecation', [
125
136
  'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
126
137
  'Update your configuration file to eliminate this warning.',
127
- // TODO: Add https://tw.wtf/purge-deprecation
138
+ 'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
128
139
  ])
129
140
  }
130
141
 
@@ -140,12 +151,30 @@ export function normalizeConfig(config) {
140
151
  return []
141
152
  })()
142
153
 
154
+ // Normalize the `blocklist`
155
+ config.blocklist = (() => {
156
+ let { blocklist } = config
157
+
158
+ if (Array.isArray(blocklist)) {
159
+ if (blocklist.every((item) => typeof item === 'string')) {
160
+ return blocklist
161
+ }
162
+
163
+ log.warn('blocklist-invalid', [
164
+ 'The `blocklist` option must be an array of strings.',
165
+ 'https://tailwindcss.com/docs/content-configuration#discarding-classes',
166
+ ])
167
+ }
168
+
169
+ return []
170
+ })()
171
+
143
172
  // Normalize prefix option
144
173
  if (typeof config.prefix === 'function') {
145
174
  log.warn('prefix-function', [
146
175
  'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
147
176
  'Update `prefix` in your configuration to be a string to eliminate this warning.',
148
- // TODO: Add https://tw.wtf/prefix-function
177
+ 'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
149
178
  ])
150
179
  config.prefix = ''
151
180
  } else {
@@ -154,6 +183,16 @@ export function normalizeConfig(config) {
154
183
 
155
184
  // Normalize the `content`
156
185
  config.content = {
186
+ relative: (() => {
187
+ let { content } = config
188
+
189
+ if (content?.relative) {
190
+ return content.relative
191
+ }
192
+
193
+ return flagEnabled(config, 'relativeContentPathsByDefault')
194
+ })(),
195
+
157
196
  files: (() => {
158
197
  let { content, purge } = config
159
198
 
@@ -245,5 +284,18 @@ export function normalizeConfig(config) {
245
284
  })(),
246
285
  }
247
286
 
287
+ // Validate globs to prevent bogus globs.
288
+ // E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
289
+ for (let file of config.content.files) {
290
+ if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
291
+ log.warn('invalid-glob-braces', [
292
+ `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
293
+ `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
294
+ // TODO: Add https://tw.wtf/invalid-glob-braces
295
+ ])
296
+ break
297
+ }
298
+ }
299
+
248
300
  return config
249
301
  }
@@ -1,3 +1,17 @@
1
+ /**
2
+ * @typedef {object} ScreenValue
3
+ * @property {number|undefined} min
4
+ * @property {number|undefined} max
5
+ * @property {string|undefined} raw
6
+ */
7
+
8
+ /**
9
+ * @typedef {object} Screen
10
+ * @property {string} name
11
+ * @property {boolean} not
12
+ * @property {ScreenValue[]} values
13
+ */
14
+
1
15
  /**
2
16
  * A function that normalizes the various forms that the screens object can be
3
17
  * provided in.
@@ -7,34 +21,118 @@
7
21
  * - { sm: '100px', md: '200px' } // Object with string values
8
22
  * - { sm: { min: '100px' }, md: { max: '100px' } } // Object with object values
9
23
  * - { sm: [{ min: '100px' }, { max: '200px' }] } // Object with object array (multiple values)
10
- * - [['sm', '100px'], ['md', '200px']] // Tuple object
11
24
  *
12
25
  * Output(s):
13
26
  * - [{ name: 'sm', values: [{ min: '100px', max: '200px' }] }] // List of objects, that contains multiple values
27
+ *
28
+ * @returns {Screen[]}
14
29
  */
15
- export function normalizeScreens(screens) {
30
+ export function normalizeScreens(screens, root = true) {
16
31
  if (Array.isArray(screens)) {
17
32
  return screens.map((screen) => {
33
+ if (root && Array.isArray(screen)) {
34
+ throw new Error('The tuple syntax is not supported for `screens`.')
35
+ }
36
+
18
37
  if (typeof screen === 'string') {
19
- return { name: screen.toString(), values: [{ min: screen, max: undefined }] }
38
+ return { name: screen.toString(), not: false, values: [{ min: screen, max: undefined }] }
20
39
  }
21
40
 
22
41
  let [name, options] = screen
23
42
  name = name.toString()
24
43
 
25
44
  if (typeof options === 'string') {
26
- return { name, values: [{ min: options, max: undefined }] }
45
+ return { name, not: false, values: [{ min: options, max: undefined }] }
27
46
  }
28
47
 
29
48
  if (Array.isArray(options)) {
30
- return { name, values: options.map((option) => resolveValue(option)) }
49
+ return { name, not: false, values: options.map((option) => resolveValue(option)) }
31
50
  }
32
51
 
33
- return { name, values: [resolveValue(options)] }
52
+ return { name, not: false, values: [resolveValue(options)] }
34
53
  })
35
54
  }
36
55
 
37
- return normalizeScreens(Object.entries(screens ?? {}))
56
+ return normalizeScreens(Object.entries(screens ?? {}), false)
57
+ }
58
+
59
+ /**
60
+ * @param {Screen} screen
61
+ * @returns {{result: false, reason: string} | {result: true, reason: null}}
62
+ */
63
+ export function isScreenSortable(screen) {
64
+ if (screen.values.length !== 1) {
65
+ return { result: false, reason: 'multiple-values' }
66
+ } else if (screen.values[0].raw !== undefined) {
67
+ return { result: false, reason: 'raw-values' }
68
+ } else if (screen.values[0].min !== undefined && screen.values[0].max !== undefined) {
69
+ return { result: false, reason: 'min-and-max' }
70
+ }
71
+
72
+ return { result: true, reason: null }
73
+ }
74
+
75
+ /**
76
+ * @param {'min' | 'max'} type
77
+ * @param {Screen | 'string'} a
78
+ * @param {Screen | 'string'} z
79
+ * @returns {number}
80
+ */
81
+ export function compareScreens(type, a, z) {
82
+ let aScreen = toScreen(a, type)
83
+ let zScreen = toScreen(z, type)
84
+
85
+ let aSorting = isScreenSortable(aScreen)
86
+ let bSorting = isScreenSortable(zScreen)
87
+
88
+ // These cases should never happen and indicate a bug in Tailwind CSS itself
89
+ if (aSorting.reason === 'multiple-values' || bSorting.reason === 'multiple-values') {
90
+ throw new Error(
91
+ 'Attempted to sort a screen with multiple values. This should never happen. Please open a bug report.'
92
+ )
93
+ } else if (aSorting.reason === 'raw-values' || bSorting.reason === 'raw-values') {
94
+ throw new Error(
95
+ 'Attempted to sort a screen with raw values. This should never happen. Please open a bug report.'
96
+ )
97
+ } else if (aSorting.reason === 'min-and-max' || bSorting.reason === 'min-and-max') {
98
+ throw new Error(
99
+ 'Attempted to sort a screen with both min and max values. This should never happen. Please open a bug report.'
100
+ )
101
+ }
102
+
103
+ // Let the sorting begin
104
+ let { min: aMin, max: aMax } = aScreen.values[0]
105
+ let { min: zMin, max: zMax } = zScreen.values[0]
106
+
107
+ // Negating screens flip their behavior. Basically `not min-width` is `max-width`
108
+ if (a.not) [aMin, aMax] = [aMax, aMin]
109
+ if (z.not) [zMin, zMax] = [zMax, zMin]
110
+
111
+ aMin = aMin === undefined ? aMin : parseFloat(aMin)
112
+ aMax = aMax === undefined ? aMax : parseFloat(aMax)
113
+ zMin = zMin === undefined ? zMin : parseFloat(zMin)
114
+ zMax = zMax === undefined ? zMax : parseFloat(zMax)
115
+
116
+ let [aValue, zValue] = type === 'min' ? [aMin, zMin] : [zMax, aMax]
117
+
118
+ return aValue - zValue
119
+ }
120
+
121
+ /**
122
+ *
123
+ * @param {PartialScreen> | string} value
124
+ * @param {'min' | 'max'} type
125
+ * @returns {Screen}
126
+ */
127
+ export function toScreen(value, type) {
128
+ if (typeof value === 'object') {
129
+ return value
130
+ }
131
+
132
+ return {
133
+ name: 'arbitrary-screen',
134
+ values: [{ [type]: value }],
135
+ }
38
136
  }
39
137
 
40
138
  function resolveValue({ 'min-width': _minWidth, min = _minWidth, max, raw } = {}) {
@@ -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
- let LENGTH = /^-?(\d+)(.*?)$/g
5
+ let LENGTH = /^-?(\d+|\.\d+)(.*?)$/g
5
6
 
6
7
  export function parseBoxShadowValue(input) {
7
- let shadows = input.split(COMMA)
8
+ let shadows = splitAtTopLevelOnly(input, ',')
8
9
  return shadows.map((shadow) => {
9
10
  let value = shadow.trim()
10
11
  let result = { raw: value }
@@ -1,49 +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)
20
- }
21
- if (glob.charAt(0) === '/') {
22
- glob = glob.substr(1)
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 []
23
15
  }
24
16
 
25
- return { base, glob }
26
- }
27
-
28
- export default function parseDependency(normalizedFileOrGlob) {
29
- if (normalizedFileOrGlob.startsWith('!')) {
30
- return null
31
- }
32
-
33
- let message
34
-
35
- if (isGlob(normalizedFileOrGlob)) {
36
- let { base, glob } = parseGlob(normalizedFileOrGlob)
37
- message = { type: 'dir-dependency', dir: path.resolve(base), glob }
38
- } else {
39
- message = { type: 'dependency', file: path.resolve(normalizedFileOrGlob) }
17
+ if (!contentPath.glob) {
18
+ return [
19
+ {
20
+ type: 'dependency',
21
+ file: contentPath.base,
22
+ },
23
+ ]
40
24
  }
41
25
 
42
- // rollup-plugin-postcss does not support dir-dependency messages
43
- // but directories can be watched in the same way as files
44
- if (message.type === 'dir-dependency' && process.env.ROLLUP_WATCH === 'true') {
45
- 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
+ ]
46
35
  }
47
36
 
48
- return message
37
+ return [
38
+ {
39
+ type: 'dir-dependency',
40
+ dir: contentPath.base,
41
+ glob: contentPath.glob,
42
+ },
43
+ ]
49
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,4 +1,3 @@
1
- import selectorParser from 'postcss-selector-parser'
2
1
  import escapeCommas from './escapeCommas'
3
2
  import { withAlphaValue } from './withAlphaVariable'
4
3
  import {
@@ -18,21 +17,22 @@ import {
18
17
  shadow,
19
18
  } from './dataTypes'
20
19
  import negateValue from './negateValue'
21
-
20
+ import { backgroundSize } from './validateFormalSyntax'
21
+ import { flagEnabled } from '../featureFlags.js'
22
+
23
+ /**
24
+ * @param {import('postcss-selector-parser').Container} selectors
25
+ * @param {(className: string) => string} updateClass
26
+ * @returns {string}
27
+ */
22
28
  export function updateAllClasses(selectors, updateClass) {
23
- let parser = selectorParser((selectors) => {
24
- selectors.walkClasses((sel) => {
25
- let updatedClass = updateClass(sel.value)
26
- sel.value = updatedClass
27
- if (sel.raws && sel.raws.value) {
28
- sel.raws.value = escapeCommas(sel.raws.value)
29
- }
30
- })
31
- })
32
-
33
- let result = parser.processSync(selectors)
29
+ selectors.walkClasses((sel) => {
30
+ sel.value = updateClass(sel.value)
34
31
 
35
- return result
32
+ if (sel.raws && sel.raws.value) {
33
+ sel.raws.value = escapeCommas(sel.raws.value)
34
+ }
35
+ })
36
36
  }
37
37
 
38
38
  function resolveArbitraryValue(modifier, validate) {
@@ -85,22 +85,47 @@ function isArbitraryValue(input) {
85
85
  return input.startsWith('[') && input.endsWith(']')
86
86
  }
87
87
 
88
- function splitAlpha(modifier) {
88
+ function splitUtilityModifier(modifier) {
89
89
  let slashIdx = modifier.lastIndexOf('/')
90
90
 
91
91
  if (slashIdx === -1 || slashIdx === modifier.length - 1) {
92
- return [modifier]
92
+ return [modifier, undefined]
93
+ }
94
+
95
+ let arbitrary = isArbitraryValue(modifier)
96
+
97
+ // The modifier could be of the form `[foo]/[bar]`
98
+ // We want to handle this case properly
99
+ // without affecting `[foo/bar]`
100
+ if (arbitrary && !modifier.includes(']/[')) {
101
+ return [modifier, undefined]
93
102
  }
94
103
 
95
104
  return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
96
105
  }
97
106
 
107
+ export function parseColorFormat(value) {
108
+ if (typeof value === 'string' && value.includes('<alpha-value>')) {
109
+ let oldValue = value
110
+
111
+ return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
112
+ }
113
+
114
+ return value
115
+ }
116
+
117
+ function unwrapArbitraryModifier(modifier) {
118
+ return normalize(modifier.slice(1, -1))
119
+ }
120
+
98
121
  export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
99
122
  if (options.values?.[modifier] !== undefined) {
100
- return options.values?.[modifier]
123
+ return parseColorFormat(options.values?.[modifier])
101
124
  }
102
125
 
103
- let [color, alpha] = splitAlpha(modifier)
126
+ // TODO: Hoist this up to getMatchingTypes or something
127
+ // We do this here because we need the alpha value (if any)
128
+ let [color, alpha] = splitUtilityModifier(modifier)
104
129
 
105
130
  if (alpha !== undefined) {
106
131
  let normalizedColor =
@@ -110,8 +135,10 @@ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
110
135
  return undefined
111
136
  }
112
137
 
138
+ normalizedColor = parseColorFormat(normalizedColor)
139
+
113
140
  if (isArbitraryValue(alpha)) {
114
- return withAlphaValue(normalizedColor, alpha.slice(1, -1))
141
+ return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha))
115
142
  }
116
143
 
117
144
  if (tailwindConfig.theme?.opacity?.[alpha] === undefined) {
@@ -134,7 +161,7 @@ function guess(validate) {
134
161
  }
135
162
  }
136
163
 
137
- let typeMap = {
164
+ export let typeMap = {
138
165
  any: asValue,
139
166
  color: asColor,
140
167
  url: guess(url),
@@ -150,6 +177,7 @@ let typeMap = {
150
177
  'absolute-size': guess(absoluteSize),
151
178
  'relative-size': guess(relativeSize),
152
179
  shadow: guess(shadow),
180
+ size: guess(backgroundSize),
153
181
  }
154
182
 
155
183
  let supportedTypes = Object.keys(typeMap)
@@ -161,6 +189,20 @@ function splitAtFirst(input, delim) {
161
189
  }
162
190
 
163
191
  export function coerceValue(types, modifier, options, tailwindConfig) {
192
+ if (options.values && modifier in options.values) {
193
+ for (let { type } of types ?? []) {
194
+ let result = typeMap[type](modifier, options, {
195
+ tailwindConfig,
196
+ })
197
+
198
+ if (result === undefined) {
199
+ continue
200
+ }
201
+
202
+ return [result, type, null]
203
+ }
204
+ }
205
+
164
206
  if (isArbitraryValue(modifier)) {
165
207
  let arbitraryValue = modifier.slice(1, -1)
166
208
  let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
@@ -178,15 +220,72 @@ export function coerceValue(types, modifier, options, tailwindConfig) {
178
220
  }
179
221
 
180
222
  if (value.length > 0 && supportedTypes.includes(explicitType)) {
181
- return [asValue(`[${value}]`, options), explicitType]
223
+ return [asValue(`[${value}]`, options), explicitType, null]
182
224
  }
183
225
  }
184
226
 
227
+ let matches = getMatchingTypes(types, modifier, options, tailwindConfig)
228
+
185
229
  // Find first matching type
186
- for (let type of [].concat(types)) {
187
- let result = typeMap[type](modifier, options, { tailwindConfig })
188
- if (result) return [result, type]
230
+ for (let match of matches) {
231
+ return match
189
232
  }
190
233
 
191
234
  return []
192
235
  }
236
+
237
+ /**
238
+ *
239
+ * @param {{type: string}[]} types
240
+ * @param {string} rawModifier
241
+ * @param {any} options
242
+ * @param {any} tailwindConfig
243
+ * @returns {Iterator<[value: string, type: string, modifier: string | null]>}
244
+ */
245
+ export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
246
+ let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
247
+
248
+ let [modifier, utilityModifier] = splitUtilityModifier(rawModifier)
249
+
250
+ let canUseUtilityModifier =
251
+ modifiersEnabled &&
252
+ options.modifiers != null &&
253
+ (options.modifiers === 'any' ||
254
+ (typeof options.modifiers === 'object' &&
255
+ ((utilityModifier && isArbitraryValue(utilityModifier)) ||
256
+ utilityModifier in options.modifiers)))
257
+
258
+ if (!canUseUtilityModifier) {
259
+ modifier = rawModifier
260
+ utilityModifier = undefined
261
+ }
262
+
263
+ if (utilityModifier !== undefined && modifier === '') {
264
+ modifier = 'DEFAULT'
265
+ }
266
+
267
+ // Check the full value first
268
+ // TODO: Move to asValue… somehow
269
+ if (utilityModifier !== undefined) {
270
+ if (typeof options.modifiers === 'object') {
271
+ let configValue = options.modifiers?.[utilityModifier] ?? null
272
+ if (configValue !== null) {
273
+ utilityModifier = configValue
274
+ } else if (isArbitraryValue(utilityModifier)) {
275
+ utilityModifier = unwrapArbitraryModifier(utilityModifier)
276
+ }
277
+ }
278
+ }
279
+
280
+ for (let { type } of types ?? []) {
281
+ let result = typeMap[type](modifier, options, {
282
+ tailwindConfig,
283
+ })
284
+
285
+ if (result === undefined) {
286
+ continue
287
+ }
288
+
289
+ yield [result, type, utilityModifier ?? null]
290
+ }
291
+ }