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
@@ -1,40 +1,184 @@
1
- const PATTERNS = [
2
- /(?:\['([^'\s]+[^<>"'`\s:\\])')/.source, // ['text-lg' -> text-lg
3
- /(?:\["([^"\s]+[^<>"'`\s:\\])")/.source, // ["text-lg" -> text-lg
4
- /(?:\[`([^`\s]+[^<>"'`\s:\\])`)/.source, // [`text-lg` -> text-lg
5
- /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
6
- /([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif]
7
- /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
8
- /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
9
- /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')]
10
- /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
11
- /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
12
- /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
13
- /([^<>"'`\s]*\[[^<>"'`\s]*:[^\]\s]*\])/.source, // `[attr:value]`
14
- /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]`
15
- /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']`
16
- /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
17
- /([^"'`\s]*[^<>"'`\s:\\])/.source, // `<sm:underline`, `md>:font-bold`
18
- /([^<>"'`\s]*[^"'`\s:\\])/.source, // `px-1.5`, `uppercase` but not `uppercase:`
19
-
20
- // Arbitrary properties
21
- // /([^"\s]*\[[^\s]+?\][^"\s]*)/.source,
22
- // /([^'\s]*\[[^\s]+?\][^'\s]*)/.source,
23
- // /([^`\s]*\[[^\s]+?\][^`\s]*)/.source,
24
- ].join('|')
25
-
26
- const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g')
27
- const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g
1
+ import { flagEnabled } from '../featureFlags.js'
2
+ import * as regex from './regex'
3
+
4
+ export function defaultExtractor(context) {
5
+ let patterns = Array.from(buildRegExps(context))
6
+
7
+ /**
8
+ * @param {string} content
9
+ */
10
+ return (content) => {
11
+ /** @type {(string|string)[]} */
12
+ let results = []
13
+
14
+ for (let pattern of patterns) {
15
+ results.push(...(content.match(pattern) ?? []))
16
+ }
17
+
18
+ return results.filter((v) => v !== undefined).map(clipAtBalancedParens)
19
+ }
20
+ }
21
+
22
+ function* buildRegExps(context) {
23
+ let separator = context.tailwindConfig.separator
24
+ let variantGroupingEnabled = flagEnabled(context.tailwindConfig, 'variantGrouping')
25
+
26
+ let utility = regex.any([
27
+ // Arbitrary properties
28
+ /\[[^\s:'"]+:[^\s\]]+\]/,
29
+
30
+ // Utilities
31
+ regex.pattern([
32
+ // Utility Name / Group Name
33
+ /-?(?:\w+)/,
34
+
35
+ // Normal/Arbitrary values
36
+ regex.optional(
37
+ regex.any([
38
+ regex.pattern([
39
+ // Arbitrary values
40
+ /-\[[^\s:]+\]/,
41
+
42
+ // Not immediately followed by an `{[(`
43
+ /(?![{([]])/,
44
+
45
+ // optionally followed by an opacity modifier
46
+ /(?:\/[^\s'"\\$]*)?/,
47
+ ]),
48
+
49
+ regex.pattern([
50
+ // Arbitrary values
51
+ /-\[[^\s]+\]/,
52
+
53
+ // Not immediately followed by an `{[(`
54
+ /(?![{([]])/,
55
+
56
+ // optionally followed by an opacity modifier
57
+ /(?:\/[^\s'"\\$]*)?/,
58
+ ]),
59
+
60
+ // Normal values w/o quotes — may include an opacity modifier
61
+ /[-\/][^\s'"\\$={]*/,
62
+ ])
63
+ ),
64
+ ]),
65
+ ])
66
+
67
+ yield regex.pattern([
68
+ // Variants
69
+ '((?=((',
70
+ regex.any(
71
+ [
72
+ regex.pattern([/([^\s"'\[\\]+-)?\[[^\s"'\\]+\]/, separator]),
73
+ regex.pattern([/[^\s"'\[\\]+/, separator]),
74
+ ],
75
+ true
76
+ ),
77
+ ')+))\\2)?',
78
+
79
+ // Important (optional)
80
+ /!?/,
81
+
82
+ variantGroupingEnabled
83
+ ? regex.any([
84
+ // Or any of those things but grouped separated by commas
85
+ regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]),
86
+
87
+ // Arbitrary properties, constrained utilities, arbitrary values, etc…
88
+ utility,
89
+ ])
90
+ : utility,
91
+ ])
92
+
93
+ // 5. Inner matches
94
+ // yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g
95
+ }
96
+
97
+ // We want to capture any "special" characters
98
+ // AND the characters immediately following them (if there is one)
99
+ let SPECIALS = /([\[\]'"`])([^\[\]'"`])?/g
100
+ let ALLOWED_CLASS_CHARACTERS = /[^"'`\s<>\]]+/
28
101
 
29
102
  /**
30
- * @param {string} content
103
+ * Clips a string ensuring that parentheses, quotes, etc… are balanced
104
+ * Used for arbitrary values only
105
+ *
106
+ * We will go past the end of the balanced parens until we find a non-class character
107
+ *
108
+ * Depth matching behavior:
109
+ * w-[calc(100%-theme('spacing[some_key][1.5]'))]']
110
+ * ┬ ┬ ┬┬ ┬ ┬┬ ┬┬┬┬┬┬┬
111
+ * 1 2 3 4 34 3 210 END
112
+ * ╰────┴──────────┴────────┴────────┴┴───┴─┴┴┴
113
+ *
114
+ * @param {string} input
31
115
  */
32
- export function defaultExtractor(content) {
33
- let broadMatches = content.matchAll(BROAD_MATCH_GLOBAL_REGEXP)
34
- let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []
35
- let results = [...broadMatches, ...innerMatches].flat().filter((v) => v !== undefined)
116
+ function clipAtBalancedParens(input) {
117
+ // We are care about this for arbitrary values
118
+ if (!input.includes('-[')) {
119
+ return input
120
+ }
121
+
122
+ let depth = 0
123
+ let openStringTypes = []
124
+
125
+ // Find all parens, brackets, quotes, etc
126
+ // Stop when we end at a balanced pair
127
+ // This is naive and will treat mismatched parens as balanced
128
+ // This shouldn't be a problem in practice though
129
+ let matches = input.matchAll(SPECIALS)
130
+
131
+ // We can't use lookbehind assertions because we have to support Safari
132
+ // So, instead, we've emulated it using capture groups and we'll re-work the matches to accommodate
133
+ matches = Array.from(matches).flatMap((match) => {
134
+ const [, ...groups] = match
135
+
136
+ return groups.map((group, idx) =>
137
+ Object.assign([], match, {
138
+ index: match.index + idx,
139
+ 0: group,
140
+ })
141
+ )
142
+ })
143
+
144
+ for (let match of matches) {
145
+ let char = match[0]
146
+ let inStringType = openStringTypes[openStringTypes.length - 1]
147
+
148
+ if (char === inStringType) {
149
+ openStringTypes.pop()
150
+ } else if (char === "'" || char === '"' || char === '`') {
151
+ openStringTypes.push(char)
152
+ }
153
+
154
+ if (inStringType) {
155
+ continue
156
+ } else if (char === '[') {
157
+ depth++
158
+ continue
159
+ } else if (char === ']') {
160
+ depth--
161
+ continue
162
+ }
163
+
164
+ // We've gone one character past the point where we should stop
165
+ // This means that there was an extra closing `]`
166
+ // We'll clip to just before it
167
+ if (depth < 0) {
168
+ return input.substring(0, match.index)
169
+ }
170
+
171
+ // We've finished balancing the brackets but there still may be characters that can be included
172
+ // For example in the class `text-[#336699]/[.35]`
173
+ // The depth goes to `0` at the closing `]` but goes up again at the `[`
174
+
175
+ // If we're at zero and encounter a non-class character then we clip the class there
176
+ if (depth === 0 && !ALLOWED_CLASS_CHARACTERS.test(char)) {
177
+ return input.substring(0, match.index)
178
+ }
179
+ }
36
180
 
37
- return results
181
+ return input
38
182
  }
39
183
 
40
184
  // Regular utilities
@@ -5,6 +5,8 @@ import parseValue from 'postcss-value-parser'
5
5
  import { normalizeScreens } from '../util/normalizeScreens'
6
6
  import buildMediaQuery from '../util/buildMediaQuery'
7
7
  import { toPath } from '../util/toPath'
8
+ import { withAlphaValue } from '../util/withAlphaVariable'
9
+ import { parseColorFormat } from '../util/pluginUtils'
8
10
 
9
11
  function isObject(input) {
10
12
  return typeof input === 'object' && input !== null
@@ -37,7 +39,7 @@ function listKeys(obj) {
37
39
  return list(Object.keys(obj))
38
40
  }
39
41
 
40
- function validatePath(config, path, defaultValue) {
42
+ function validatePath(config, path, defaultValue, themeOpts = {}) {
41
43
  const pathString = Array.isArray(path)
42
44
  ? pathToString(path)
43
45
  : path.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
@@ -114,7 +116,7 @@ function validatePath(config, path, defaultValue) {
114
116
 
115
117
  return {
116
118
  isValid: true,
117
- value: transformThemeValue(themeSection)(value),
119
+ value: transformThemeValue(themeSection)(value, themeOpts),
118
120
  }
119
121
  }
120
122
 
@@ -160,16 +162,30 @@ let nodeTypePropertyMap = {
160
162
  export default function ({ tailwindConfig: config }) {
161
163
  let functions = {
162
164
  theme: (node, path, ...defaultValue) => {
163
- const { isValid, value, error } = validatePath(
165
+ let matches = path.match(/^([^\/\s]+)(?:\s*\/\s*([^\/\s]+))$/)
166
+ let alpha = undefined
167
+
168
+ if (matches) {
169
+ path = matches[1]
170
+ alpha = matches[2]
171
+ }
172
+
173
+ let { isValid, value, error } = validatePath(
164
174
  config,
165
175
  path,
166
- defaultValue.length ? defaultValue : undefined
176
+ defaultValue.length ? defaultValue : undefined,
177
+ { opacityValue: alpha }
167
178
  )
168
179
 
169
180
  if (!isValid) {
170
181
  throw node.error(error)
171
182
  }
172
183
 
184
+ if (alpha !== undefined) {
185
+ value = parseColorFormat(value)
186
+ value = withAlphaValue(value, alpha, value)
187
+ }
188
+
173
189
  return value
174
190
  },
175
191
  screen: (node, screen) => {