tailwindcss 3.4.1 → 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/README.md +2 -3
  3. package/lib/cli/build/plugin.js +4 -11
  4. package/lib/cli.js +1 -5
  5. package/lib/corePluginList.js +1 -0
  6. package/lib/corePlugins.js +50 -21
  7. package/lib/css/preflight.css +4 -3
  8. package/lib/featureFlags.js +2 -6
  9. package/lib/lib/content.js +36 -3
  10. package/lib/lib/defaultExtractor.js +2 -2
  11. package/lib/lib/expandApplyAtRules.js +13 -0
  12. package/lib/lib/expandTailwindAtRules.js +20 -32
  13. package/lib/lib/generateRules.js +5 -2
  14. package/lib/lib/load-config.js +4 -0
  15. package/lib/lib/offsets.js +51 -2
  16. package/lib/lib/resolveDefaultsAtRules.js +3 -1
  17. package/lib/lib/setupContextUtils.js +5 -1
  18. package/lib/lib/sharedState.js +2 -10
  19. package/lib/plugin.js +0 -50
  20. package/lib/processTailwindFeatures.js +0 -2
  21. package/lib/util/dataTypes.js +1 -1
  22. package/package.json +5 -8
  23. package/peers/index.js +61 -61
  24. package/src/cli/build/plugin.js +4 -11
  25. package/src/cli.js +1 -5
  26. package/src/corePluginList.js +1 -1
  27. package/src/corePlugins.js +45 -23
  28. package/src/css/preflight.css +4 -3
  29. package/src/featureFlags.js +2 -6
  30. package/src/lib/content.js +42 -1
  31. package/src/lib/defaultExtractor.js +2 -2
  32. package/src/lib/expandApplyAtRules.js +17 -0
  33. package/src/lib/expandTailwindAtRules.js +23 -41
  34. package/src/lib/generateRules.js +2 -2
  35. package/src/lib/load-config.ts +5 -0
  36. package/src/lib/offsets.js +61 -2
  37. package/src/lib/resolveDefaultsAtRules.js +5 -1
  38. package/src/lib/setupContextUtils.js +6 -1
  39. package/src/lib/sharedState.js +0 -4
  40. package/src/plugin.js +0 -60
  41. package/src/processTailwindFeatures.js +0 -3
  42. package/src/util/dataTypes.js +1 -1
  43. package/types/generated/corePluginList.d.ts +1 -1
  44. package/lib/lib/detectNesting.js +0 -45
  45. package/lib/oxide/cli/build/deps.js +0 -89
  46. package/lib/oxide/cli/build/index.js +0 -53
  47. package/lib/oxide/cli/build/plugin.js +0 -375
  48. package/lib/oxide/cli/build/utils.js +0 -87
  49. package/lib/oxide/cli/build/watching.js +0 -179
  50. package/lib/oxide/cli/help/index.js +0 -72
  51. package/lib/oxide/cli/index.js +0 -214
  52. package/lib/oxide/cli/init/index.js +0 -52
  53. package/lib/oxide/cli.js +0 -5
  54. package/lib/oxide/postcss-plugin.js +0 -2
  55. package/scripts/swap-engines.js +0 -40
  56. package/src/lib/detectNesting.js +0 -47
  57. package/src/oxide/cli/build/deps.ts +0 -91
  58. package/src/oxide/cli/build/index.ts +0 -47
  59. package/src/oxide/cli/build/plugin.ts +0 -442
  60. package/src/oxide/cli/build/utils.ts +0 -74
  61. package/src/oxide/cli/build/watching.ts +0 -225
  62. package/src/oxide/cli/help/index.ts +0 -69
  63. package/src/oxide/cli/index.ts +0 -204
  64. package/src/oxide/cli/init/index.ts +0 -59
  65. package/src/oxide/cli.ts +0 -1
  66. package/src/oxide/postcss-plugin.ts +0 -1
package/CHANGELOG.md CHANGED
@@ -9,13 +9,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - Nothing yet!
11
11
 
