Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Tailwind v3 #63

Merged
merged 33 commits into from Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d950a8d
add support for aspect-ratio and shadow-color
dcastil Dec 10, 2021
fec2b18
add support for columns and isTshirtSize validator
dcastil Dec 10, 2021
6c78c4c
add tsts for isTshirtSize validator
dcastil Dec 10, 2021
96b8b3a
add isTshirtSize to documentation
dcastil Dec 10, 2021
5baf408
remove outcommented code in default config
dcastil Dec 10, 2021
739f4d7
add support for break-after, break-before and break-inside utilities
dcastil Dec 10, 2021
0177290
add support for text-indent utility
dcastil Dec 10, 2021
a0999e0
add support for text-decoration utilities
dcastil Dec 10, 2021
55ab167
breaking: add support for outline utilities
dcastil Dec 10, 2021
8c07248
update Tailwind version support text in documentation
dcastil Dec 10, 2021
1269ce6
breaking: add support for new vertical-align utilities
dcastil Dec 10, 2021
1437de6
add support for accent-color utilities
dcastil Dec 10, 2021
ebe96d3
remove early development section from documentation
dcastil Dec 10, 2021
24ff3ed
add support for scroll-snap utilities
dcastil Dec 10, 2021
10bd1c2
add support for scroll-behavior utilities
dcastil Dec 10, 2021
1bb2177
add support for touch-action utilities
dcastil Dec 10, 2021
8d39da8
add support for flex-basis utilities
dcastil Dec 10, 2021
e6d8912
breaking: use grow and shrink instead of flex-grow and flex-shrink ut…
dcastil Dec 10, 2021
7ba7334
add support for new border-width and border-color utilities
dcastil Dec 10, 2021
03b71bf
add border-hidden utility
dcastil Dec 10, 2021
65b03e4
breaking: rename some text-overflow classes
dcastil Dec 10, 2021
f3f6605
add overflow-clip utilities
dcastil Dec 10, 2021
61325c3
add full color palette to fill and stroke utilities
dcastil Dec 10, 2021
cf93ba2
add min/max/fit-content values to min/max-width/height utilities
dcastil Dec 10, 2021
c9289c2
add support for will-change utilities
dcastil Dec 10, 2021
2837e54
add support for all cursor values
dcastil Dec 10, 2021
f8acd7c
add custom value support for font-weight, bg-position, bg-size and bg…
dcastil Dec 10, 2021
bfe2cc9
breaking: rename box decoration utiltities
dcastil Dec 10, 2021
014a011
add arbitrary value support for vertical-align
dcastil Dec 10, 2021
adc3c02
breaking: rename custom values to arbitrary values everywhere
dcastil Dec 10, 2021
607f78f
add support for arbitrary properties
dcastil Dec 10, 2021
803889d
add documentation about arbitrary property support
dcastil Dec 10, 2021
1f799bc
adjust Tailwind support message in documentation
dcastil Dec 10, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 34 additions & 17 deletions README.md
Expand Up @@ -16,17 +16,11 @@ twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
// → 'hover:bg-dark-red p-3 bg-[#B91C1C]'
```

- Supports Tailwind v2.0 up to v2.2, support for newer versions will be added continuously
- Supports Tailwind v3.0 (if you use Tailwind v2, use [tailwind-merge v0.9.0](https://github.com/dcastil/tailwind-merge/tree/v0.9.0))
- Works in Node >=12 and all modern browsers
- Fully typed
- [<!-- AUTOGENERATED START package-gzip-size -->5.2 kB<!-- AUTOGENERATED END --> minified + gzipped](https://bundlephobia.com/package/tailwind-merge) (<!-- AUTOGENERATED START package-composition -->96.7% self, 3.3% hashlru<!-- AUTOGENERATED END -->)

## Early development

This library is in an early pre-v1 development stage and might have some bugs and inconveniences here and there. I use the library in production and intend it to be sufficient for production use, as long as you're fine with some potential breaking changes in minor releases until v1 (lock the version range to patch releases with `~` in your `package.json` to prevent accidental breaking changes).

I want to keep the library on v0 until I feel confident enough that there aren't any major bugs or flaws in its API and implementation. If you find a bug or something you don't like, please [submit an issue](https://github.com/dcastil/tailwind-merge/issues/new/choose) or a pull request. I'm happy about any kind of feedback!

## What is it for

If you use Tailwind with a component-based UI renderer like [React](https://reactjs.org) or [Vue](https://vuejs.org), you're probably familiar with the situation that you want to change some styles of a component, but only in one place.
Expand Down Expand Up @@ -100,13 +94,26 @@ twMerge('hover:p-2 hover:p-4') // → 'hover:p-4'
twMerge('hover:focus:p-2 focus:hover:p-4') // → 'focus:hover:p-4'
```

### Supports custom values
### Supports arbitrary values

```ts
twMerge('bg-black bg-[color:var(--mystery-var)]') // → 'bg-[color:var(--mystery-var)]'
twMerge('grid-cols-[1fr,auto] grid-cols-2') // → 'grid-cols-2'
```

### Supports arbitrary properties

```ts
twMerge('[mask-type:luminance] [mask-type:alpha]') // → '[mask-type:alpha]'
twMerge('[--scroll-offset:56px] lg:[--scroll-offset:44px]')
// → '[--scroll-offset:56px] lg:[--scroll-offset:44px]'

// Don't do this!
twMerge('[padding:1rem] p-8') // → '[padding:1rem] p-8'
```

