tailwindcss 3.1.2 → 3.1.3

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.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - Nothing yet!
11
11
 
12
+ ## [3.1.3] - 2022-06-14
13
+
14
+ ### Fixed
15
+
16
+ - Fix extraction of multi-word utilities with arbitrary values and quotes ([#8604](https://github.com/tailwindlabs/tailwindcss/pull/8604))
17
+ - Fix casing of import of `corePluginList` type definition ([#8587](https://github.com/tailwindlabs/tailwindcss/pull/8587))
18
+ - Ignore PostCSS nodes returned by `addVariant` ([#8608](https://github.com/tailwindlabs/tailwindcss/pull/8608))
19
+ - Fix missing spaces around arithmetic operators ([#8615](https://github.com/tailwindlabs/tailwindcss/pull/8615))
20
+ - Detect alpha value in CSS `theme()` function when using quotes ([#8625](https://github.com/tailwindlabs/tailwindcss/pull/8625))
21
+ - Fix "Maximum call stack size exceeded" bug ([#8636](https://github.com/tailwindlabs/tailwindcss/pull/8636))
22
+ - Allow functions returning parallel variants to mutate the container ([#8622](https://github.com/tailwindlabs/tailwindcss/pull/8622))
23
+ - Remove text opacity CSS variables from `::marker` ([#8622](https://github.com/tailwindlabs/tailwindcss/pull/8622))
24
+
12
25
  ## [3.1.2] - 2022-06-10
13
26
 
14
27
  ### Fixed
@@ -1968,7 +1981,8 @@ No release notes
1968
1981
 
1969
1982
  - Everything!
1970
1983
 
1971
- [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.2...HEAD
1984
+ [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.3...HEAD
1985
+ [3.1.3]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.2...v3.1.3
1972
1986
  [3.1.2]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.1...v3.1.2
1973
1987
  [3.1.1]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.0...v3.1.1
1974
1988
  [3.1.0]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.24...v3.1.0
@@ -19,6 +19,7 @@ var _packageJson = require("../package.json");
19
19
  var _log = _interopRequireDefault(require("./util/log"));
20
20
  var _normalizeScreens = require("./util/normalizeScreens");
21
21
  var _parseBoxShadowValue = require("./util/parseBoxShadowValue");
22
+ var _removeAlphaVariables = require("./util/removeAlphaVariables");
22
23
  var _featureFlags = require("./featureFlags");
23
24
  function _interopRequireDefault(obj) {
24
25
  return obj && obj.__esModule ? obj : {
@@ -69,8 +70,18 @@ let variantPlugins = {
69
70
  addVariant("first-letter", "&::first-letter");
70
71
  addVariant("first-line", "&::first-line");
71
72
  addVariant("marker", [
72
- "& *::marker",
73
- "&::marker"
73
+ ({ container })=>{
74
+ (0, _removeAlphaVariables).removeAlphaVariables(container, [
75
+ "--tw-text-opacity"
76
+ ]);
77
+ return "& *::marker";
78
+ },
79
+ ({ container })=>{
80
+ (0, _removeAlphaVariables).removeAlphaVariables(container, [
81
+ "--tw-text-opacity"
82
+ ]);
83
+ return "&::marker";
84
+ },
74
85
  ]);
75
86
  addVariant("selection", [
76
87
  "& *::selection",
@@ -140,22 +151,11 @@ let variantPlugins = {
140
151
  [
141
152
  "visited",
142
153
  ({ container })=>{
143
- let toRemove = [
154
+ (0, _removeAlphaVariables).removeAlphaVariables(container, [
144
155
  "--tw-text-opacity",
145
156
  "--tw-border-opacity",
146
- "--tw-bg-opacity"
147
- ];
148
- container.walkDecls((decl)=>{
149
- if (toRemove.includes(decl.prop)) {
150
- decl.remove();
151
- return;
152
- }
153
- for (const varName of toRemove){
154
- if (decl.value.includes(`/ var(${varName})`)) {
155
- decl.value = decl.value.replace(`/ var(${varName})`, "");
156
- }
157
- }
158
- });
157
+ "--tw-bg-opacity",
158
+ ]);
159
159
  return "&:visited";
160
160
  },
161
161
  ],
@@ -52,7 +52,10 @@ function defaultExtractor(context) {
52
52
  /** @type {(string|string)[]} */ let results = [];
53
53
  for (let pattern of patterns){
54
54
  var ref;
55
- results.push(...(ref = content.match(pattern)) !== null && ref !== void 0 ? ref : []);
55
+ results = [
56
+ ...results,
57
+ ...(ref = content.match(pattern)) !== null && ref !== void 0 ? ref : []
58
+ ];
56
59
  }
57
60
  return results.filter((v)=>v !== undefined).map(clipAtBalancedParens);
58
61
  };
@@ -71,7 +74,7 @@ function* buildRegExps(context) {
71
74
  regex.optional(regex.any([
72
75
  regex.pattern([
73
76
  // Arbitrary values
74
- /-\[[^\s:]+\]/,
77
+ /-(?:\w+-)*\[[^\s:]+\]/,
75
78
  // Not immediately followed by an `{[(`
76
79
  /(?![{([]])/,
77
80
  // optionally followed by an opacity modifier
@@ -79,7 +82,7 @@ function* buildRegExps(context) {
79
82
  ]),
80
83
  regex.pattern([
81
84
  // Arbitrary values
82
- /-\[[^\s]+\]/,
85
+ /-(?:\w+-)*\[[^\s]+\]/,
83
86
  // Not immediately followed by an `{[(`
84
87
  /(?![{([]])/,
85
88
  // optionally followed by an opacity modifier
@@ -42,7 +42,7 @@ function listKeys(obj) {
42
42
  return list(Object.keys(obj));
43
43
  }
44
44
  function validatePath(config, path, defaultValue, themeOpts = {}) {
45
- const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+/g, "").replace(/['"]+$/g, "");
45
+ const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+|['"]+$/g, "");
46
46
  const pathSegments = Array.isArray(path) ? path : (0, _toPath).toPath(pathString);
47
47
  const value = (0, _dlv).default(config.theme, pathSegments, defaultValue);
48
48
  if (value === undefined) {
@@ -140,6 +140,9 @@ let nodeTypePropertyMap = {
140
140
  function _default({ tailwindConfig: config }) {
141
141
  let functions = {
142
142
  theme: (node, path, ...defaultValue)=>{
143
+ // Strip quotes from beginning and end of string
144
+ // This allows the alpha value to be present inside of quotes
145
+ path = path.replace(/^['"]+|['"]+$/g, "");
143
146
  let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]+))$/);
144
147
  let alpha = undefined;
145
148
  if (matches) {
@@ -205,13 +205,16 @@ function applyVariant(variant, matches, context) {
205
205
  rule1.clone()
206
206
  ]
207
207
  });
208
- for (let [variantSort, variantFunction] of variantFunctionTuples){
209
- let clone = container.clone();
208
+ for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples){
209
+ let clone = containerFromArray !== null && containerFromArray !== void 0 ? containerFromArray : container.clone();
210
210
  let collectedFormats = [];
211
- let originals = new Map();
212
211
  function prepareBackup() {
213
- if (originals.size > 0) return; // Already prepared, chicken out
214
- clone.walkRules((rule)=>originals.set(rule, rule.selector));
212
+ // Already prepared, chicken out
213
+ if (clone.raws.neededBackup) {
214
+ return;
215
+ }
216
+ clone.raws.neededBackup = true;
217
+ clone.walkRules((rule)=>rule.raws.originalSelector = rule.selector);
215
218
  }
216
219
  function modifySelectors(modifierFunction) {
217
220
  prepareBackup();
@@ -264,7 +267,10 @@ function applyVariant(variant, matches, context) {
264
267
  // then this might be the place too look at. One potential solution to this problem is
265
268
  // reserving additional X places for these 'unknown' variants in between.
266
269
  variantSort | BigInt(idx << ruleWithVariant.length),
267
- variantFunction,
270
+ variantFunction,
271
+ // If the clone has been modified we have to pass that back
272
+ // though so each rule can use the modified container
273
+ clone.clone(),
268
274
  ]);
269
275
  }
270
276
  continue;
@@ -275,13 +281,15 @@ function applyVariant(variant, matches, context) {
275
281
  if (ruleWithVariant === null) {
276
282
  continue;
277
283
  }
278
- // We filled the `originals`, therefore we assume that somebody touched
284
+ // We had to backup selectors, therefore we assume that somebody touched
279
285
  // `container` or `modifySelectors`. Let's see if they did, so that we
280
286
  // can restore the selectors, and collect the format strings.
281
- if (originals.size > 0) {
287
+ if (clone.raws.neededBackup) {
288
+ delete clone.raws.neededBackup;
282
289
  clone.walkRules((rule)=>{
283
- if (!originals.has(rule)) return;
284
- let before = originals.get(rule);
290
+ let before = rule.raws.originalSelector;
291
+ if (!before) return;
292
+ delete rule.raws.originalSelector;
285
293
  if (before === rule.selector) return; // No mutation happened
286
294
  let modified = rule.selector;
287
295
  // Rebuild the base selector, this is what plugin authors would do
@@ -478,10 +478,11 @@ function buildPluginApi(tailwindConfig, context, { variantList , variantMap , of
478
478
  throw new Error(`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`);
479
479
  }
480
480
  if (Array.isArray(result)) {
481
- return result.map((variant)=>parseVariant(variant));
481
+ return result.filter((variant)=>typeof variant === "string").map((variant)=>parseVariant(variant));
482
482
  }
483
483
  // result may be undefined with legacy variants that use APIs like `modifySelectors`
484
- return result && parseVariant(result)(api);
484
+ // result may also be a postcss node if someone was returning the result from `modifySelectors`
485
+ return result && typeof result === "string" && parseVariant(result)(api);
485
486
  };
486
487
  }
487
488
  if (!isValidVariantFormatString(variantFunction)) {
@@ -46,9 +46,9 @@ function normalize(value, isRoot = true) {
46
46
  if (isRoot) {
47
47
  value = value.trim();
48
48
  }
49
- // Add spaces around operators inside calc() that do not follow an operator
49
+ // Add spaces around operators inside math functions like calc() that do not follow an operator
50
50
  // or '('.
51
- value = value.replace(/calc\(.+\)/g, (match)=>{
51
+ value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{
52
52
  return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ");
53
53
  });
54
54
  // Add spaces around some operators not inside calc() that do not follow an operator
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ exports.removeAlphaVariables = removeAlphaVariables;
6
+ function removeAlphaVariables(container, toRemove) {
7
+ container.walkDecls((decl)=>{
8
+ if (toRemove.includes(decl.prop)) {
9
+ decl.remove();
10
+ return;
11
+ }
12
+ for (let varName of toRemove){
13
+ if (decl.value.includes(`/ var(${varName})`)) {
14
+ decl.value = decl.value.replace(`/ var(${varName})`, "");
15
+ }
16
+ }
17
+ });
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwindcss",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "A utility-first CSS framework for rapidly building custom user interfaces.",
5
5
  "license": "MIT",
6
6
  "main": "lib/index.js",
@@ -52,8 +52,8 @@
52
52
  "eslint": "^8.16.0",
53
53
  "eslint-config-prettier": "^8.5.0",
54
54
  "eslint-plugin-prettier": "^4.0.0",
55
- "jest": "^28.1.0",
56
- "jest-diff": "^28.1.0",
55
+ "jest": "^28.1.1",
56
+ "jest-diff": "^28.1.1",
57
57
  "prettier": "^2.6.2",
58
58
  "prettier-plugin-tailwindcss": "^0.1.11",
59
59
  "rimraf": "^3.0.0",
@@ -63,7 +63,7 @@
63
63
  "postcss": "^8.0.9"
64
64
  },
65
65
  "dependencies": {
66
- "arg": "^5.0.1",
66
+ "arg": "^5.0.2",
67
67
  "chokidar": "^3.5.3",
68
68
  "color-name": "^1.1.4",
69
69
  "detective": "^5.2.1",
@@ -14,6 +14,7 @@ import { version as tailwindVersion } from '../package.json'
14
14
  import log from './util/log'
15
15
  import { normalizeScreens } from './util/normalizeScreens'
16
16
  import { formatBoxShadowValue, parseBoxShadowValue } from './util/parseBoxShadowValue'
17
+ import { removeAlphaVariables } from './util/removeAlphaVariables'
17
18
  import { flagEnabled } from './featureFlags'
18
19
 
19
20
  export let variantPlugins = {
@@ -21,7 +22,19 @@ export let variantPlugins = {
21
22
  addVariant('first-letter', '&::first-letter')
22
23
  addVariant('first-line', '&::first-line')
23
24
 
24
- addVariant('marker', ['& *::marker', '&::marker'])
25
+ addVariant('marker', [
26
+ ({ container }) => {
27
+ removeAlphaVariables(container, ['--tw-text-opacity'])
28
+
29
+ return '& *::marker'
30
+ },
31
+ ({ container }) => {
32
+ removeAlphaVariables(container, ['--tw-text-opacity'])
33
+
34
+ return '&::marker'
35
+ },
36
+ ])
37
+
25
38
  addVariant('selection', ['& *::selection', '&::selection'])
26
39
 
27
40
  addVariant('file', '&::file-selector-button')
@@ -77,21 +90,11 @@ export let variantPlugins = {
77
90
  [
78
91
  'visited',
79
92
  ({ container }) => {
80
- let toRemove = ['--tw-text-opacity', '--tw-border-opacity', '--tw-bg-opacity']
81
-
82
- container.walkDecls((decl) => {
83
- if (toRemove.includes(decl.prop)) {
84
- decl.remove()
85
-
86
- return
87
- }
88
-
89
- for (const varName of toRemove) {
90
- if (decl.value.includes(`/ var(${varName})`)) {
91
- decl.value = decl.value.replace(`/ var(${varName})`, '')
92
- }
93
- }
94
- })
93
+ removeAlphaVariables(container, [
94
+ '--tw-text-opacity',
95
+ '--tw-border-opacity',
96
+ '--tw-bg-opacity',
97
+ ])
95
98
 
96
99
  return '&:visited'
97
100
  },
@@ -12,7 +12,7 @@ export function defaultExtractor(context) {
12
12
  let results = []
13
13
 
14
14
  for (let pattern of patterns) {
15
- results.push(...(content.match(pattern) ?? []))
15
+ results = [...results, ...(content.match(pattern) ?? [])]
16
16
  }
17
17
 
18
18
  return results.filter((v) => v !== undefined).map(clipAtBalancedParens)
@@ -37,7 +37,7 @@ function* buildRegExps(context) {
37
37
  regex.any([
38
38
  regex.pattern([
39
39
  // Arbitrary values
40
- /-\[[^\s:]+\]/,
40
+ /-(?:\w+-)*\[[^\s:]+\]/,
41
41
 
42
42
  // Not immediately followed by an `{[(`
43
43
  /(?![{([]])/,
@@ -48,7 +48,7 @@ function* buildRegExps(context) {
48
48
 
49
49
  regex.pattern([
50
50
  // Arbitrary values
51
- /-\[[^\s]+\]/,
51
+ /-(?:\w+-)*\[[^\s]+\]/,
52
52
 
53
53
  // Not immediately followed by an `{[(`
54
54
  /(?![{([]])/,
@@ -40,9 +40,7 @@ function listKeys(obj) {
40
40
  }
41
41
 
42
42
  function validatePath(config, path, defaultValue, themeOpts = {}) {
43
- const pathString = Array.isArray(path)
44
- ? pathToString(path)
45
- : path.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
43
+ const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+|['"]+$/g, '')
46
44
  const pathSegments = Array.isArray(path) ? path : toPath(pathString)
47
45
  const value = dlv(config.theme, pathSegments, defaultValue)
48
46
 
@@ -162,6 +160,10 @@ let nodeTypePropertyMap = {
162
160
  export default function ({ tailwindConfig: config }) {
163
161
  let functions = {
164
162
  theme: (node, path, ...defaultValue) => {
163
+ // Strip quotes from beginning and end of string
164
+ // This allows the alpha value to be present inside of quotes
165
+ path = path.replace(/^['"]+|['"]+$/g, '')
166
+
165
167
  let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]+))$/)
166
168
  let alpha = undefined
167
169
 
@@ -163,15 +163,17 @@ function applyVariant(variant, matches, context) {
163
163
 
164
164
  let container = postcss.root({ nodes: [rule.clone()] })
165
165
 
166
- for (let [variantSort, variantFunction] of variantFunctionTuples) {
167
- let clone = container.clone()
166
+ for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples) {
167
+ let clone = containerFromArray ?? container.clone()
168
168
  let collectedFormats = []
169
169
 
170
- let originals = new Map()
171
-
172
170
  function prepareBackup() {
173
- if (originals.size > 0) return // Already prepared, chicken out
174
- clone.walkRules((rule) => originals.set(rule, rule.selector))
171
+ // Already prepared, chicken out
172
+ if (clone.raws.neededBackup) {
173
+ return
174
+ }
175
+ clone.raws.neededBackup = true
176
+ clone.walkRules((rule) => (rule.raws.originalSelector = rule.selector))
175
177
  }
176
178
 
177
179
  function modifySelectors(modifierFunction) {
@@ -231,6 +233,10 @@ function applyVariant(variant, matches, context) {
231
233
  // reserving additional X places for these 'unknown' variants in between.
232
234
  variantSort | BigInt(idx << ruleWithVariant.length),
233
235
  variantFunction,
236
+
237
+ // If the clone has been modified we have to pass that back
238
+ // though so each rule can use the modified container
239
+ clone.clone(),
234
240
  ])
235
241
  }
236
242
  continue
@@ -244,13 +250,15 @@ function applyVariant(variant, matches, context) {
244
250
  continue
245
251
  }
246
252
 
247
- // We filled the `originals`, therefore we assume that somebody touched
253
+ // We had to backup selectors, therefore we assume that somebody touched
248
254
  // `container` or `modifySelectors`. Let's see if they did, so that we
249
255
  // can restore the selectors, and collect the format strings.
250
- if (originals.size > 0) {
256
+ if (clone.raws.neededBackup) {
257
+ delete clone.raws.neededBackup
251
258
  clone.walkRules((rule) => {
252
- if (!originals.has(rule)) return
253
- let before = originals.get(rule)
259
+ let before = rule.raws.originalSelector
260
+ if (!before) return
261
+ delete rule.raws.originalSelector
254
262
  if (before === rule.selector) return // No mutation happened
255
263
 
256
264
  let modified = rule.selector
@@ -465,11 +465,14 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
465
465
  }
466
466
 
467
467
  if (Array.isArray(result)) {
468
- return result.map((variant) => parseVariant(variant))
468
+ return result
469
+ .filter((variant) => typeof variant === 'string')
470
+ .map((variant) => parseVariant(variant))
469
471
  }
470
472
 
471
473
  // result may be undefined with legacy variants that use APIs like `modifySelectors`
472
- return result && parseVariant(result)(api)
474
+ // result may also be a postcss node if someone was returning the result from `modifySelectors`
475
+ return result && typeof result === 'string' && parseVariant(result)(api)
473
476
  }
474
477
  }
475
478
 
@@ -40,9 +40,9 @@ export function normalize(value, isRoot = true) {
40
40
  value = value.trim()
41
41
  }
42
42
 
43
- // Add spaces around operators inside calc() that do not follow an operator
43
+ // Add spaces around operators inside math functions like calc() that do not follow an operator
44
44
  // or '('.
45
- value = value.replace(/calc\(.+\)/g, (match) => {
45
+ value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => {
46
46
  return match.replace(
47
47
  /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
48
48
  '$1 $2 '
@@ -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
+ }
package/types/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CorePluginList } from './generated/CorePluginList'
1
+ import type { CorePluginList } from './generated/corePluginList'
2
2
  import type { DefaultColors } from './generated/colors'
3
3
 
4
4
  // Helpers