12
- ## [3.4.1] - 2014-01-05
12
+ ## [3.4.2] - 2024-03-27
13
+
14
+ ### Fixed
15
+
16
+ - Ensure max specificity of `0,0,1` for button and input Preflight rules ([#12735](https://github.com/tailwindlabs/tailwindcss/pull/12735))
17
+ - Improve glob handling for folders with `(`, `)`, `[` or `]` in the file path ([#12715](https://github.com/tailwindlabs/tailwindcss/pull/12715))
18
+ - Split `:has` rules when using `experimental.optimizeUniversalDefaults` ([#12736](https://github.com/tailwindlabs/tailwindcss/pull/12736))
19
+ - Sort arbitrary properties alphabetically across multiple class lists ([#12911](https://github.com/tailwindlabs/tailwindcss/pull/12911))
20
+ - Add `mix-blend-plus-darker` utility ([#12923](https://github.com/tailwindlabs/tailwindcss/pull/12923))
21
+ - Ensure dashes are allowed in variant modifiers ([#13303](https://github.com/tailwindlabs/tailwindcss/pull/13303))
22
+ - Fix crash showing completions in Intellisense when using a custom separator ([#13306](https://github.com/tailwindlabs/tailwindcss/pull/13306))
23
+ - Transpile `import.meta.url` in config files ([#13322](https://github.com/tailwindlabs/tailwindcss/pull/13322))
24
+ - Reset letter spacing for form elements ([#13150](https://github.com/tailwindlabs/tailwindcss/pull/13150))
25
+ - Fix missing `xx-large` and remove double `x-large` absolute size ([#13324](https://github.com/tailwindlabs/tailwindcss/pull/13324))
26
+ - Don't error when encountering nested CSS unless trying to `@apply` a class that uses nesting ([#13325](https://github.com/tailwindlabs/tailwindcss/pull/13325))
27
+ - Ensure that arbitrary properties respect `important` configuration ([#13353](https://github.com/tailwindlabs/tailwindcss/pull/13353))
28
+ - Change dark mode selector so `@apply` works correctly with pseudo elements ([#13379](https://github.com/tailwindlabs/tailwindcss/pull/13379))
29
+
30
+ ## [3.4.1] - 2024-01-05
13
31
 
14
32
  ### Fixed
15
33
 
16
34
  - Don't remove keyframe stops when using important utilities ([#12639](https://github.com/tailwindlabs/tailwindcss/pull/12639))
17
35
  - Don't add spaces to gradients and grid track names when followed by `calc()` ([#12704](https://github.com/tailwindlabs/tailwindcss/pull/12704))
18
36
  - Restore old behavior for `class` dark mode strategy ([#12717](https://github.com/tailwindlabs/tailwindcss/pull/12717))
37
+ - Improve glob handling for folders with `(`, `)`, `[` or `]` in the file path ([#12715](https://github.com/tailwindlabs/tailwindcss/pull/12715))
19
38
 
20
39
  ### Added
21
40
 
@@ -2351,7 +2370,8 @@ No release notes
2351
2370
 
2352
2371
  - Everything!
2353
2372
 
2354
- [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.4.1...HEAD
2373
+ [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.4.2...HEAD
2374
+ [3.4.2]: https://github.com/tailwindlabs/tailwindcss/compare/v3.4.1...v3.4.2
2355
2375
  [3.4.1]: https://github.com/tailwindlabs/tailwindcss/compare/v3.4.0...v3.4.1
2356
2376
  [3.4.0]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.7...v3.4.0
2357
2377
  [3.3.7]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.6...v3.3.7
package/README.md CHANGED
@@ -12,15 +12,14 @@
12
12
  A utility-first CSS framework for rapidly building custom user interfaces.
13
13
  </p>
14
14
 
15
-
16
15
  <p align="center">
17
- <a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci-stable.yml?branch=master" alt="Build Status"></a>
16
+ <a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci.yml?branch=master" alt="Build Status"></a>
18
17
  <a href="https://www.npmjs.com/package/tailwindcss"><img src="https://img.shields.io/npm/dt/tailwindcss.svg" alt="Total Downloads"></a>
19
18
  <a href="https://github.com/tailwindcss/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
20
19
  <a href="https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
21
20
  </p>
22
21
 
23
- ------
22
+ ---
24
23
 
25
24
  ## Documentation
26
25
 
@@ -167,17 +167,10 @@ let state = {
167
167
  // TODO: When we make the postcss plugin async-capable this can become async
168
168
  let files = _fastglob.default.sync(this.contentPatterns.all);
169
169
  for (let file of files){
170
- if (false) {
171
- content.push({
172
- file,
173
- extension: _path.default.extname(file).slice(1)
174
- });
175
- } else {
176
- content.push({
177
- content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"),
178
- extension: _path.default.extname(file).slice(1)
179
- });
180
- }
170
+ content.push({
171
+ content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"),
172
+ extension: _path.default.extname(file).slice(1)
173
+ });
181
174
  }
182
175
  // Resolve raw content in the tailwind config
183
176
  let rawContent = this.config.content.files.filter((file)=>{
package/lib/cli.js CHANGED
@@ -1,7 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- if (false) {
4
- module.exports = require("./oxide/cli");
5
- } else {
6
- module.exports = require("./cli/index");
7
- }
3
+ module.exports = require("./cli/index");
@@ -185,6 +185,7 @@ const _default = [
185
185
  "transitionDuration",
186
186
  "transitionTimingFunction",
187
187
  "willChange",
188
+ "contain",
188
189
  "content",
189
190
  "forcedColorAdjust"
190
191
  ];
@@ -325,7 +325,7 @@ let variantPlugins = {
325
325
  addVariant("dark", selector);
326
326
  } else if (mode === "class") {
327
327
  // Old behavior
328
- addVariant("dark", `:is(${selector} &)`);
328
+ addVariant("dark", `&:is(${selector} *)`);
329
329
  }
330
330
  },
331
331
  printVariant: ({ addVariant })=>{
@@ -2022,15 +2022,6 @@ let corePlugins = {
2022
2022
  matchUtilities({
2023
2023
  "space-x": (value)=>{
2024
2024
  value = value === "0" ? "0px" : value;
2025
- if (false) {
2026
- return {
2027
- "& > :not([hidden]) ~ :not([hidden])": {
2028
- "--tw-space-x-reverse": "0",
2029
- "margin-inline-end": `calc(${value} * var(--tw-space-x-reverse))`,
2030
- "margin-inline-start": `calc(${value} * calc(1 - var(--tw-space-x-reverse)))`
2031
- }
2032
- };
2033
- }
2034
2025
  return {
2035
2026
  "& > :not([hidden]) ~ :not([hidden])": {
2036
2027
  "--tw-space-x-reverse": "0",
@@ -2066,16 +2057,6 @@ let corePlugins = {
2066
2057
  matchUtilities({
2067
2058
  "divide-x": (value)=>{
2068
2059
  value = value === "0" ? "0px" : value;
2069
- if (false) {
2070
- return {
2071
- "& > :not([hidden]) ~ :not([hidden])": {
2072
- "@defaults border-width": {},
2073
- "--tw-divide-x-reverse": "0",
2074
- "border-inline-end-width": `calc(${value} * var(--tw-divide-x-reverse))`,
2075
- "border-inline-start-width": `calc(${value} * calc(1 - var(--tw-divide-x-reverse)))`
2076
- }
2077
- };
2078
- }
2079
2060
  return {
2080
2061
  "& > :not([hidden]) ~ :not([hidden])": {
2081
2062
  "@defaults border-width": {},
@@ -3692,6 +3673,9 @@ let corePlugins = {
3692
3673
  ".mix-blend-luminosity": {
3693
3674
  "mix-blend-mode": "luminosity"
3694
3675
  },
3676
+ ".mix-blend-plus-darker": {
3677
+ "mix-blend-mode": "plus-darker"
3678
+ },
3695
3679
  ".mix-blend-plus-lighter": {
3696
3680
  "mix-blend-mode": "plus-lighter"
3697
3681
  }
@@ -3705,7 +3689,7 @@ let corePlugins = {
3705
3689
  `var(--tw-shadow)`
3706
3690
  ].join(", ");
3707
3691
  return function({ matchUtilities , addDefaults , theme }) {
3708
- addDefaults(" box-shadow", {
3692
+ addDefaults("box-shadow", {
3709
3693
  "--tw-ring-offset-shadow": "0 0 #0000",
3710
3694
  "--tw-ring-shadow": "0 0 #0000",
3711
3695
  "--tw-shadow": "0 0 #0000",
@@ -4257,6 +4241,51 @@ let corePlugins = {
4257
4241
  ]
4258
4242
  ]
4259
4243
  ]),
4244
+ contain: ({ addDefaults , addUtilities })=>{
4245
+ let cssContainValue = "var(--tw-contain-size) var(--tw-contain-layout) var(--tw-contain-paint) var(--tw-contain-style)";
4246
+ addDefaults("contain", {
4247
+ "--tw-contain-size": " ",
4248
+ "--tw-contain-layout": " ",
4249
+ "--tw-contain-paint": " ",
4250
+ "--tw-contain-style": " "
4251
+ });
4252
+ addUtilities({
4253
+ ".contain-none": {
4254
+ contain: "none"
4255
+ },
4256
+ ".contain-content": {
4257
+ contain: "content"
4258
+ },
4259
+ ".contain-strict": {
4260
+ contain: "strict"
4261
+ },
4262
+ ".contain-size": {
4263
+ "@defaults contain": {},
4264
+ "--tw-contain-size": "size",
4265
+ contain: cssContainValue
4266
+ },
4267
+ ".contain-inline-size": {
4268
+ "@defaults contain": {},
4269
+ "--tw-contain-size": "inline-size",
4270
+ contain: cssContainValue
4271
+ },
4272
+ ".contain-layout": {
4273
+ "@defaults contain": {},
4274
+ "--tw-contain-layout": "layout",
4275
+ contain: cssContainValue
4276
+ },
4277
+ ".contain-paint": {
4278
+ "@defaults contain": {},
4279
+ "--tw-contain-paint": "paint",
4280
+ contain: cssContainValue
4281
+ },
4282
+ ".contain-style": {
4283
+ "@defaults contain": {},
4284
+ "--tw-contain-style": "style",
4285
+ contain: cssContainValue
4286
+ }
4287
+ });
4288
+ },
4260
4289
  content: (0, _createUtilityPlugin.default)("content", [
4261
4290
  [
4262
4291
  "content",
@@ -175,6 +175,7 @@ textarea {
175
175
  font-size: 100%; /* 1 */
176
176
  font-weight: inherit; /* 1 */
177
177
  line-height: inherit; /* 1 */
178
+ letter-spacing: inherit; /* 1 */
178
179
  color: inherit; /* 1 */
179
180
  margin: 0; /* 2 */
180
181
  padding: 0; /* 3 */
@@ -195,9 +196,9 @@ select {
195
196
  */
196
197
 
197
198
  button,
198
- [type='button'],
199
- [type='reset'],
200
- [type='submit'] {
199
+ input:where([type='button']),
200
+ input:where([type='reset']),
201
+ input:where([type='submit']) {
201
202
  -webkit-appearance: button; /* 1 */
202
203
  background-color: transparent; /* 2 */
203
204
  background-image: none; /* 2 */
@@ -29,12 +29,8 @@ function _interop_require_default(obj) {
29
29
  let defaults = {
30
30
  optimizeUniversalDefaults: false,
31
31
  generalizedModifiers: true,
32
- get disableColorOpacityUtilitiesByDefault () {
33
- return false;
34
- },
35
- get relativeContentPathsByDefault () {
36
- return false;
37
- }
32
+ disableColorOpacityUtilitiesByDefault: false,
33
+ relativeContentPathsByDefault: false
38
34
  };
39
35
  let featureFlags = {
40
36
  future: [
@@ -21,7 +21,6 @@ const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
21
21
  const _path = /*#__PURE__*/ _interop_require_default(require("path"));
22
22
  const _isglob = /*#__PURE__*/ _interop_require_default(require("is-glob"));
23
23
  const _fastglob = /*#__PURE__*/ _interop_require_default(require("fast-glob"));
24
- const _normalizepath = /*#__PURE__*/ _interop_require_default(require("normalize-path"));
25
24
  const _parseGlob = require("../util/parseGlob");
26
25
  const _sharedState = require("./sharedState");
27
26
  function _interop_require_default(obj) {
@@ -29,11 +28,42 @@ function _interop_require_default(obj) {
29
28
  default: obj
30
29
  };
31
30
  }
31
+ /*!
32
+ * Modified version of normalize-path, original license below
33
+ *
34
+ * normalize-path <https://github.com/jonschlinkert/normalize-path>
35
+ *
36
+ * Copyright (c) 2014-2018, Jon Schlinkert.
37
+ * Released under the MIT License.
38
+ */ function normalizePath(path) {
39
+ if (typeof path !== "string") {
40
+ throw new TypeError("expected path to be a string");
41
+ }
42
+ if (path === "\\" || path === "/") return "/";
43
+ var len = path.length;
44
+ if (len <= 1) return path;
45
+ // ensure that win32 namespaces has two leading slashes, so that the path is
46
+ // handled properly by the win32 version of path.parse() after being normalized
47
+ // https://msdn.microsoft.com/library/windows/desktop/aa365247(v=vs.85).aspx#namespaces
48
+ var prefix = "";
49
+ if (len > 4 && path[3] === "\\") {
50
+ var ch = path[2];
51
+ if ((ch === "?" || ch === ".") && path.slice(0, 2) === "\\\\") {
52
+ path = path.slice(2);
53
+ prefix = "//";
54
+ }
55
+ }
56
+ // Modified part: instead of purely splitting on `\\` and `/`, we split on
57
+ // `/` and `\\` that is _not_ followed by any of the following characters: ()[]
58
+ // This is to ensure that we keep the escaping of brackets and parentheses
59
+ let segs = path.split(/[/\\]+(?![\(\)\[\]])/);
60
+ return prefix + segs.join("/");
61
+ }
32
62
  function parseCandidateFiles(context, tailwindConfig) {
33
63
  let files = tailwindConfig.content.files;
34
64
  // Normalize the file globs
35
65
  files = files.filter((filePath)=>typeof filePath === "string");
36
- files = files.map(_normalizepath.default);
66
+ files = files.map(normalizePath);
37
67
  // Split into included and excluded globs
38
68
  let tasks = _fastglob.default.generateTasks(files);
39
69
  /** @type {ContentPath[]} */ let included = [];
@@ -60,6 +90,9 @@ function parseCandidateFiles(context, tailwindConfig) {
60
90
  * @param {boolean} ignore
61
91
  * @returns {ContentPath}
62
92
  */ function parseFilePath(filePath, ignore) {
93
+ // Escape special characters in the file path such as: ()[]
94
+ // But only if the special character isn't already escaped
95
+ filePath = filePath.replace(/(?<!\\)([\[\]\(\)])/g, "\\$1");
63
96
  let contentPath = {
64
97
  original: filePath,
65
98
  base: filePath,
@@ -81,7 +114,7 @@ function parseCandidateFiles(context, tailwindConfig) {
81
114
  // Afaik, this technically shouldn't be needed but there's probably
82
115
  // some internal, direct path matching with a normalized path in
83
116
  // a package which can't handle mixed directory separators
84
- let base = (0, _normalizepath.default)(contentPath.base);
117
+ let base = normalizePath(contentPath.base);
85
118
  // If the user's file path contains any special characters (like parens) for instance fast-glob
86
119
  // is like "OOOH SHINY" and treats them as such. So we have to escape the base path to fix this
87
120
  base = _fastglob.default.escapePath(base);
@@ -128,7 +128,7 @@ function* buildRegExps(context) {
128
128
  ]),
129
129
  // With variant modifier (e.g.: group-[..]/modifier)
130
130
  _regex.pattern([
131
- /([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/,
131
+ /([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/[\w_-]+/,
132
132
  separator
133
133
  ]),
134
134
  _regex.pattern([
@@ -144,7 +144,7 @@ function* buildRegExps(context) {
144
144
  _regex.any([
145
145
  // With variant modifier (e.g.: group-[..]/modifier)
146
146
  _regex.pattern([
147
- /([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/,
147
+ /([^\s"'`\[\\]+-)?\[[^\s`]+\]\/[\w_-]+/,
148
148
  separator
149
149
  ]),
150
150
  _regex.pattern([
@@ -380,6 +380,19 @@ function processApply(root, context, localCache) {
380
380
  throw apply.error(`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`);
381
381
  }
382
382
  let rules = applyClassCache.get(applyCandidate);
383
+ // Verify that we can apply the class
384
+ for (let [, rule] of rules){
385
+ if (rule.type === "atrule") {
386
+ continue;
387
+ }
388
+ rule.walkRules(()=>{
389
+ throw apply.error([
390
+ `The \`${applyCandidate}\` class cannot be used with \`@apply\` because \`@apply\` does not currently support nested CSS.`,
391
+ "Rewrite the selector without nesting or configure the `tailwindcss/nesting` plugin:",
392
+ "https://tailwindcss.com/docs/using-with-preprocessors#nesting"
393
+ ].join("\n"));
394
+ });
395
+ }
383
396
  candidates.push([
384
397
  applyCandidate,
385
398
  important,
@@ -154,37 +154,25 @@ function expandTailwindAtRules(context) {
154
154
  ]);
155
155
  let seen = new Set();
156
156
  env.DEBUG && console.time("Reading changed files");
157
- if (false) {
158
- // TODO: Pass through or implement `extractor`
159
- for (let candidate of require("@tailwindcss/oxide").parseCandidateStringsFromFiles(context.changedContent)){
160
- candidates.add(candidate);
161
- }
162
- // for (let { file, content, extension } of context.changedContent) {
163
- // let transformer = getTransformer(context.tailwindConfig, extension)
164
- // let extractor = getExtractor(context, extension)
165
- // getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen)
166
- // }
167
- } else {
168
- /** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */ let regexParserContent = [];
169
- for (let item of context.changedContent){
170
- let transformer = getTransformer(context.tailwindConfig, item.extension);
171
- let extractor = getExtractor(context, item.extension);
172
- regexParserContent.push([
173
- item,
174
- {
175
- transformer,
176
- extractor
177
- }
178
- ]);
179
- }
180
- const BATCH_SIZE = 500;
181
- for(let i = 0; i < regexParserContent.length; i += BATCH_SIZE){
182
- let batch = regexParserContent.slice(i, i + BATCH_SIZE);
183
- await Promise.all(batch.map(async ([{ file , content }, { transformer , extractor }])=>{
184
- content = file ? await _fs.default.promises.readFile(file, "utf8") : content;
185
- getClassCandidates(transformer(content), extractor, candidates, seen);
186
- }));
187
- }
157
+ /** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */ let regexParserContent = [];
158
+ for (let item of context.changedContent){
159
+ let transformer = getTransformer(context.tailwindConfig, item.extension);
160
+ let extractor = getExtractor(context, item.extension);
161
+ regexParserContent.push([
162
+ item,
163
+ {
164
+ transformer,
165
+ extractor
166
+ }
167
+ ]);
168
+ }
169
+ const BATCH_SIZE = 500;
170
+ for(let i = 0; i < regexParserContent.length; i += BATCH_SIZE){
171
+ let batch = regexParserContent.slice(i, i + BATCH_SIZE);
172
+ await Promise.all(batch.map(async ([{ file , content }, { transformer , extractor }])=>{
173
+ content = file ? await _fs.default.promises.readFile(file, "utf8") : content;
174
+ getClassCandidates(transformer(content), extractor, candidates, seen);
175
+ }));
188
176
  }
189
177
  env.DEBUG && console.timeEnd("Reading changed files");
190
178
  // ---
@@ -192,7 +180,7 @@ function expandTailwindAtRules(context) {
192
180
  let classCacheCount = context.classCache.size;
193
181
  env.DEBUG && console.time("Generate rules");
194
182
  env.DEBUG && console.time("Sorting candidates");
195
- let sortedCandidates = false ? candidates : new Set([
183
+ let sortedCandidates = new Set([
196
184
  ...candidates
197
185
  ].sort((a, z)=>{
198
186
  if (a === z) return 0;
@@ -514,12 +514,15 @@ function extractArbitraryProperty(classCandidate, context) {
514
514
  if (!isParsableCssValue(property, normalized)) {
515
515
  return null;
516
516
  }
517
- let sort = context.offsets.arbitraryProperty();
517
+ let sort = context.offsets.arbitraryProperty(classCandidate);
518
518
  return [
519
519
  [
520
520
  {
521
521
  sort,
522
- layer: "utilities"
522
+ layer: "utilities",
523
+ options: {
524
+ respectImportant: true
525
+ }
523
526
  },
524
527
  ()=>({
525
528
  [(0, _nameClass.asClass)(classCandidate)]: {
@@ -31,6 +31,10 @@ function lazyJiti() {
31
31
  return jiti !== null && jiti !== void 0 ? jiti : jiti = (0, _jiti.default)(__filename, {
32
32
  interopDefault: true,
33
33
  transform: (opts)=>{
34
+ // Sucrase can't transform import.meta so we have to use Babel
35
+ if (opts.source.includes("import.meta")) {
36
+ return require("jiti/dist/babel.js")(opts);
37
+ }
34
38
  return (0, _sucrase.transform)(opts.source, {
35
39
  transforms: [
36
40
  "typescript",
@@ -66,15 +66,19 @@ class Offsets {
66
66
  variants: 0n,
67
67
  parallelIndex: 0n,
68
68
  index: this.offsets[layer]++,
69
+ propertyOffset: 0n,
70
+ property: "",
69
71
  options: []
70
72
  };
71
73
  }
72
74
  /**
75
+ * @param {string} name
73
76
  * @returns {RuleOffset}
74
- */ arbitraryProperty() {
77
+ */ arbitraryProperty(name) {
75
78
  return {
76
79
  ...this.create("utilities"),
77
- arbitrary: 1n
80
+ arbitrary: 1n,
81
+ property: name
78
82
  };
79
83
  }
80
84
  /**
@@ -214,6 +218,10 @@ class Offsets {
214
218
  if (a.arbitrary !== b.arbitrary) {
215
219
  return a.arbitrary - b.arbitrary;
216
220
  }
221
+ // Always sort arbitrary properties alphabetically
222
+ if (a.propertyOffset !== b.propertyOffset) {
223
+ return a.propertyOffset - b.propertyOffset;
224
+ }
217
225
  // Sort utilities, components, etc… in the order they were registered
218
226
  return a.index - b.index;
219
227
  }
@@ -267,8 +275,49 @@ class Offsets {
267
275
  * @template T
268
276
  * @param {[RuleOffset, T][]} list
269
277
  * @returns {[RuleOffset, T][]}
278
+ */ sortArbitraryProperties(list) {
279
+ // Collect all known arbitrary properties
280
+ let known = new Set();
281
+ for (let [offset] of list){
282
+ if (offset.arbitrary === 1n) {
283
+ known.add(offset.property);
284
+ }
285
+ }
286
+ // No arbitrary properties? Nothing to do.
287
+ if (known.size === 0) {
288
+ return list;
289
+ }
290
+ // Sort the properties alphabetically
291
+ let properties = Array.from(known).sort();
292
+ // Create a map from the property name to its offset
293
+ let offsets = new Map();
294
+ let offset = 1n;
295
+ for (let property of properties){
296
+ offsets.set(property, offset++);
297
+ }
298
+ // Apply the sorted offsets to the list
299
+ return list.map((item)=>{
300
+ let [offset, rule] = item;
301
+ var _offsets_get;
302
+ offset = {
303
+ ...offset,
304
+ propertyOffset: (_offsets_get = offsets.get(offset.property)) !== null && _offsets_get !== void 0 ? _offsets_get : 0n
305
+ };
306
+ return [
307
+ offset,
308
+ rule
309
+ ];
310
+ });
311
+ }
312
+ /**
313
+ * @template T
314
+ * @param {[RuleOffset, T][]} list
315
+ * @returns {[RuleOffset, T][]}
270
316
  */ sort(list) {
317
+ // Sort arbitrary variants so they're in alphabetical order
271
318
  list = this.remapArbitraryVariantOffsets(list);
319
+ // Sort arbitrary properties so they're in alphabetical order
320
+ list = this.sortArbitraryProperties(list);
272
321
  return list.sort(([a], [b])=>(0, _bigSign.default)(this.compare(a, b)));
273
322
  }
274
323
  }
@@ -111,7 +111,9 @@ function resolveDefaultsAtRules({ tailwindConfig }) {
111
111
  // we consider them separately because merging the declarations into
112
112
  // a single rule will cause browsers that do not understand the
113
113
  // vendor prefix to throw out the whole rule
114
- let selectorGroupName = selector.includes(":-") || selector.includes("::-") ? selector : "__DEFAULT__";
114
+ // Additionally if a selector contains `:has` we also consider
115
+ // it separately because FF only recently gained support for it
116
+ let selectorGroupName = selector.includes(":-") || selector.includes("::-") || selector.includes(":has") ? selector : "__DEFAULT__";
115
117
  var _selectorGroups_get;
116
118
  let selectors = (_selectorGroups_get = selectorGroups.get(selectorGroupName)) !== null && _selectorGroups_get !== void 0 ? _selectorGroups_get : new Set();
117
119
  selectorGroups.set(selectorGroupName, selectors);
@@ -1021,6 +1021,10 @@ function registerPlugins(plugins, context) {
1021
1021
  };
1022
1022
  // Generate a list of available variants with meta information of the type of variant.
1023
1023
  context.getVariants = function getVariants() {
1024
+ // We use a unique, random ID for candidate names to avoid conflicts
1025
+ // We can't use characters like `_`, `:`, `@` or `.` because they might
1026
+ // be used as a separator
1027
+ let id = Math.random().toString(36).substring(7).toUpperCase();
1024
1028
  let result = [];
1025
1029
  for (let [name, options] of context.variantOptions.entries()){
1026
1030
  if (options.variantInfo === VARIANT_INFO.Base) continue;
@@ -1031,7 +1035,7 @@ function registerPlugins(plugins, context) {
1031
1035
  values: Object.keys((_options_values = options.values) !== null && _options_values !== void 0 ? _options_values : {}),
1032
1036
  hasDash: name !== "@",
1033
1037
  selectors ({ modifier , value } = {}) {
1034
- let candidate = "__TAILWIND_PLACEHOLDER__";
1038
+ let candidate = `TAILWINDPLACEHOLDER${id}`;
1035
1039
  let rule = _postcss.default.rule({
1036
1040
  selector: `.${candidate}`
1037
1041
  });
@@ -34,20 +34,12 @@ _export(exports, {
34
34
  return resolveDebug;
35
35
  }
36
36
  });
37
- const _packagejson = /*#__PURE__*/ _interop_require_default(require("../../package.json"));
38
- function _interop_require_default(obj) {
39
- return obj && obj.__esModule ? obj : {
40
- default: obj
41
- };
42
- }
43
37
  const env = typeof process !== "undefined" ? {
44
38
  NODE_ENV: process.env.NODE_ENV,
45
- DEBUG: resolveDebug(process.env.DEBUG),
46
- ENGINE: _packagejson.default.tailwindcss.engine
39
+ DEBUG: resolveDebug(process.env.DEBUG)
47
40
  } : {
48
41
  NODE_ENV: "production",
49
- DEBUG: false,
50
- ENGINE: _packagejson.default.tailwindcss.engine
42
+ DEBUG: false
51
43
  };
52
44
  const contextMap = new Map();
53
45
  const configContextMap = new Map();