Watch out for mixing arbitrary properties which could be expressed as Tailwind classes. tailwind-merge does not resolve conflicts between arbitrary properties and their matching Tailwind classes to keep the bundle size small.

### Supports important modifier

```ts
Expand Down Expand Up @@ -193,13 +200,13 @@ E.g. here is the overflow class group which results in the classes `overflow-aut
const overflowClassGroup = [{ overflow: ['auto', 'hidden', 'visible', 'scroll'] }]
```

Sometimes it isn't possible to enumerate all elements in a class group. Think of a Tailwind class which allows custom values. In this scenario you can use a validator function which takes a _class part_ and returns a boolean indicating whether a class is part of a class group.
Sometimes it isn't possible to enumerate all elements in a class group. Think of a Tailwind class which allows arbitrary values. In this scenario you can use a validator function which takes a _class part_ and returns a boolean indicating whether a class is part of a class group.

E.g. here is the fill class group.

```ts
const isCustomValue = (classPart: string) => /^\[.+\]$/.test(classPart)
const fillClassGroup = [{ fill: ['current', isCustomValue] }]
const isArbitraryValue = (classPart: string) => /^\[.+\]$/.test(classPart)
const fillClassGroup = [{ fill: ['current', isArbitraryValue] }]
```

Because the function is under the `fill` key, it will only get called for classes which start with `fill-`. Also, the function only gets passed the part of the class name which comes after `fill-`, this way you can use the same function in multiple class groups. tailwind-merge exports its own [validators](#validators), so you don't need to recreate them.
Expand Down Expand Up @@ -506,9 +513,14 @@ const customTwMerge = createTailwindMerge(getDefaultConfig, (config) =>
```ts
interface Validators {
isLength(classPart: string): boolean
isCustomLength(classPart: string): boolean
isArbitraryLength(classPart: string): boolean
isInteger(classPart: string): boolean
isCustomValue(classPart: string): boolean
isArbitraryValue(classPart: string): boolean
isTshirtSize(classPart: string): boolean
isArbitrarySize(classPart: string): boolean
isArbitraryPosition(classPart: string): boolean
isArbitraryUrl(classPart: string): boolean
isArbitraryWeight(classPart: string): boolean
isAny(classPart: string): boolean
}
```
Expand All @@ -521,10 +533,15 @@ const paddingClassGroup = [{ p: [validators.isLength] }]

A brief summary for each validator:

- `isLength` checks whether a class part is a number (`3`, `1.5`), a fraction (`3/4`), a custom length (`[3%]`, `[4px]`, `[length:var(--my-var)]`), or one of the strings `px`, `full` or `screen`.
- `isCustomLength` checks for custom length values (`[3%]`, `[4px]`, `[length:var(--my-var)]`).
- `isInteger` checks for integer values (`3`) and custom integer values (`[3]`).
- `isCustomValue` checks whether the class part is enclosed in brackets (`[something]`)
- `isLength` checks whether a class part is a number (`3`, `1.5`), a fraction (`3/4`), a arbitrary length (`[3%]`, `[4px]`, `[length:var(--my-var)]`), or one of the strings `px`, `full` or `screen`.
- `isArbitraryLength` checks for arbitrary length values (`[3%]`, `[4px]`, `[length:var(--my-var)]`).
- `isInteger` checks for integer values (`3`) and arbitrary integer values (`[3]`).
- `isArbitraryValue` checks whether the class part is enclosed in brackets (`[something]`)
- `isTshirtSize`checks whether class part is a T-shirt size (`sm`, `xl`), optionally with a preceding number (`2xl`).
- `isArbitrarySize` checks whether class part is arbitrary value which starts with with `size:` (`[size:200px_100px]`) which is necessary for background-size classNames.
- `isArbitraryPosition` checks whether class part is arbitrary value which starts with with `position:` (`[position:200px_100px]`) which is necessary for background-position classNames.
- `isArbitraryUrl` checks whether class part is arbitrary value which starts with `url:` or `url(` (`[url('/path-to-image.png')]`, `url:var(--maybe-a-url-at-runtime)]`) which is necessary for background-image classNames.
- `isArbitraryWeight` checks whether class part is arbitrary value whcih starts with `weight:` or is a number (`[weight:var(--value)]`, `[450]`) which is necessary for font-weight classNames.
- `isAny` always returns true. Be careful with this validator as it might match unwanted classes. I use it primarily to match colors or when I'm ceertain there are no other class groups in a namespace.

### `Config`
Expand Down
19 changes: 18 additions & 1 deletion src/class-utils.ts
Expand Up @@ -24,7 +24,7 @@ export function createClassUtils(config: Config) {
classParts.shift()
}

return getGroupRecursive(classParts, classMap)
return getGroupRecursive(classParts, classMap) || getGroupIdForArbitraryProperty(className)
}

function getConflictingClassGroupIds(classGroupId: ClassGroupId) {
Expand Down Expand Up @@ -64,6 +64,23 @@ function getGroupRecursive(
return classPartObject.validators.find(({ validator }) => validator(classRest))?.classGroupId
}

const arbitraryPropertyRegex = /^\[(.+)\]$/

function getGroupIdForArbitraryProperty(className: string) {
if (arbitraryPropertyRegex.test(className)) {
const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)![1]
const property = arbitraryPropertyClassName?.substring(
0,
arbitraryPropertyClassName.indexOf(':')
)

if (property) {
// I use two dots here because one dot is used as prefix for class groups in plugins
return 'arbitrary..' + property
}
}
}

/**
* Exported for testing only
*/
Expand Down