tailwindcss 0.0.0-insiders.d87bdb2 → 0.0.0-insiders.db475be

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,9 +9,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Fixed
11
11
 
12
+ - Remove opacity variables from `:visited` pseudo class ([#7458](https://github.com/tailwindlabs/tailwindcss/pull/7458))
13
+ - Support arbitrary values + calc + theme with quotes ([#7462](https://github.com/tailwindlabs/tailwindcss/pull/7462))
14
+
15
+ ## [3.0.22] - 2022-02-11
16
+
17
+ ### Fixed
18
+
19
+ - Temporarily move postcss to dependencies ([#7424](https://github.com/tailwindlabs/tailwindcss/pull/7424))
20
+
21
+ ## [3.0.21] - 2022-02-10
22
+
23
+ ### Fixed
24
+
25
+ - Move prettier plugin to dev dependencies ([#7418](https://github.com/tailwindlabs/tailwindcss/pull/7418))
26
+
27
+ ## [3.0.20] - 2022-02-10
28
+
29
+ ### Added
30
+
31
+ - Expose `context.sortClassList(classes)` ([#7412](https://github.com/tailwindlabs/tailwindcss/pull/7412))
32
+
33
+ ## [3.0.19] - 2022-02-07
34
+
35
+ ### Fixed
36
+
12
37
  - Fix preflight border color fallback ([#7288](https://github.com/tailwindlabs/tailwindcss/pull/7288))
13
38
  - Correctly parse shadow lengths without a leading zero ([#7289](https://github.com/tailwindlabs/tailwindcss/pull/7289))
14
39
  - Don't crash when scanning extremely long class candidates ([#7331](https://github.com/tailwindlabs/tailwindcss/pull/7331))
40
+ - Use less hacky fix for URLs detected as custom properties ([#7275](https://github.com/tailwindlabs/tailwindcss/pull/7275))
41
+ - Correctly generate negative utilities when dash is before the prefix ([#7295](https://github.com/tailwindlabs/tailwindcss/pull/7295))
42
+ - Detect prefixed negative utilities in the safelist ([#7295](https://github.com/tailwindlabs/tailwindcss/pull/7295))
15
43
 
16
44
  ## [3.0.18] - 2022-01-28
17
45
 
@@ -1840,7 +1868,11 @@ No release notes
1840
1868
 
1841
1869
  - Everything!
1842
1870
 
1843
- [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.18...HEAD
1871
+ [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.22...HEAD
1872
+ [3.0.22]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.21...v3.0.22
1873
+ [3.0.21]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.20...v3.0.21
1874
+ [3.0.20]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.19...v3.0.20
1875
+ [3.0.19]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.18...v3.0.19
1844
1876
  [3.0.18]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.17...v3.0.18
1845
1877
  [3.0.17]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.16...v3.0.17
1846
1878
  [3.0.16]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.15...v3.0.16
@@ -116,7 +116,28 @@ let variantPlugins = {
116
116
  'last-of-type',
117
117
  'only-of-type',
118
118
  // State
119
- 'visited',
119
+ [
120
+ 'visited',
121
+ ({ container })=>{
122
+ let toRemove = [
123
+ '--tw-text-opacity',
124
+ '--tw-border-opacity',
125
+ '--tw-bg-opacity'
126
+ ];
127
+ container.walkDecls((decl)=>{
128
+ if (toRemove.includes(decl.prop)) {
129
+ decl.remove();
130
+ return;
131
+ }
132
+ for (const varName of toRemove){
133
+ if (decl.value.includes(`/ var(${varName})`)) {
134
+ decl.value = decl.value.replace(`/ var(${varName})`, '');
135
+ }
136
+ }
137
+ });
138
+ return ':visited';
139
+ },
140
+ ],
120
141
  'target',
121
142
  [
122
143
  'open',
@@ -149,13 +170,22 @@ let variantPlugins = {
149
170
  ]
150
171
  );
151
172
  for (let [variantName, state] of pseudoVariants){
152
- addVariant(variantName, `&${state}`);
173
+ addVariant(variantName, (ctx)=>{
174
+ let result = typeof state === 'function' ? state(ctx) : state;
175
+ return `&${result}`;
176
+ });
153
177
  }
154
178
  for (let [variantName1, state1] of pseudoVariants){
155
- addVariant(`group-${variantName1}`, `:merge(.group)${state1} &`);
179
+ addVariant(`group-${variantName1}`, (ctx)=>{
180
+ let result = typeof state1 === 'function' ? state1(ctx) : state1;
181
+ return `:merge(.group)${result} &`;
182
+ });
156
183
  }
157
184
  for (let [variantName2, state2] of pseudoVariants){
158
- addVariant(`peer-${variantName2}`, `:merge(.peer)${state2} ~ &`);
185
+ addVariant(`peer-${variantName2}`, (ctx)=>{
186
+ let result = typeof state2 === 'function' ? state2(ctx) : state2;
187
+ return `:merge(.peer)${result} ~ &`;
188
+ });
159
189
  }
160
190
  },
161
191
  directionVariants: ({ addVariant })=>{
@@ -13,6 +13,8 @@ const PATTERNS = [
13
13
  /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source,
14
14
  /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source,
15
15
  /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source,
16
+ /([^<>"'`\s]*\[[^<>"'`\s]*\('[^"`\s]*'\)+\])/.source,
17
+ /([^<>"'`\s]*\[[^<>"'`\s]*\("[^'`\s]*"\)+\])/.source,
16
18
  /([^<>"'`\s]*\['[^"'`\s]*'\])/.source,
17
19
  /([^<>"'`\s]*\["[^"'`\s]*"\])/.source,
18
20
  /([^<>"'`\s]*\[[^<>"'`\s]*:[^\]\s]*\])/.source,
@@ -140,11 +140,14 @@ function processApply(root, context) {
140
140
  throw apply.error(`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`);
141
141
  }
142
142
  for (let applyCandidate of applyCandidates){
143
+ if ([
144
+ prefix(context, 'group'),
145
+ prefix(context, 'peer')
146
+ ].includes(applyCandidate)) {
147
+ // TODO: Link to specific documentation page with error code.
148
+ throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
149
+ }
143
150
  if (!applyClassCache.has(applyCandidate)) {
144
- if (applyCandidate === prefix(context, 'group')) {
145
- // TODO: Link to specific documentation page with error code.
146
- throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
147
- }
148
151
  throw apply.error(`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`);
149
152
  }
150
153
  let rules = applyClassCache.get(applyCandidate);
@@ -72,8 +72,14 @@ function applyPrefix(matches, context) {
72
72
  match[1].clone()
73
73
  ]
74
74
  });
75
+ let classCandidate = match[1].raws.tailwind.classCandidate;
75
76
  container.walkRules((r)=>{
76
- r.selector = (0, _prefixSelector).default(context.tailwindConfig.prefix, r.selector);
77
+ // If this is a negative utility with a dash *before* the prefix we
78
+ // have to ensure that the generated selector matches the candidate
79
+ // Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
80
+ // The disconnect between candidate <-> class can cause @apply to hard crash.
81
+ let shouldPrependNegative = classCandidate.startsWith('-');
82
+ r.selector = (0, _prefixSelector).default(context.tailwindConfig.prefix, r.selector, shouldPrependNegative);
77
83
  });
78
84
  match[1] = container.nodes[0];
79
85
  }
@@ -222,6 +228,7 @@ function applyVariant(variant, matches, context) {
222
228
  // .sm:underline {} is a variant of something in the utilities layer
223
229
  // .sm:container {} is a variant of the container component
224
230
  clone.nodes[0].raws.tailwind = {
231
+ ...clone.nodes[0].raws.tailwind,
225
232
  parentLayer: meta.layer
226
233
  };
227
234
  var _collectedFormats;
@@ -265,10 +272,32 @@ function parseRules(rule, cache, options = {}) {
265
272
  }
266
273
  const IS_VALID_PROPERTY_NAME = /^[a-z_-]/;
267
274
  function isValidPropName(name) {
268
- // TODO: properly fix this!
269
- return IS_VALID_PROPERTY_NAME.test(name) && !name.startsWith('http');
275
+ return IS_VALID_PROPERTY_NAME.test(name);
276
+ }
277
+ /**
278
+ * @param {string} declaration
279
+ * @returns {boolean}
280
+ */ function looksLikeUri(declaration) {
281
+ // Quick bailout for obvious non-urls
282
+ // This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
283
+ if (!declaration.includes('://')) {
284
+ return false;
285
+ }
286
+ try {
287
+ const url = new URL(declaration);
288
+ return url.scheme !== '' && url.host !== '';
289
+ } catch (err) {
290
+ // Definitely not a valid url
291
+ return false;
292
+ }
270
293
  }
271
294
  function isParsableCssValue(property, value) {
295
+ // We don't want to to treat [https://example.com] as a custom property
296
+ // Even though, according to the CSS grammar, it's a totally valid CSS declaration
297
+ // So we short-circuit here by checking if the custom property looks like a url
298
+ if (looksLikeUri(`${property}:${value}`)) {
299
+ return false;
300
+ }
272
301
  try {
273
302
  _postcss.default.parse(`a{${property}:${value}}`).toResult();
274
303
  return true;
@@ -348,6 +377,15 @@ function* resolveMatchedPlugins(classCandidate, context) {
348
377
  function splitWithSeparator(input, separator) {
349
378
  return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'));
350
379
  }
380
+ function* recordCandidates(matches, classCandidate) {
381
+ for (const match of matches){
382
+ match[1].raws.tailwind = {
383
+ ...match[1].raws.tailwind,
384
+ classCandidate
385
+ };
386
+ yield match;
387
+ }
388
+ }
351
389
  function* resolveMatches(candidate, context) {
352
390
  let separator = context.tailwindConfig.separator;
353
391
  let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse();
@@ -457,7 +495,9 @@ function* resolveMatches(candidate, context) {
457
495
  ]);
458
496
  continue;
459
497
  }
460
- matches = applyPrefix(matches.flat(), context);
498
+ matches = matches.flat();
499
+ matches = Array.from(recordCandidates(matches, classCandidate));
500
+ matches = applyPrefix(matches, context);
461
501
  if (important) {
462
502
  matches = applyImportant(matches, context);
463
503
  }
@@ -465,6 +505,10 @@ function* resolveMatches(candidate, context) {
465
505
  matches = applyVariant(variant, matches, context);
466
506
  }
467
507
  for (let match1 of matches){
508
+ match1[1].raws.tailwind = {
509
+ ...match1[1].raws.tailwind,
510
+ candidate
511
+ };
468
512
  // Apply final format selector
469
513
  if (match1[0].collectedFormats) {
470
514
  let finalFormat = (0, _formatVariantSelector).formatVariantSelector('&', ...match1[0].collectedFormats);
@@ -24,6 +24,7 @@ var _toPath = require("../util/toPath");
24
24
  var _log = _interopRequireDefault(require("../util/log"));
25
25
  var _negateValue = _interopRequireDefault(require("../util/negateValue"));
26
26
  var _isValidArbitraryValue = _interopRequireDefault(require("../util/isValidArbitraryValue"));
27
+ var _generateRules = require("./generateRules");
27
28
  function _interopRequireDefault(obj) {
28
29
  return obj && obj.__esModule ? obj : {
29
30
  default: obj
@@ -50,6 +51,10 @@ function _interopRequireWildcard(obj) {
50
51
  return newObj;
51
52
  }
52
53
  }
54
+ function prefix(context, selector) {
55
+ let prefix1 = context.tailwindConfig.prefix;
56
+ return typeof prefix1 === 'function' ? prefix1(selector) : prefix1 + selector;
57
+ }
53
58
  function parseVariantFormatString(input) {
54
59
  if (input.includes('{')) {
55
60
  if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`);
@@ -673,18 +678,31 @@ function registerPlugins(plugins, context) {
673
678
  }
674
679
  if (checks.length > 0) {
675
680
  let patternMatchingCount = new Map();
681
+ let prefixLength = context.tailwindConfig.prefix.length;
676
682
  for (let util of classList){
677
683
  let utils = Array.isArray(util) ? (()=>{
678
684
  let [utilName, options] = util;
679
685
  var ref;
680
- let classes = Object.keys((ref = options === null || options === void 0 ? void 0 : options.values) !== null && ref !== void 0 ? ref : {}).map((value)=>(0, _nameClass).formatClass(utilName, value)
686
+ let values = Object.keys((ref = options === null || options === void 0 ? void 0 : options.values) !== null && ref !== void 0 ? ref : {});
687
+ let classes = values.map((value)=>(0, _nameClass).formatClass(utilName, value)
681
688
  );
682
689
  if (options === null || options === void 0 ? void 0 : options.supportsNegativeValues) {
690
+ // This is the normal negated version
691
+ // e.g. `-inset-1` or `-tw-inset-1`
683
692
  classes = [
684
693
  ...classes,
685
694
  ...classes.map((cls)=>'-' + cls
686
695
  )
687
696
  ];
697
+ // This is the negated version *after* the prefix
698
+ // e.g. `tw--inset-1`
699
+ // The prefix is already attached to util name
700
+ // So we add the negative after the prefix
701
+ classes = [
702
+ ...classes,
703
+ ...classes.map((cls)=>cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength)
704
+ ),
705
+ ];
688
706
  }
689
707
  return classes;
690
708
  })() : [
@@ -723,9 +741,44 @@ function registerPlugins(plugins, context) {
723
741
  }
724
742
  }
725
743
  }
744
+ // A list of utilities that are used by certain Tailwind CSS utilities but
745
+ // that don't exist on their own. This will result in them "not existing" and
746
+ // sorting could be weird since you still require them in order to make the
747
+ // host utitlies work properly. (Thanks Biology)
748
+ let parasiteUtilities = new Set([
749
+ prefix(context, 'group'),
750
+ prefix(context, 'peer')
751
+ ]);
752
+ context.sortClassList = function sortClassList(classes) {
753
+ let sortedClassNames = new Map();
754
+ for (let [sort, rule] of (0, _generateRules).generateRules(new Set(classes), context)){
755
+ if (sortedClassNames.has(rule.raws.tailwind.candidate)) continue;
756
+ sortedClassNames.set(rule.raws.tailwind.candidate, sort);
757
+ }
758
+ return classes.map((className)=>{
759
+ var ref;
760
+ let order = (ref = sortedClassNames.get(className)) !== null && ref !== void 0 ? ref : null;
761
+ if (order === null && parasiteUtilities.has(className)) {
762
+ // This will make sure that it is at the very beginning of the
763
+ // `components` layer which technically means 'before any
764
+ // components'.
765
+ order = context.layerOrder.components;
766
+ }
767
+ return [
768
+ className,
769
+ order
770
+ ];
771
+ }).sort(([, a], [, z])=>{
772
+ if (a === z) return 0;
773
+ if (a === null) return -1;
774
+ if (z === null) return 1;
775
+ return (0, _bigSign).default(a - z);
776
+ }).map(([className])=>className
777
+ );
778
+ };
726
779
  // Generate a list of strings for autocompletion purposes, e.g.
727
780
  // ['uppercase', 'lowercase', ...]
728
- context.getClassList = function() {
781
+ context.getClassList = function getClassList() {
729
782
  let output = [];
730
783
  for (let util of classList){
731
784
  if (Array.isArray(util)) {
@@ -4,18 +4,17 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  exports.default = _default;
6
6
  var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
7
- var _tap = require("./tap");
8
7
  function _interopRequireDefault(obj) {
9
8
  return obj && obj.__esModule ? obj : {
10
9
  default: obj
11
10
  };
12
11
  }
13
- function _default(prefix, selector) {
12
+ function _default(prefix, selector, prependNegative = false) {
14
13
  return (0, _postcssSelectorParser).default((selectors)=>{
15
14
  selectors.walkClasses((classSelector)=>{
16
- (0, _tap).tap(classSelector.value, (baseClass)=>{
17
- classSelector.value = `${prefix}${baseClass}`;
18
- });
15
+ let baseClass = classSelector.value;
16
+ let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-');
17
+ classSelector.value = shouldPlaceNegativeBeforePrefix ? `-${prefix}${baseClass.slice(1)}` : `${prefix}${baseClass}`;
19
18
  });
20
19
  }).processSync(selector);
21
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwindcss",
3
- "version": "0.0.0-insiders.d87bdb2",
3
+ "version": "0.0.0-insiders.db475be",
4
4
  "description": "A utility-first CSS framework for rapidly building custom user interfaces.",
5
5
  "license": "MIT",
6
6
  "main": "lib/index.js",
@@ -44,14 +44,14 @@
44
44
  "@swc/register": "^0.1.10",
45
45
  "autoprefixer": "^10.4.2",
46
46
  "cssnano": "^5.0.16",
47
- "esbuild": "^0.14.10",
47
+ "esbuild": "^0.14.21",
48
48
  "eslint": "^8.8.0",
49
49
  "eslint-config-prettier": "^8.3.0",
50
50
  "eslint-plugin-prettier": "^4.0.0",
51
- "jest": "^27.4.7",
52
- "jest-diff": "^27.4.6",
53
- "postcss": "^8.4.5",
51
+ "jest": "^27.5.1",
52
+ "jest-diff": "^27.5.1",
54
53
  "prettier": "^2.5.1",
54
+ "prettier-plugin-tailwindcss": "^0.1.7",
55
55
  "rimraf": "^3.0.0"
56
56
  },
57
57
  "peerDependencies": {
@@ -72,6 +72,7 @@
72
72
  "is-glob": "^4.0.3",
73
73
  "normalize-path": "^3.0.0",
74
74
  "object-hash": "^2.2.0",
75
+ "postcss": "^8.4.6",
75
76
  "postcss-js": "^4.0.0",
76
77
  "postcss-load-config": "^3.1.0",
77
78
  "postcss-nested": "5.0.6",
package/peers/index.js CHANGED
@@ -22,31 +22,31 @@ var require_picocolors = __commonJS({
22
22
  };
23
23
  var createColors = (enabled = isColorSupported) => ({
24
24
  isColorSupported: enabled,
25
- reset: enabled ? (s) => `${s}` : String,
26
- bold: enabled ? formatter("", "", "") : String,
27
- dim: enabled ? formatter("", "", "") : String,
28
- italic: enabled ? formatter("", "") : String,
29
- underline: enabled ? formatter("", "") : String,
30
- inverse: enabled ? formatter("", "") : String,
31
- hidden: enabled ? formatter("", "") : String,
32
- strikethrough: enabled ? formatter("", "") : String,
33
- black: enabled ? formatter("", "") : String,
34
- red: enabled ? formatter("", "") : String,
35
- green: enabled ? formatter("", "") : String,
36
- yellow: enabled ? formatter("", "") : String,
37
- blue: enabled ? formatter("", "") : String,
38
- magenta: enabled ? formatter("", "") : String,
39
- cyan: enabled ? formatter("", "") : String,
40
- white: enabled ? formatter("", "") : String,
41
- gray: enabled ? formatter("", "") : String,
42
- bgBlack: enabled ? formatter("", "") : String,
43
- bgRed: enabled ? formatter("", "") : String,
44
- bgGreen: enabled ? formatter("", "") : String,
45
- bgYellow: enabled ? formatter("", "") : String,
46
- bgBlue: enabled ? formatter("", "") : String,
47
- bgMagenta: enabled ? formatter("", "") : String,
48
- bgCyan: enabled ? formatter("", "") : String,
49
- bgWhite: enabled ? formatter("", "") : String
25
+ reset: enabled ? (s) => `\x1B[0m${s}\x1B[0m` : String,
26
+ bold: enabled ? formatter("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m") : String,
27
+ dim: enabled ? formatter("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m") : String,
28
+ italic: enabled ? formatter("\x1B[3m", "\x1B[23m") : String,
29
+ underline: enabled ? formatter("\x1B[4m", "\x1B[24m") : String,
30
+ inverse: enabled ? formatter("\x1B[7m", "\x1B[27m") : String,
31
+ hidden: enabled ? formatter("\x1B[8m", "\x1B[28m") : String,
32
+ strikethrough: enabled ? formatter("\x1B[9m", "\x1B[29m") : String,
33
+ black: enabled ? formatter("\x1B[30m", "\x1B[39m") : String,
34
+ red: enabled ? formatter("\x1B[31m", "\x1B[39m") : String,
35
+ green: enabled ? formatter("\x1B[32m", "\x1B[39m") : String,
36
+ yellow: enabled ? formatter("\x1B[33m", "\x1B[39m") : String,
37
+ blue: enabled ? formatter("\x1B[34m", "\x1B[39m") : String,
38
+ magenta: enabled ? formatter("\x1B[35m", "\x1B[39m") : String,
39
+ cyan: enabled ? formatter("\x1B[36m", "\x1B[39m") : String,
40
+ white: enabled ? formatter("\x1B[37m", "\x1B[39m") : String,
41
+ gray: enabled ? formatter("\x1B[90m", "\x1B[39m") : String,
42
+ bgBlack: enabled ? formatter("\x1B[40m", "\x1B[49m") : String,
43
+ bgRed: enabled ? formatter("\x1B[41m", "\x1B[49m") : String,
44
+ bgGreen: enabled ? formatter("\x1B[42m", "\x1B[49m") : String,
45
+ bgYellow: enabled ? formatter("\x1B[43m", "\x1B[49m") : String,
46
+ bgBlue: enabled ? formatter("\x1B[44m", "\x1B[49m") : String,
47
+ bgMagenta: enabled ? formatter("\x1B[45m", "\x1B[49m") : String,
48
+ bgCyan: enabled ? formatter("\x1B[46m", "\x1B[49m") : String,
49
+ bgWhite: enabled ? formatter("\x1B[47m", "\x1B[49m") : String
50
50
  });
51
51
  module2.exports = createColors();
52
52
  module2.exports.createColors = createColors;
@@ -4407,11 +4407,13 @@ var require_parser = __commonJS({
4407
4407
  if (brackets.length > 0)
4408
4408
  this.unclosedBracket(bracket);
4409
4409
  if (end && colon) {
4410
- while (tokens.length) {
4411
- token = tokens[tokens.length - 1][0];
4412
- if (token !== "space" && token !== "comment")
4413
- break;
4414
- this.tokenizer.back(tokens.pop());
4410
+ if (!customProperty) {
4411
+ while (tokens.length) {
4412
+ token = tokens[tokens.length - 1][0];
4413
+ if (token !== "space" && token !== "comment")
4414
+ break;
4415
+ this.tokenizer.back(tokens.pop());
4416
+ }
4415
4417
  }
4416
4418
  this.decl(tokens, customProperty);
4417
4419
  } else {
@@ -4467,7 +4469,14 @@ var require_parser = __commonJS({
4467
4469
  node.raws.before += node.prop[0];
4468
4470
  node.prop = node.prop.slice(1);
4469
4471
  }
4470
- let firstSpaces = this.spacesAndCommentsFromStart(tokens);
4472
+ let firstSpaces = [];
4473
+ let next;
4474
+ while (tokens.length) {
4475
+ next = tokens[0][0];
4476
+ if (next !== "space" && next !== "comment")
4477
+ break;
4478
+ firstSpaces.push(tokens.shift());
4479
+ }
4471
4480
  this.precheckMissedSemicolon(tokens);
4472
4481
  for (let i = tokens.length - 1; i >= 0; i--) {
4473
4482
  token = tokens[i];
@@ -4499,12 +4508,11 @@ var require_parser = __commonJS({
4499
4508
  }
4500
4509
  }
4501
4510
  let hasWord = tokens.some((i) => i[0] !== "space" && i[0] !== "comment");
4502
- this.raw(node, "value", tokens);
4503
4511
  if (hasWord) {
4504
- node.raws.between += firstSpaces;
4505
- } else {
4506
- node.value = firstSpaces + node.value;
4512
+ node.raws.between += firstSpaces.map((i) => i[1]).join("");
4513
+ firstSpaces = [];
4507
4514
  }
4515
+ this.raw(node, "value", firstSpaces.concat(tokens), customProperty);
4508
4516
  if (node.value.includes(":") && !customProperty) {
4509
4517
  this.checkMissedSemicolon(tokens);
4510
4518
  }
@@ -4635,28 +4643,25 @@ var require_parser = __commonJS({
4635
4643
  if (node.type !== "comment")
4636
4644
  this.semicolon = false;
4637
4645
  }
4638
- raw(node, prop, tokens) {
4646
+ raw(node, prop, tokens, customProperty) {
4639
4647
  let token, type;
4640
4648
  let length = tokens.length;
4641
4649
  let value = "";
4642
4650
  let clean = true;
4643
4651
  let next, prev;
4644
- let pattern = /^([#.|])?(\w)+/i;
4645
4652
  for (let i = 0; i < length; i += 1) {
4646
4653
  token = tokens[i];
4647
4654
  type = token[0];
4648
- if (type === "comment" && node.type === "rule") {
4655
+ if (type === "space" && i === length - 1 && !customProperty) {
4656
+ clean = false;
4657
+ } else if (type === "comment") {
4649
4658
  prev = tokens[i - 1];
4650
4659
  next = tokens[i + 1];
4651
- if (prev[0] !== "space" && next[0] !== "space" && pattern.test(prev[1]) && pattern.test(next[1])) {
4660
+ if (prev && next && prev[0] !== "space" && next[0] !== "space") {
4652
4661
  value += token[1];
4653
4662
  } else {
4654
4663
  clean = false;
4655
4664
  }
4656
- continue;
4657
- }
4658
- if (type === "comment" || type === "space" && i === length - 1) {
4659
- clean = false;
4660
4665
  } else {
4661
4666
  value += token[1];
4662
4667
  }
@@ -5356,8 +5361,12 @@ var require_no_work_result = __commonJS({
5356
5361
  } catch (error) {
5357
5362
  this.error = error;
5358
5363
  }
5359
- this._root = root;
5360
- return root;
5364
+ if (this.error) {
5365
+ throw this.error;
5366
+ } else {
5367
+ this._root = root;
5368
+ return root;
5369
+ }
5361
5370
  }
5362
5371
  get messages() {
5363
5372
  return [];
@@ -5408,7 +5417,7 @@ var require_processor = __commonJS({
5408
5417
  var Root = require_root();
5409
5418
  var Processor = class {
5410
5419
  constructor(plugins = []) {
5411
- this.version = "8.4.5";
5420
+ this.version = "8.4.6";
5412
5421
  this.plugins = this.normalize(plugins);
5413
5422
  }
5414
5423
  use(plugin) {
@@ -19734,7 +19743,7 @@ var require_parse_cst = __commonJS({
19734
19743
  str += "\b";
19735
19744
  break;
19736
19745
  case "e":
19737
- str += "";
19746
+ str += "\x1B";
19738
19747
  break;
19739
19748
  case "f":
19740
19749
  str += "\f";
@@ -70,7 +70,28 @@ export let variantPlugins = {
70
70
  'only-of-type',
71
71
 
72
72
  // State
73
- 'visited',
73
+ [
74
+ 'visited',
75
+ ({ container }) => {
76
+ let toRemove = ['--tw-text-opacity', '--tw-border-opacity', '--tw-bg-opacity']
77
+
78
+ container.walkDecls((decl) => {
79
+ if (toRemove.includes(decl.prop)) {
80
+ decl.remove()
81
+
82
+ return
83
+ }
84
+
85
+ for (const varName of toRemove) {
86
+ if (decl.value.includes(`/ var(${varName})`)) {
87
+ decl.value = decl.value.replace(`/ var(${varName})`, '')
88
+ }
89
+ }
90
+ })
91
+
92
+ return ':visited'
93
+ },
94
+ ],
74
95
  'target',
75
96
  ['open', '[open]'],
76
97
 
@@ -100,15 +121,27 @@ export let variantPlugins = {
100
121
  ].map((variant) => (Array.isArray(variant) ? variant : [variant, `:${variant}`]))
101
122
 
102
123
  for (let [variantName, state] of pseudoVariants) {
103
- addVariant(variantName, `&${state}`)
124
+ addVariant(variantName, (ctx) => {
125
+ let result = typeof state === 'function' ? state(ctx) : state
126
+
127
+ return `&${result}`
128
+ })
104
129
  }
105
130
 
106
131
  for (let [variantName, state] of pseudoVariants) {
107
- addVariant(`group-${variantName}`, `:merge(.group)${state} &`)
132
+ addVariant(`group-${variantName}`, (ctx) => {
133
+ let result = typeof state === 'function' ? state(ctx) : state
134
+
135
+ return `:merge(.group)${result} &`
136
+ })
108
137
  }
109
138
 
110
139
  for (let [variantName, state] of pseudoVariants) {
111
- addVariant(`peer-${variantName}`, `:merge(.peer)${state} ~ &`)
140
+ addVariant(`peer-${variantName}`, (ctx) => {
141
+ let result = typeof state === 'function' ? state(ctx) : state
142
+
143
+ return `:merge(.peer)${result} ~ &`
144
+ })
112
145
  }
113
146
  },
114
147
 
@@ -8,6 +8,8 @@ const PATTERNS = [
8
8
  /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
9
9
  /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')]
10
10
  /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
11
+ /([^<>"'`\s]*\[[^<>"'`\s]*\('[^"`\s]*'\)+\])/.source, // h-[calc(100%-theme('spacing.1'))]
12
+ /([^<>"'`\s]*\[[^<>"'`\s]*\("[^'`\s]*"\)+\])/.source, // h-[calc(100%-theme("spacing.1"))]
11
13
  /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
12
14
  /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
13
15
  /([^<>"'`\s]*\[[^<>"'`\s]*:[^\]\s]*\])/.source, // `[attr:value]`
@@ -161,12 +161,12 @@ function processApply(root, context) {
161
161
  }
162
162
 
163
163
  for (let applyCandidate of applyCandidates) {
164
- if (!applyClassCache.has(applyCandidate)) {
165
- if (applyCandidate === prefix(context, 'group')) {
166
- // TODO: Link to specific documentation page with error code.
167
- throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`)
168
- }
164
+ if ([prefix(context, 'group'), prefix(context, 'peer')].includes(applyCandidate)) {
165
+ // TODO: Link to specific documentation page with error code.
166
+ throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`)
167
+ }
169
168
 
169
+ if (!applyClassCache.has(applyCandidate)) {
170
170
  throw apply.error(
171
171
  `The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`
172
172
  )
@@ -63,9 +63,23 @@ function applyPrefix(matches, context) {
63
63
  let [meta] = match
64
64
  if (meta.options.respectPrefix) {
65
65
  let container = postcss.root({ nodes: [match[1].clone()] })
66
+ let classCandidate = match[1].raws.tailwind.classCandidate
67
+
66
68
  container.walkRules((r) => {
67
- r.selector = prefixSelector(context.tailwindConfig.prefix, r.selector)
69
+ // If this is a negative utility with a dash *before* the prefix we
70
+ // have to ensure that the generated selector matches the candidate
71
+
72
+ // Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
73
+ // The disconnect between candidate <-> class can cause @apply to hard crash.
74
+ let shouldPrependNegative = classCandidate.startsWith('-')
75
+
76
+ r.selector = prefixSelector(
77
+ context.tailwindConfig.prefix,
78
+ r.selector,
79
+ shouldPrependNegative
80
+ )
68
81
  })
82
+
69
83
  match[1] = container.nodes[0]
70
84
  }
71
85
  }
@@ -220,7 +234,7 @@ function applyVariant(variant, matches, context) {
220
234
  // For example:
221
235
  // .sm:underline {} is a variant of something in the utilities layer
222
236
  // .sm:container {} is a variant of the container component
223
- clone.nodes[0].raws.tailwind = { parentLayer: meta.layer }
237
+ clone.nodes[0].raws.tailwind = { ...clone.nodes[0].raws.tailwind, parentLayer: meta.layer }
224
238
 
225
239
  let withOffset = [
226
240
  {
@@ -262,11 +276,37 @@ function parseRules(rule, cache, options = {}) {
262
276
  const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
263
277
 
264
278
  function isValidPropName(name) {
265
- // TODO: properly fix this!
266
- return IS_VALID_PROPERTY_NAME.test(name) && !name.startsWith('http')
279
+ return IS_VALID_PROPERTY_NAME.test(name)
280
+ }
281
+
282
+ /**
283
+ * @param {string} declaration
284
+ * @returns {boolean}
285
+ */
286
+ function looksLikeUri(declaration) {
287
+ // Quick bailout for obvious non-urls
288
+ // This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
289
+ if (!declaration.includes('://')) {
290
+ return false
291
+ }
292
+
293
+ try {
294
+ const url = new URL(declaration)
295
+ return url.scheme !== '' && url.host !== ''
296
+ } catch (err) {
297
+ // Definitely not a valid url
298
+ return false
299
+ }
267
300
  }
268
301
 
269
302
  function isParsableCssValue(property, value) {
303
+ // We don't want to to treat [https://example.com] as a custom property
304
+ // Even though, according to the CSS grammar, it's a totally valid CSS declaration
305
+ // So we short-circuit here by checking if the custom property looks like a url
306
+ if (looksLikeUri(`${property}:${value}`)) {
307
+ return false
308
+ }
309
+
270
310
  try {
271
311
  postcss.parse(`a{${property}:${value}}`).toResult()
272
312
  return true
@@ -345,6 +385,14 @@ function splitWithSeparator(input, separator) {
345
385
  return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'))
346
386
  }
347
387
 
388
+ function* recordCandidates(matches, classCandidate) {
389
+ for (const match of matches) {
390
+ match[1].raws.tailwind = { ...match[1].raws.tailwind, classCandidate }
391
+
392
+ yield match
393
+ }
394
+ }
395
+
348
396
  function* resolveMatches(candidate, context) {
349
397
  let separator = context.tailwindConfig.separator
350
398
  let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
@@ -456,7 +504,9 @@ function* resolveMatches(candidate, context) {
456
504
  continue
457
505
  }
458
506
 
459
- matches = applyPrefix(matches.flat(), context)
507
+ matches = matches.flat()
508
+ matches = Array.from(recordCandidates(matches, classCandidate))
509
+ matches = applyPrefix(matches, context)
460
510
 
461
511
  if (important) {
462
512
  matches = applyImportant(matches, context)
@@ -467,6 +517,8 @@ function* resolveMatches(candidate, context) {
467
517
  }
468
518
 
469
519
  for (let match of matches) {
520
+ match[1].raws.tailwind = { ...match[1].raws.tailwind, candidate }
521
+
470
522
  // Apply final format selector
471
523
  if (match[0].collectedFormats) {
472
524
  let finalFormat = formatVariantSelector('&', ...match[0].collectedFormats)
@@ -19,6 +19,12 @@ import { toPath } from '../util/toPath'
19
19
  import log from '../util/log'
20
20
  import negateValue from '../util/negateValue'
21
21
  import isValidArbitraryValue from '../util/isValidArbitraryValue'
22
+ import { generateRules } from './generateRules'
23
+
24
+ function prefix(context, selector) {
25
+ let prefix = context.tailwindConfig.prefix
26
+ return typeof prefix === 'function' ? prefix(selector) : prefix + selector
27
+ }
22
28
 
23
29
  function parseVariantFormatString(input) {
24
30
  if (input.includes('{')) {
@@ -666,17 +672,30 @@ function registerPlugins(plugins, context) {
666
672
 
667
673
  if (checks.length > 0) {
668
674
  let patternMatchingCount = new Map()
675
+ let prefixLength = context.tailwindConfig.prefix.length
669
676
 
670
677
  for (let util of classList) {
671
678
  let utils = Array.isArray(util)
672
679
  ? (() => {
673
680
  let [utilName, options] = util
674
- let classes = Object.keys(options?.values ?? {}).map((value) =>
675
- formatClass(utilName, value)
676
- )
681
+ let values = Object.keys(options?.values ?? {})
682
+ let classes = values.map((value) => formatClass(utilName, value))
677
683
 
678
684
  if (options?.supportsNegativeValues) {
685
+ // This is the normal negated version
686
+ // e.g. `-inset-1` or `-tw-inset-1`
679
687
  classes = [...classes, ...classes.map((cls) => '-' + cls)]
688
+
689
+ // This is the negated version *after* the prefix
690
+ // e.g. `tw--inset-1`
691
+ // The prefix is already attached to util name
692
+ // So we add the negative after the prefix
693
+ classes = [
694
+ ...classes,
695
+ ...classes.map(
696
+ (cls) => cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength)
697
+ ),
698
+ ]
680
699
  }
681
700
 
682
701
  return classes
@@ -720,9 +739,43 @@ function registerPlugins(plugins, context) {
720
739
  }
721
740
  }
722
741
 
742
+ // A list of utilities that are used by certain Tailwind CSS utilities but
743
+ // that don't exist on their own. This will result in them "not existing" and
744
+ // sorting could be weird since you still require them in order to make the
745
+ // host utitlies work properly. (Thanks Biology)
746
+ let parasiteUtilities = new Set([prefix(context, 'group'), prefix(context, 'peer')])
747
+ context.sortClassList = function sortClassList(classes) {
748
+ let sortedClassNames = new Map()
749
+ for (let [sort, rule] of generateRules(new Set(classes), context)) {
750
+ if (sortedClassNames.has(rule.raws.tailwind.candidate)) continue
751
+ sortedClassNames.set(rule.raws.tailwind.candidate, sort)
752
+ }
753
+
754
+ return classes
755
+ .map((className) => {
756
+ let order = sortedClassNames.get(className) ?? null
757
+
758
+ if (order === null && parasiteUtilities.has(className)) {
759
+ // This will make sure that it is at the very beginning of the
760
+ // `components` layer which technically means 'before any
761
+ // components'.
762
+ order = context.layerOrder.components
763
+ }
764
+
765
+ return [className, order]
766
+ })
767
+ .sort(([, a], [, z]) => {
768
+ if (a === z) return 0
769
+ if (a === null) return -1
770
+ if (z === null) return 1
771
+ return bigSign(a - z)
772
+ })
773
+ .map(([className]) => className)
774
+ }
775
+
723
776
  // Generate a list of strings for autocompletion purposes, e.g.
724
777
  // ['uppercase', 'lowercase', ...]
725
- context.getClassList = function () {
778
+ context.getClassList = function getClassList() {
726
779
  let output = []
727
780
 
728
781
  for (let util of classList) {
@@ -1,12 +1,14 @@
1
1
  import parser from 'postcss-selector-parser'
2
- import { tap } from './tap'
3
2
 
4
- export default function (prefix, selector) {
3
+ export default function (prefix, selector, prependNegative = false) {
5
4
  return parser((selectors) => {
6
5
  selectors.walkClasses((classSelector) => {
7
- tap(classSelector.value, (baseClass) => {
8
- classSelector.value = `${prefix}${baseClass}`
9
- })
6
+ let baseClass = classSelector.value
7
+ let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-')
8
+
9
+ classSelector.value = shouldPlaceNegativeBeforePrefix
10
+ ? `-${prefix}${baseClass.slice(1)}`
11
+ : `${prefix}${baseClass}`
10
12
  })
11
13
  }).processSync(selector)
12
14
  }