tailwind-merge 2.3.0 → 2.4.0-dev.0a332483114bb4ab4ec002262968ced86200ae23

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <div align="center">
4
4
  <br />
5
5
  <a href="https://github.com/dcastil/tailwind-merge">
6
- <img src="https://github.com/dcastil/tailwind-merge/raw/v2.3.0/assets/logo.svg" alt="tailwind-merge" height="150px" />
6
+ <img src="https://github.com/dcastil/tailwind-merge/raw/0a332483114bb4ab4ec002262968ced86200ae23/assets/logo.svg" alt="tailwind-merge" height="150px" />
7
7
  </a>
8
8
  </div>
9
9
 
@@ -25,14 +25,14 @@ twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
25
25
 
26
26
  ## Get started
27
27
 
28
- - [What is it for](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/what-is-it-for.md)
29
- - [When and how to use it](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/when-and-how-to-use-it.md)
30
- - [Features](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/features.md)
31
- - [Limitations](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/limitations.md)
32
- - [Configuration](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/configuration.md)
33
- - [Recipes](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/recipes.md)
34
- - [API reference](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/api-reference.md)
35
- - [Writing plugins](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/writing-plugins.md)
36
- - [Versioning](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/versioning.md)
37
- - [Contributing](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/contributing.md)
38
- - [Similar packages](https://github.com/dcastil/tailwind-merge/tree/v2.3.0/docs/similar-packages.md)
28
+ - [What is it for](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/what-is-it-for.md)
29
+ - [When and how to use it](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/when-and-how-to-use-it.md)
30
+ - [Features](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/features.md)
31
+ - [Limitations](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/limitations.md)
32
+ - [Configuration](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/configuration.md)
33
+ - [Recipes](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/recipes.md)
34
+ - [API reference](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/api-reference.md)
35
+ - [Writing plugins](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/writing-plugins.md)
36
+ - [Versioning](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/versioning.md)
37
+ - [Contributing](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/contributing.md)
38
+ - [Similar packages](https://github.com/dcastil/tailwind-merge/tree/0a332483114bb4ab4ec002262968ced86200ae23/docs/similar-packages.md)
@@ -4,33 +4,33 @@ Object.defineProperty(exports, Symbol.toStringTag, {
4
4
  value: 'Module'
5
5
  });
6
6
  const CLASS_PART_SEPARATOR = '-';
7
- function createClassUtils(config) {
7
+ const createClassGroupUtils = config => {
8
8
  const classMap = createClassMap(config);
9
9
  const {
10
10
  conflictingClassGroups,
11
11
  conflictingClassGroupModifiers
12
12
  } = config;
13
- function getClassGroupId(className) {
13
+ const getClassGroupId = className => {
14
14
  const classParts = className.split(CLASS_PART_SEPARATOR);
15
15
  // Classes like `-inset-1` produce an empty string as first classPart. We assume that classes for negative values are used correctly and remove it from classParts.
16
16
  if (classParts[0] === '' && classParts.length !== 1) {
17
17
  classParts.shift();
18
18
  }
19
19
  return getGroupRecursive(classParts, classMap) || getGroupIdForArbitraryProperty(className);
20
- }
21
- function getConflictingClassGroupIds(classGroupId, hasPostfixModifier) {
20
+ };
21
+ const getConflictingClassGroupIds = (classGroupId, hasPostfixModifier) => {
22
22
  const conflicts = conflictingClassGroups[classGroupId] || [];
23
23
  if (hasPostfixModifier && conflictingClassGroupModifiers[classGroupId]) {
24
24
  return [...conflicts, ...conflictingClassGroupModifiers[classGroupId]];
25
25
  }
26
26
  return conflicts;
27
- }
27
+ };
28
28
  return {
29
29
  getClassGroupId,
30
30
  getConflictingClassGroupIds
31
31
  };
32
- }
33
- function getGroupRecursive(classParts, classPartObject) {
32
+ };
33
+ const getGroupRecursive = (classParts, classPartObject) => {
34
34
  if (classParts.length === 0) {
35
35
  return classPartObject.classGroupId;
36
36
  }
@@ -47,9 +47,9 @@ function getGroupRecursive(classParts, classPartObject) {
47
47
  return classPartObject.validators.find(({
48
48
  validator
49
49
  }) => validator(classRest))?.classGroupId;
50
- }
50
+ };
51
51
  const arbitraryPropertyRegex = /^\[(.+)\]$/;
52
- function getGroupIdForArbitraryProperty(className) {
52
+ const getGroupIdForArbitraryProperty = className => {
53
53
  if (arbitraryPropertyRegex.test(className)) {
54
54
  const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)[1];
55
55
  const property = arbitraryPropertyClassName?.substring(0, arbitraryPropertyClassName.indexOf(':'));
@@ -58,11 +58,11 @@ function getGroupIdForArbitraryProperty(className) {
58
58
  return 'arbitrary..' + property;
59
59
  }
60
60
  }
61
- }
61
+ };
62
62
  /**
63
63
  * Exported for testing only
64
64
  */
65
- function createClassMap(config) {
65
+ const createClassMap = config => {
66
66
  const {
67
67
  theme,
68
68
  prefix
@@ -76,8 +76,8 @@ function createClassMap(config) {
76
76
  processClassesRecursively(classGroup, classMap, classGroupId, theme);
77
77
  });
78
78
  return classMap;
79
- }
80
- function processClassesRecursively(classGroup, classPartObject, classGroupId, theme) {
79
+ };
80
+ const processClassesRecursively = (classGroup, classPartObject, classGroupId, theme) => {
81
81
  classGroup.forEach(classDefinition => {
82
82
  if (typeof classDefinition === 'string') {
83
83
  const classPartObjectToEdit = classDefinition === '' ? classPartObject : getPart(classPartObject, classDefinition);
@@ -99,8 +99,8 @@ function processClassesRecursively(classGroup, classPartObject, classGroupId, th
99
99
  processClassesRecursively(classGroup, getPart(classPartObject, key), classGroupId, theme);
100
100
  });
101
101
  });
102
- }
103
- function getPart(classPartObject, path) {
102
+ };
103
+ const getPart = (classPartObject, path) => {
104
104
  let currentClassPartObject = classPartObject;
105
105
  path.split(CLASS_PART_SEPARATOR).forEach(pathPart => {
106
106
  if (!currentClassPartObject.nextPart.has(pathPart)) {
@@ -112,11 +112,9 @@ function getPart(classPartObject, path) {
112
112
  currentClassPartObject = currentClassPartObject.nextPart.get(pathPart);
113
113
  });
114
114
  return currentClassPartObject;
115
- }
116
- function isThemeGetter(func) {
117
- return func.isThemeGetter;
118
- }
119
- function getPrefixedClassGroupEntries(classGroupEntries, prefix) {
115
+ };
116
+ const isThemeGetter = func => func.isThemeGetter;
117
+ const getPrefixedClassGroupEntries = (classGroupEntries, prefix) => {
120
118
  if (!prefix) {
121
119
  return classGroupEntries;
122
120
  }
@@ -132,10 +130,10 @@ function getPrefixedClassGroupEntries(classGroupEntries, prefix) {
132
130
  });
133
131
  return [classGroupId, prefixedClassGroup];
134
132
  });
135
- }
133
+ };
136
134
 
137
135
  // LRU cache inspired from hashlru (https://github.com/dominictarr/hashlru/blob/v1.0.4/index.js) but object replaced with Map to improve performance
138
- function createLruCache(maxCacheSize) {
136
+ const createLruCache = maxCacheSize => {
139
137
  if (maxCacheSize < 1) {
140
138
  return {
141
139
  get: () => undefined,
@@ -145,7 +143,7 @@ function createLruCache(maxCacheSize) {
145
143
  let cacheSize = 0;
146
144
  let cache = new Map();
147
145
  let previousCache = new Map();
148
- function update(key, value) {
146
+ const update = (key, value) => {
149
147
  cache.set(key, value);
150
148
  cacheSize++;
151
149
  if (cacheSize > maxCacheSize) {
@@ -153,7 +151,7 @@ function createLruCache(maxCacheSize) {
153
151
  previousCache = cache;
154
152
  cache = new Map();
155
153
  }
156
- }
154
+ };
157
155
  return {
158
156
  get(key) {
159
157
  let value = cache.get(key);
@@ -173,15 +171,18 @@ function createLruCache(maxCacheSize) {
173
171
  }
174
172
  }
175
173
  };
176
- }
174
+ };
177
175
  const IMPORTANT_MODIFIER = '!';
178
- function createSplitModifiers(config) {
179
- const separator = config.separator;
176
+ const createParseClassName = config => {
177
+ const {
178
+ separator,
179
+ experimentalParseClassName
180
+ } = config;
180
181
  const isSeparatorSingleCharacter = separator.length === 1;
181
182
  const firstSeparatorCharacter = separator[0];
182
183
  const separatorLength = separator.length;
183
- // splitModifiers inspired by https://github.com/tailwindlabs/tailwindcss/blob/v3.2.2/src/util/splitAtTopLevelOnly.js
184
- return function splitModifiers(className) {
184
+ // parseClassName inspired by https://github.com/tailwindlabs/tailwindcss/blob/v3.2.2/src/util/splitAtTopLevelOnly.js
185
+ const parseClassName = className => {
185
186
  const modifiers = [];
186
187
  let bracketDepth = 0;
187
188
  let modifierStart = 0;
@@ -216,13 +217,20 @@ function createSplitModifiers(config) {
216
217
  maybePostfixModifierPosition
217
218
  };
218
219
  };
219
- }
220
+ if (experimentalParseClassName) {
221
+ return className => experimentalParseClassName({
222
+ className,
223
+ parseClassName
224
+ });
225
+ }
226
+ return parseClassName;
227
+ };
220
228
  /**
221
229
  * Sorts modifiers according to following schema:
222
230
  * - Predefined modifiers are sorted alphabetically
223
231
  * - When an arbitrary variant appears, it must be preserved which modifiers are before and after it
224
232
  */
225
- function sortModifiers(modifiers) {
233
+ const sortModifiers = modifiers => {
226
234
  if (modifiers.length <= 1) {
227
235
  return modifiers;
228
236
  }
@@ -239,18 +247,15 @@ function sortModifiers(modifiers) {
239
247
  });
240
248
  sortedModifiers.push(...unsortedModifiers.sort());
241
249
  return sortedModifiers;
242
- }
243
- function createConfigUtils(config) {
244
- return {
245
- cache: createLruCache(config.cacheSize),
246
- splitModifiers: createSplitModifiers(config),
247
- ...createClassUtils(config)
248
- };
249
- }
250
- const SPLIT_CLASSES_REGEX = /\s+/;
251
- function mergeClassList(classList, configUtils) {
250
+ };
251
+ const createConfigUtils = config => ({
252
+ cache: createLruCache(config.cacheSize),
253
+ parseClassName: createParseClassName(config),
254
+ ...createClassGroupUtils(config)
255
+ });
256
+ const mergeClassList = (classList, configUtils) => {
252
257
  const {
253
- splitModifiers,
258
+ parseClassName,
254
259
  getClassGroupId,
255
260
  getConflictingClassGroupIds
256
261
  } = configUtils;
@@ -261,61 +266,51 @@ function mergeClassList(classList, configUtils) {
261
266
  * @example 'hover:focus:bg-color'
262
267
  * @example 'md:!pr'
263
268
  */
264
- const classGroupsInConflict = new Set();
265
- return classList.trim().split(SPLIT_CLASSES_REGEX).map(originalClassName => {
269
+ const classGroupsInConflict = [];
270
+ let result = '';
271
+ for (let i = classList.length - 1; i >= 0;) {
272
+ while (classList[i] === ' ') {
273
+ --i;
274
+ }
275
+ const nextI = classList.lastIndexOf(' ', i);
276
+ const originalClassName = classList.slice(nextI === -1 ? 0 : nextI + 1, i + 1);
277
+ i = nextI;
266
278
  const {
267
279
  modifiers,
268
280
  hasImportantModifier,
269
281
  baseClassName,
270
282
  maybePostfixModifierPosition
271
- } = splitModifiers(originalClassName);
272
- let classGroupId = getClassGroupId(maybePostfixModifierPosition ? baseClassName.substring(0, maybePostfixModifierPosition) : baseClassName);
283
+ } = parseClassName(originalClassName);
273
284
  let hasPostfixModifier = Boolean(maybePostfixModifierPosition);
285
+ let classGroupId = getClassGroupId(hasPostfixModifier ? baseClassName.substring(0, maybePostfixModifierPosition) : baseClassName);
274
286
  if (!classGroupId) {
275
- if (!maybePostfixModifierPosition) {
276
- return {
277
- isTailwindClass: false,
278
- originalClassName
279
- };
287
+ if (!hasPostfixModifier) {
288
+ result = originalClassName + (result.length > 0 ? ' ' + result : result);
289
+ continue;
280
290
  }
281
291
  classGroupId = getClassGroupId(baseClassName);
282
292
  if (!classGroupId) {
283
- return {
284
- isTailwindClass: false,
285
- originalClassName
286
- };
293
+ result = originalClassName + (result.length > 0 ? ' ' + result : result);
294
+ continue;
287
295
  }
288
296
  hasPostfixModifier = false;
289
297
  }
290
298
  const variantModifier = sortModifiers(modifiers).join(':');
291
299
  const modifierId = hasImportantModifier ? variantModifier + IMPORTANT_MODIFIER : variantModifier;
292
- return {
293
- isTailwindClass: true,
294
- modifierId,
295
- classGroupId,
296
- originalClassName,
297
- hasPostfixModifier
298
- };
299
- }).reverse()
300
- // Last class in conflict wins, so we need to filter conflicting classes in reverse order.
301
- .filter(parsed => {
302
- if (!parsed.isTailwindClass) {
303
- return true;
304
- }
305
- const {
306
- modifierId,
307
- classGroupId,
308
- hasPostfixModifier
309
- } = parsed;
310
300
  const classId = modifierId + classGroupId;
311
- if (classGroupsInConflict.has(classId)) {
312
- return false;
301
+ if (classGroupsInConflict.includes(classId)) {
302
+ continue;
313
303
  }
314
- classGroupsInConflict.add(classId);
315
- getConflictingClassGroupIds(classGroupId, hasPostfixModifier).forEach(group => classGroupsInConflict.add(modifierId + group));
316
- return true;
317
- }).reverse().map(parsed => parsed.originalClassName).join(' ');
318
- }
304
+ classGroupsInConflict.push(classId);
305
+ const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier);
306
+ for (let i = 0; i < conflictGroups.length; ++i) {
307
+ const group = conflictGroups[i];
308
+ classGroupsInConflict.push(modifierId + group);
309
+ }
310
+ result = originalClassName + (result.length > 0 ? ' ' + result : result);
311
+ }
312
+ return result;
313
+ };
319
314
 
320
315
  /**
321
316
  * The code in this file is copied from https://github.com/lukeed/clsx and modified to suit the needs of tailwind-merge better.
@@ -341,7 +336,7 @@ function twJoin() {
341
336
  }
342
337
  return string;
343
338
  }
344
- function toValue(mix) {
339
+ const toValue = mix => {
345
340
  if (typeof mix === 'string') {
346
341
  return mix;
347
342
  }
@@ -356,7 +351,7 @@ function toValue(mix) {
356
351
  }
357
352
  }
358
353
  return string;
359
- }
354
+ };
360
355
  function createTailwindMerge(createConfigFirst, ...createConfigRest) {
361
356
  let configUtils;
362
357
  let cacheGet;
@@ -383,11 +378,11 @@ function createTailwindMerge(createConfigFirst, ...createConfigRest) {
383
378
  return functionToCall(twJoin.apply(null, arguments));
384
379
  };
385
380
  }
386
- function fromTheme(key) {
381
+ const fromTheme = key => {
387
382
  const themeGetter = theme => theme[key] || [];
388
383
  themeGetter.isThemeGetter = true;
389
384
  return themeGetter;
390
- }
385
+ };
391
386
  const arbitraryValueRegex = /^\[(?:([a-z-]+):)?(.+)\]$/i;
392
387
  const fractionRegex = /^\d+\/\d+$/;
393
388
  const stringLengths = /*#__PURE__*/new Set(['px', 'full', 'screen']);
@@ -397,48 +392,22 @@ const colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch))\(.+\)$/;
397
392
  // Shadow always begins with x and y offset separated by underscore optionally prepended by inset
398
393
  const shadowRegex = /^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;
399
394
  const imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/;
400
- function isLength(value) {
401
- return isNumber(value) || stringLengths.has(value) || fractionRegex.test(value);
402
- }
403
- function isArbitraryLength(value) {
404
- return getIsArbitraryValue(value, 'length', isLengthOnly);
405
- }
406
- function isNumber(value) {
407
- return Boolean(value) && !Number.isNaN(Number(value));
408
- }
409
- function isArbitraryNumber(value) {
410
- return getIsArbitraryValue(value, 'number', isNumber);
411
- }
412
- function isInteger(value) {
413
- return Boolean(value) && Number.isInteger(Number(value));
414
- }
415
- function isPercent(value) {
416
- return value.endsWith('%') && isNumber(value.slice(0, -1));
417
- }
418
- function isArbitraryValue(value) {
419
- return arbitraryValueRegex.test(value);
420
- }
421
- function isTshirtSize(value) {
422
- return tshirtUnitRegex.test(value);
423
- }
395
+ const isLength = value => isNumber(value) || stringLengths.has(value) || fractionRegex.test(value);
396
+ const isArbitraryLength = value => getIsArbitraryValue(value, 'length', isLengthOnly);
397
+ const isNumber = value => Boolean(value) && !Number.isNaN(Number(value));
398
+ const isArbitraryNumber = value => getIsArbitraryValue(value, 'number', isNumber);
399
+ const isInteger = value => Boolean(value) && Number.isInteger(Number(value));
400
+ const isPercent = value => value.endsWith('%') && isNumber(value.slice(0, -1));
401
+ const isArbitraryValue = value => arbitraryValueRegex.test(value);
402
+ const isTshirtSize = value => tshirtUnitRegex.test(value);
424
403
  const sizeLabels = /*#__PURE__*/new Set(['length', 'size', 'percentage']);
425
- function isArbitrarySize(value) {
426
- return getIsArbitraryValue(value, sizeLabels, isNever);
427
- }
428
- function isArbitraryPosition(value) {
429
- return getIsArbitraryValue(value, 'position', isNever);
430
- }
404
+ const isArbitrarySize = value => getIsArbitraryValue(value, sizeLabels, isNever);
405
+ const isArbitraryPosition = value => getIsArbitraryValue(value, 'position', isNever);
431
406
  const imageLabels = /*#__PURE__*/new Set(['image', 'url']);
432
- function isArbitraryImage(value) {
433
- return getIsArbitraryValue(value, imageLabels, isImage);
434
- }
435
- function isArbitraryShadow(value) {
436
- return getIsArbitraryValue(value, '', isShadow);
437
- }
438
- function isAny() {
439
- return true;
440
- }
441
- function getIsArbitraryValue(value, label, testValue) {
407
+ const isArbitraryImage = value => getIsArbitraryValue(value, imageLabels, isImage);
408
+ const isArbitraryShadow = value => getIsArbitraryValue(value, '', isShadow);
409
+ const isAny = () => true;
410
+ const getIsArbitraryValue = (value, label, testValue) => {
442
411
  const result = arbitraryValueRegex.exec(value);
443
412
  if (result) {
444
413
  if (result[1]) {
@@ -447,22 +416,15 @@ function getIsArbitraryValue(value, label, testValue) {
447
416
  return testValue(result[2]);
448
417
  }
449
418
  return false;
450
- }
451
- function isLengthOnly(value) {
452
- // `colorFunctionRegex` check is necessary because color functions can have percentages in them which which would be incorrectly classified as lengths.
453
- // For example, `hsl(0 0% 0%)` would be classified as a length without this check.
454
- // I could also use lookbehind assertion in `lengthUnitRegex` but that isn't supported widely enough.
455
- return lengthUnitRegex.test(value) && !colorFunctionRegex.test(value);
456
- }
457
- function isNever() {
458
- return false;
459
- }
460
- function isShadow(value) {
461
- return shadowRegex.test(value);
462
- }
463
- function isImage(value) {
464
- return imageRegex.test(value);
465
- }
419
+ };
420
+ const isLengthOnly = value =>
421
+ // `colorFunctionRegex` check is necessary because color functions can have percentages in them which which would be incorrectly classified as lengths.
422
+ // For example, `hsl(0 0% 0%)` would be classified as a length without this check.
423
+ // I could also use lookbehind assertion in `lengthUnitRegex` but that isn't supported widely enough.
424
+ lengthUnitRegex.test(value) && !colorFunctionRegex.test(value);
425
+ const isNever = () => false;
426
+ const isShadow = value => shadowRegex.test(value);
427
+ const isImage = value => imageRegex.test(value);
466
428
  const validators = /*#__PURE__*/Object.defineProperty({
467
429
  __proto__: null,
468
430
  isAny,
@@ -481,7 +443,7 @@ const validators = /*#__PURE__*/Object.defineProperty({
481
443
  }, Symbol.toStringTag, {
482
444
  value: 'Module'
483
445
  });
484
- function getDefaultConfig() {
446
+ const getDefaultConfig = () => {
485
447
  const colors = fromTheme('colors');
486
448
  const spacing = fromTheme('spacing');
487
449
  const blur = fromTheme('blur');
@@ -519,7 +481,6 @@ function getDefaultConfig() {
519
481
  const getAlign = () => ['start', 'end', 'center', 'between', 'around', 'evenly', 'stretch'];
520
482
  const getZeroAndEmpty = () => ['', '0', isArbitraryValue];
521
483
  const getBreaks = () => ['auto', 'avoid', 'all', 'avoid-page', 'page', 'left', 'right', 'column'];
522
- const getNumber = () => [isNumber, isArbitraryNumber];
523
484
  const getNumberAndArbitrary = () => [isNumber, isArbitraryValue];
524
485
  return {
525
486
  cacheSize: 500,
@@ -528,12 +489,12 @@ function getDefaultConfig() {
528
489
  colors: [isAny],
529
490
  spacing: [isLength, isArbitraryLength],
530
491
  blur: ['none', '', isTshirtSize, isArbitraryValue],
531
- brightness: getNumber(),
492
+ brightness: getNumberAndArbitrary(),
532
493
  borderColor: [colors],
533
494
  borderRadius: ['none', '', 'full', isTshirtSize, isArbitraryValue],
534
495
  borderSpacing: getSpacingWithArbitrary(),
535
496
  borderWidth: getLengthWithEmptyAndArbitrary(),
536
- contrast: getNumber(),
497
+ contrast: getNumberAndArbitrary(),
537
498
  grayscale: getZeroAndEmpty(),
538
499
  hueRotate: getNumberAndArbitrary(),
539
500
  invert: getZeroAndEmpty(),
@@ -542,10 +503,10 @@ function getDefaultConfig() {
542
503
  gradientColorStopPositions: [isPercent, isArbitraryLength],
543
504
  inset: getSpacingWithAutoAndArbitrary(),
544
505
  margin: getSpacingWithAutoAndArbitrary(),
545
- opacity: getNumber(),
506
+ opacity: getNumberAndArbitrary(),
546
507
  padding: getSpacingWithArbitrary(),
547
- saturate: getNumber(),
548
- scale: getNumber(),
508
+ saturate: getNumberAndArbitrary(),
509
+ scale: getNumberAndArbitrary(),
549
510
  sepia: getZeroAndEmpty(),
550
511
  skew: getNumberAndArbitrary(),
551
512
  space: getSpacingWithArbitrary(),
@@ -2534,22 +2495,24 @@ function getDefaultConfig() {
2534
2495
  'font-size': ['leading']
2535
2496
  }
2536
2497
  };
2537
- }
2498
+ };
2538
2499
 
2539
2500
  /**
2540
2501
  * @param baseConfig Config where other config will be merged into. This object will be mutated.
2541
2502
  * @param configExtension Partial config to merge into the `baseConfig`.
2542
2503
  */
2543
- function mergeConfigs(baseConfig, {
2504
+ const mergeConfigs = (baseConfig, {
2544
2505
  cacheSize,
2545
2506
  prefix,
2546
2507
  separator,
2508
+ experimentalParseClassName,
2547
2509
  extend = {},
2548
2510
  override = {}
2549
- }) {
2511
+ }) => {
2550
2512
  overrideProperty(baseConfig, 'cacheSize', cacheSize);
2551
2513
  overrideProperty(baseConfig, 'prefix', prefix);
2552
2514
  overrideProperty(baseConfig, 'separator', separator);
2515
+ overrideProperty(baseConfig, 'experimentalParseClassName', experimentalParseClassName);
2553
2516
  for (const configKey in override) {
2554
2517
  overrideConfigProperties(baseConfig[configKey], override[configKey]);
2555
2518
  }
@@ -2557,20 +2520,20 @@ function mergeConfigs(baseConfig, {
2557
2520
  mergeConfigProperties(baseConfig[key], extend[key]);
2558
2521
  }
2559
2522
  return baseConfig;
2560
- }
2561
- function overrideProperty(baseObject, overrideKey, overrideValue) {
2523
+ };
2524
+ const overrideProperty = (baseObject, overrideKey, overrideValue) => {
2562
2525
  if (overrideValue !== undefined) {
2563
2526
  baseObject[overrideKey] = overrideValue;
2564
2527
  }
2565
- }
2566
- function overrideConfigProperties(baseObject, overrideObject) {
2528
+ };
2529
+ const overrideConfigProperties = (baseObject, overrideObject) => {
2567
2530
  if (overrideObject) {
2568
2531
  for (const key in overrideObject) {
2569
2532
  overrideProperty(baseObject, key, overrideObject[key]);
2570
2533
  }
2571
2534
  }
2572
- }
2573
- function mergeConfigProperties(baseObject, mergeObject) {
2535
+ };
2536
+ const mergeConfigProperties = (baseObject, mergeObject) => {
2574
2537
  if (mergeObject) {
2575
2538
  for (const key in mergeObject) {
2576
2539
  const mergeValue = mergeObject[key];
@@ -2579,10 +2542,8 @@ function mergeConfigProperties(baseObject, mergeObject) {
2579
2542
  }
2580
2543
  }
2581
2544
  }
2582
- }
2583
- function extendTailwindMerge(configExtension, ...createConfig) {
2584
- return typeof configExtension === 'function' ? createTailwindMerge(getDefaultConfig, configExtension, ...createConfig) : createTailwindMerge(() => mergeConfigs(getDefaultConfig(), configExtension), ...createConfig);
2585
- }
2545
+ };
2546
+ const extendTailwindMerge = (configExtension, ...createConfig) => typeof configExtension === 'function' ? createTailwindMerge(getDefaultConfig, configExtension, ...createConfig) : createTailwindMerge(() => mergeConfigs(getDefaultConfig(), configExtension), ...createConfig);
2586
2547
  const twMerge = /*#__PURE__*/createTailwindMerge(getDefaultConfig);
2587
2548
  exports.createTailwindMerge = createTailwindMerge;
2588
2549
  exports.extendTailwindMerge = extendTailwindMerge;