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 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)