tw-mrg 1.0.0
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/LICENSE +9 -0
- package/README.md +197 -0
- package/dist/index.d.ts +650 -0
- package/dist/index.js +2897 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2026 Milo Aguera
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<br />
|
|
3
|
+
<a href="https://github.com/miloag/tw-mrg">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/miloag/tw-mrg/main/docs/thumb.svg" alt="tw-mrg" height="62px" />
|
|
5
|
+
</a>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
# tw-mrg
|
|
9
|
+
|
|
10
|
+
A utility library for intelligently merging Tailwind CSS v4 class names in JavaScript and TypeScript applications. When you need to conditionally combine Tailwind classes or allow component consumers to override default styles, tw-mrg ensures that conflicting classes are resolved correctly by keeping only the most relevant styles.
|
|
11
|
+
|
|
12
|
+
This package is based on [tailwind-merge](https://github.com/dcastil/tailwind-merge) and is designed to complement the official [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss) framework by solving the class conflict problem that arises in component-based architectures.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { tw } from "tw-mrg";
|
|
16
|
+
|
|
17
|
+
// Later classes override earlier conflicting classes
|
|
18
|
+
tw("p-4", "p-8"); // → 'p-8'
|
|
19
|
+
|
|
20
|
+
// Non-conflicting classes are preserved together
|
|
21
|
+
tw("p-4", "mt-2"); // → 'p-4 mt-2'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Acknowledgments
|
|
25
|
+
|
|
26
|
+
This project builds on the excellent work done by [Dany Castillo](https://github.com/dcastil) on [tailwind-merge](https://github.com/dcastil/tailwind-merge), adapting and extending the concepts for [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss) v4 with additional features like runtime CSS injection and an integrated variant system.
|
|
27
|
+
|
|
28
|
+
## Why You Need This
|
|
29
|
+
|
|
30
|
+
When building reusable components with Tailwind CSS, you often encounter a frustrating limitation: CSS class order in HTML has no effect on which styles are applied. The styles are determined solely by the order in which they appear in the generated stylesheet.
|
|
31
|
+
|
|
32
|
+
Consider this common scenario where you want to create a reusable button component that accepts custom class overrides:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
function Button({ className, children }) {
|
|
36
|
+
return (
|
|
37
|
+
<button className={`px-4 py-2 bg-blue-500 ${className}`}>
|
|
38
|
+
{children}
|
|
39
|
+
</button>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Attempting to override the padding
|
|
44
|
+
<Button className="px-8">Click me</Button>;
|
|
45
|
+
// Result: "px-4 py-2 bg-blue-500 px-8"
|
|
46
|
+
// Problem: Both px-4 and px-8 exist in the class string,
|
|
47
|
+
// but which one wins depends on stylesheet order, not HTML order
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This unpredictable behavior makes it difficult to build component libraries where consumers can reliably override styles. The tw-mrg library solves this problem by intelligently analyzing class names and removing conflicting classes, always keeping the ones that appear later in the arguments.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
Install tw-mrg using your preferred package manager:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
npm add tw-mrg
|
|
58
|
+
pnpm add tw-mrg
|
|
59
|
+
yarn add tw-mrg
|
|
60
|
+
bun add tw-mrg
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Requirements:** Node.js 18 or higher, and Tailwind CSS v4.0.0 or higher as a peer dependency.
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
Import the `tw` function and use it to merge your Tailwind classes:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { tw } from "tw-mrg";
|
|
71
|
+
|
|
72
|
+
// Basic conflict resolution: the last conflicting class wins
|
|
73
|
+
tw("p-4", "p-8"); // → 'p-8'
|
|
74
|
+
tw("text-red-500", "text-blue-500"); // → 'text-blue-500'
|
|
75
|
+
tw("inline", "block", "flex"); // → 'flex'
|
|
76
|
+
|
|
77
|
+
// Refinements are intelligently preserved when they don't truly conflict
|
|
78
|
+
tw("p-4", "pt-2"); // → 'p-4 pt-2' (pt-2 refines the top padding)
|
|
79
|
+
tw("mx-auto", "ml-4"); // → 'mx-auto ml-4' (ml-4 refines the left margin)
|
|
80
|
+
|
|
81
|
+
// Modifiers create separate conflict contexts
|
|
82
|
+
tw("hover:bg-blue-500", "hover:bg-red-500"); // → 'hover:bg-red-500'
|
|
83
|
+
tw("md:p-4", "lg:p-8"); // → 'md:p-4 lg:p-8' (different breakpoints)
|
|
84
|
+
tw("p-4", "hover:p-8"); // → 'p-4 hover:p-8' (different states)
|
|
85
|
+
|
|
86
|
+
// Supports conditional classes similar to clsx/classnames
|
|
87
|
+
tw("base-class", isActive && "active-class", { disabled: isDisabled });
|
|
88
|
+
|
|
89
|
+
// Works with arrays for organizing complex class lists
|
|
90
|
+
tw(["p-4", "text-lg"], "bg-white", ["border", "rounded"]);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Component Variant System
|
|
94
|
+
|
|
95
|
+
The `twStates` function provides a powerful way to define component variants, similar to CVA (Class Variance Authority). This makes it easy to create consistent, reusable components with predefined style variations:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { twStates } from "tw-mrg";
|
|
99
|
+
|
|
100
|
+
const button = twStates({
|
|
101
|
+
// Base classes applied to all variants
|
|
102
|
+
base: "px-4 py-2 rounded font-medium transition-colors focus-visible:outline-none",
|
|
103
|
+
|
|
104
|
+
// Define variant axes with their possible values
|
|
105
|
+
variants: {
|
|
106
|
+
variant: {
|
|
107
|
+
primary: "bg-blue-500 text-white hover:bg-blue-600",
|
|
108
|
+
secondary: "bg-gray-200 text-gray-800 hover:bg-gray-300",
|
|
109
|
+
ghost: "bg-transparent hover:bg-gray-100",
|
|
110
|
+
},
|
|
111
|
+
size: {
|
|
112
|
+
sm: "text-sm px-2 py-1",
|
|
113
|
+
md: "text-base px-4 py-2",
|
|
114
|
+
lg: "text-lg px-6 py-3",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Optional: specify which variants to use by default
|
|
119
|
+
defaultVariants: {
|
|
120
|
+
variant: "primary",
|
|
121
|
+
size: "md",
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Usage in components
|
|
126
|
+
button(); // Uses default variants
|
|
127
|
+
button({ variant: "secondary" }); // Override specific variant
|
|
128
|
+
button({ size: "lg", className: "mt-4" }); // Additional classes are merged
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Core API Functions
|
|
132
|
+
|
|
133
|
+
| Function | Description |
|
|
134
|
+
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
135
|
+
| `tw()` | The primary function for merging classes with intelligent conflict resolution. Accepts strings, arrays, objects, and conditional expressions. |
|
|
136
|
+
| `twJoin()` | A faster alternative that joins classes without conflict resolution. Use when you control all classes and know there are no conflicts. |
|
|
137
|
+
| `twStates()` | Creates a variant function for component styling with predefined style variations and compound variants support. |
|
|
138
|
+
| `twDebug()` | Returns detailed information about how classes were resolved, useful for understanding and debugging unexpected results. |
|
|
139
|
+
| `twPrefix()` | Adds modifier prefixes to all classes in a string, useful for programmatically applying responsive or state modifiers. |
|
|
140
|
+
| `createTw()` | Factory function for creating customized tw instances with custom prefixes, cache sizes, or extended class groups. |
|
|
141
|
+
|
|
142
|
+
## Key Features and Capabilities
|
|
143
|
+
|
|
144
|
+
- **Optimized O(n) Performance**: The conflict resolution algorithm processes each class exactly once using a reverse iteration strategy, ensuring consistent performance regardless of input complexity.
|
|
145
|
+
|
|
146
|
+
- **Trie-Based Class Classification**: Class group lookups use an efficient prefix trie data structure, providing O(k) lookup time where k is the length of the class name, rather than iterating through all possible patterns.
|
|
147
|
+
|
|
148
|
+
- **LRU Caching for Repeated Calls**: Results are cached using a Least Recently Used (LRU) cache with a configurable size (default: 500 entries), making repeated calls with the same inputs instant.
|
|
149
|
+
|
|
150
|
+
- **Runtime CSS Injection**: For dynamic or arbitrary classes that aren't in your built CSS, tw-mrg can generate and inject the necessary styles at runtime using Tailwind's design system.
|
|
151
|
+
|
|
152
|
+
- **Specificity-Aware Merging**: The library understands Tailwind's class hierarchy. For example, `p-4` (all sides) and `pt-2` (top only) can coexist because `pt-2` has higher specificity for the top padding.
|
|
153
|
+
|
|
154
|
+
- **Complete Modifier Support**: Full support for responsive modifiers (`sm:`, `md:`, `lg:`), state modifiers (`hover:`, `focus:`, `active:`), and arbitrary variants (`[&:nth-child(2)]:`).
|
|
155
|
+
|
|
156
|
+
- **Tree-Shakeable Configurations**: Choose between the full configuration (~7KB gzipped) covering all Tailwind utilities, or the minimal configuration (~1.5KB gzipped) covering only the most commonly used utilities.
|
|
157
|
+
|
|
158
|
+
- **Full TypeScript Support**: Complete type definitions with inferred types for variant configurations, providing excellent IDE autocomplete and compile-time error checking.
|
|
159
|
+
|
|
160
|
+
## Documentation
|
|
161
|
+
|
|
162
|
+
The following documentation guides cover all aspects of using tw-mrg effectively in your projects:
|
|
163
|
+
|
|
164
|
+
- [Getting Started](./docs/getting-started.md) — Complete installation instructions, input format details, and introductory examples to help you start using tw-mrg in your project.
|
|
165
|
+
- [Core Concepts](./docs/core-concepts.md) — Deep dive into how the conflict resolution algorithm works, including class groups, specificity hierarchies, and the data flow through the system.
|
|
166
|
+
- [Variants](./docs/variants.md) — Comprehensive guide to the twStates variant system, including compound variants, boolean variants, and React component integration patterns.
|
|
167
|
+
- [CSS Injection](./docs/css-injection.md) — How to use runtime CSS generation for dynamic classes, including initialization, validation, and practical React hook patterns.
|
|
168
|
+
- [Customization](./docs/customization.md) — Configuration options for custom Tailwind setups, including prefixes, extending class groups, and creating custom tw instances.
|
|
169
|
+
- [Utilities](./docs/utilities.md) — Reference for helper functions like parsing utilities, cache management, and configuration access.
|
|
170
|
+
- [API Reference](./docs/api.md) — Complete API documentation with all function signatures, types, and configuration options.
|
|
171
|
+
- [Patterns](./docs/patterns.md) — Common recipes and best practices for component libraries, slot patterns, and integration strategies.
|
|
172
|
+
- [Edge Cases](./docs/edge-cases.md) — Handling of edge cases, limitations, and workarounds for complex scenarios.
|
|
173
|
+
|
|
174
|
+
## Development
|
|
175
|
+
|
|
176
|
+
For contributors and developers who want to build or modify tw-mrg locally:
|
|
177
|
+
|
|
178
|
+
```sh
|
|
179
|
+
# Install dependencies
|
|
180
|
+
pnpm install
|
|
181
|
+
|
|
182
|
+
# Build the library for production
|
|
183
|
+
pnpm build
|
|
184
|
+
|
|
185
|
+
# Run in development mode with file watching
|
|
186
|
+
pnpm dev
|
|
187
|
+
|
|
188
|
+
# Run type checking to verify TypeScript types
|
|
189
|
+
pnpm typecheck
|
|
190
|
+
|
|
191
|
+
# Run the test suite
|
|
192
|
+
pnpm test
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
[MIT](./LICENSE)
|