tailwind-to-style 3.1.3 → 3.2.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/README.md +520 -304
- package/dist/core/tws.cjs +984 -0
- package/dist/core/tws.d.ts +14 -0
- package/dist/core/tws.esm.js +981 -0
- package/dist/core/tws.esm.js.map +1 -0
- package/dist/core/twsx.cjs +9068 -0
- package/dist/core/twsx.d.ts +26 -0
- package/dist/core/twsx.esm.js +9066 -0
- package/dist/core/twsx.esm.js.map +1 -0
- package/dist/core/twsxVariants.cjs +9542 -0
- package/dist/core/twsxVariants.d.ts +85 -0
- package/dist/core/twsxVariants.esm.js +9541 -0
- package/dist/core/twsxVariants.esm.js.map +1 -0
- package/dist/cx.cjs +115 -0
- package/dist/cx.d.ts +41 -0
- package/dist/cx.esm.js +111 -0
- package/dist/cx.esm.js.map +1 -0
- package/dist/index.cjs +493 -223
- package/dist/index.d.ts +103 -20
- package/dist/index.esm.js +489 -224
- package/dist/index.esm.js.map +1 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/utils/index.cjs +1797 -0
- package/dist/utils/index.d.ts +44 -0
- package/dist/utils/index.esm.js +1795 -0
- package/dist/utils/index.esm.js.map +1 -0
- package/package.json +51 -7
- package/types/core/tws.d.ts +14 -0
- package/types/core/twsx.d.ts +26 -0
- package/types/core/twsxVariants.d.ts +85 -0
- package/types/cx.d.ts +41 -0
- package/types/index.d.ts +382 -0
- package/types/utils/index.d.ts +44 -0
- package/README.v2-backup.md +0 -2456
package/README.md
CHANGED
|
@@ -5,234 +5,391 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/tailwind-to-style)
|
|
6
6
|
[](https://github.com/Bigetion/tailwind-to-style/actions)
|
|
7
7
|
[](https://www.npmjs.com/package/tailwind-to-style)
|
|
8
|
+
[](https://bundlephobia.com/package/tailwind-to-style)
|
|
8
9
|
[](https://github.com/Bigetion/tailwind-to-style/blob/main/LICENSE)
|
|
9
10
|
|
|
10
|
-
> **Runtime Tailwind CSS to inline styles converter
|
|
11
|
-
>
|
|
12
|
-
> Simple, fast, framework-agnostic. Convert Tailwind utility classes to inline styles or CSS at runtime with zero build step.
|
|
11
|
+
> **Runtime Tailwind CSS to inline styles converter.**
|
|
12
|
+
> Zero build step. SSR-ready. Tree-shakeable. Works everywhere — React, Vue, Svelte, Node.js, vanilla JS.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
---
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [Why tailwind-to-style?](#why-tailwind-to-style)
|
|
19
|
+
- [Installation](#installation)
|
|
20
|
+
- [Quick Start](#quick-start)
|
|
21
|
+
- [Core API](#core-api)
|
|
22
|
+
- [`tws()` — Tailwind to Inline Styles](#tws--tailwind-to-inline-styles)
|
|
23
|
+
- [`twsx()` — CSS-in-JS Engine](#twsx--css-in-js-engine)
|
|
24
|
+
- [`twsxVariants()` — Component Variant System](#twsxvariants--component-variant-system)
|
|
25
|
+
- [`cx()` — Conditional Class Builder](#cx--conditional-class-builder)
|
|
26
|
+
- [Configuration & Plugins](#configuration--plugins)
|
|
27
|
+
- [`configure()` — Custom Theme](#configure--custom-theme)
|
|
28
|
+
- [Plugin System](#plugin-system)
|
|
29
|
+
- [SSR (Server-Side Rendering)](#ssr-server-side-rendering)
|
|
30
|
+
- [Animation System](#animation-system)
|
|
31
|
+
- [Tree-Shakeable Imports](#tree-shakeable-imports)
|
|
32
|
+
- [Preflight CSS](#preflight-css)
|
|
33
|
+
- [Framework Integration](#framework-integration)
|
|
34
|
+
- [Performance](#performance)
|
|
35
|
+
- [Debugging & Logging](#debugging--logging)
|
|
36
|
+
- [Comparison](#comparison)
|
|
37
|
+
- [Migration from v2](#migration-from-v2)
|
|
38
|
+
- [Contributing](#contributing)
|
|
39
|
+
- [Support](#-support)
|
|
40
|
+
- [License](#license)
|
|
23
41
|
|
|
24
|
-
|
|
42
|
+
---
|
|
25
43
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
44
|
+
## Why tailwind-to-style?
|
|
45
|
+
|
|
46
|
+
| Feature | Description |
|
|
47
|
+
|---|---|
|
|
48
|
+
| **Zero Build Step** | No PostCSS, no compilation — just JavaScript |
|
|
49
|
+
| **Framework Agnostic** | React, Vue, Svelte, vanilla JS |
|
|
50
|
+
| **Full Tailwind Support** | All utilities, responsive, pseudo-states, arbitrary values |
|
|
51
|
+
| **SCSS-like Nesting** | `twsx()` for complex nested selector-based styles |
|
|
52
|
+
| **Variant System** | Type-safe component variants like CVA/tailwind-variants |
|
|
53
|
+
| **Conditional Classes** | Built-in `cx()` utility (like clsx/classnames) |
|
|
54
|
+
| **SSR Support** | Server-side rendering with `startSSR()`/`stopSSR()` |
|
|
55
|
+
| **@css Directive** | Inject raw CSS for vendor-specific or complex properties |
|
|
56
|
+
| **Customizable** | Extend theme with colors, spacing, fonts, plugins |
|
|
57
|
+
| **TypeScript** | Full type definitions with generics for autocomplete |
|
|
58
|
+
| **Tree-Shakeable** | Import only what you need — reduce bundle by 50-70% |
|
|
59
|
+
| **Lightweight** | ~12KB minified, zero runtime dependencies |
|
|
60
|
+
| **Lightning Fast** | Pre-compiled regex + multi-level LRU caching |
|
|
29
61
|
|
|
30
|
-
|
|
62
|
+
---
|
|
31
63
|
|
|
32
|
-
|
|
64
|
+
## Installation
|
|
33
65
|
|
|
34
|
-
|
|
66
|
+
```bash
|
|
67
|
+
npm install tailwind-to-style
|
|
68
|
+
```
|
|
35
69
|
|
|
36
|
-
```
|
|
37
|
-
|
|
70
|
+
```bash
|
|
71
|
+
yarn add tailwind-to-style
|
|
72
|
+
```
|
|
38
73
|
|
|
39
|
-
|
|
74
|
+
```bash
|
|
75
|
+
pnpm add tailwind-to-style
|
|
76
|
+
```
|
|
40
77
|
|
|
41
|
-
|
|
42
|
-
<div style={styles}>Hello World</div>
|
|
78
|
+
**CDN (browser):**
|
|
43
79
|
|
|
44
|
-
|
|
45
|
-
|
|
80
|
+
```html
|
|
81
|
+
<script src="https://unpkg.com/tailwind-to-style"></script>
|
|
82
|
+
<script>
|
|
83
|
+
const { tws, twsx } = tailwindToStyle
|
|
84
|
+
</script>
|
|
46
85
|
```
|
|
47
86
|
|
|
48
|
-
|
|
87
|
+
---
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
## Quick Start
|
|
51
90
|
|
|
52
91
|
```javascript
|
|
53
|
-
import { twsx } from 'tailwind-to-style'
|
|
92
|
+
import { tws, twsx, twsxVariants, cx } from 'tailwind-to-style'
|
|
93
|
+
|
|
94
|
+
// 1. Inline styles
|
|
95
|
+
const style = tws('bg-blue-500 text-white p-4 rounded-lg', true)
|
|
96
|
+
// → { backgroundColor: '#3b82f6', color: '#fff', padding: '1rem', borderRadius: '0.5rem' }
|
|
97
|
+
|
|
98
|
+
// 2. Real CSS with selectors
|
|
99
|
+
twsx({
|
|
100
|
+
'.card': ['bg-white p-6 rounded-xl shadow-md', {
|
|
101
|
+
'&:hover': 'shadow-xl',
|
|
102
|
+
'> .title': 'text-xl font-bold text-gray-900',
|
|
103
|
+
}]
|
|
104
|
+
})
|
|
105
|
+
// → auto-injects <style> with .card { ... } .card:hover { ... }
|
|
54
106
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
'bg-blue-500 text-white px-4 py-2 rounded',
|
|
64
|
-
{
|
|
65
|
-
'&:hover': 'bg-blue-600',
|
|
66
|
-
'&:active': 'bg-blue-700'
|
|
67
|
-
}
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
],
|
|
71
|
-
|
|
72
|
-
// Media queries at root level
|
|
73
|
-
'@media (max-width: 768px)': {
|
|
74
|
-
'.card': 'p-4',
|
|
75
|
-
'.card > .title': 'text-xl'
|
|
76
|
-
}
|
|
107
|
+
// 3. Component variants
|
|
108
|
+
const btn = twsxVariants('.btn', {
|
|
109
|
+
base: 'px-4 py-2 rounded-lg font-medium',
|
|
110
|
+
variants: {
|
|
111
|
+
color: { primary: 'bg-blue-500 text-white', danger: 'bg-red-500 text-white' },
|
|
112
|
+
size: { sm: 'text-sm', md: 'text-base', lg: 'text-lg' },
|
|
113
|
+
},
|
|
114
|
+
defaultVariants: { color: 'primary', size: 'md' },
|
|
77
115
|
})
|
|
116
|
+
btn({ color: 'danger', size: 'lg' }) // → "btn btn-danger-lg"
|
|
78
117
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
document.head.appendChild(style)
|
|
118
|
+
// 4. Conditional classes
|
|
119
|
+
cx('p-4', isActive && 'bg-blue-500', { 'opacity-50': isDisabled })
|
|
120
|
+
// → 'p-4 bg-blue-500'
|
|
83
121
|
```
|
|
84
122
|
|
|
85
|
-
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Core API
|
|
86
126
|
|
|
87
|
-
### `tws(
|
|
127
|
+
### `tws()` — Tailwind to Inline Styles
|
|
88
128
|
|
|
89
|
-
|
|
129
|
+
Converts Tailwind CSS class strings into CSS string or JSON style objects at runtime.
|
|
90
130
|
|
|
91
131
|
```javascript
|
|
92
132
|
import { tws } from 'tailwind-to-style'
|
|
93
133
|
|
|
94
|
-
//
|
|
95
|
-
|
|
134
|
+
// CSS string (default)
|
|
135
|
+
tws('bg-blue-500 p-4 rounded-lg')
|
|
136
|
+
// → "background-color: #3b82f6; padding: 1rem; border-radius: 0.5rem;"
|
|
137
|
+
|
|
138
|
+
// JSON object (pass `true` as 2nd argument)
|
|
139
|
+
tws('flex items-center gap-4', true)
|
|
96
140
|
// → { display: 'flex', alignItems: 'center', gap: '1rem' }
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Supported features:**
|
|
97
144
|
|
|
98
|
-
|
|
99
|
-
|
|
145
|
+
```javascript
|
|
146
|
+
// Responsive breakpoints
|
|
147
|
+
tws('text-sm md:text-base lg:text-lg')
|
|
100
148
|
|
|
101
149
|
// Pseudo-states
|
|
102
|
-
|
|
150
|
+
tws('bg-blue-500 hover:bg-blue-600 focus:ring-2')
|
|
103
151
|
|
|
104
152
|
// Arbitrary values
|
|
105
|
-
|
|
153
|
+
tws('w-[123px] text-[#abc] mt-[2.5rem] grid-cols-[1fr,2fr]')
|
|
106
154
|
|
|
107
155
|
// Important modifier
|
|
108
|
-
|
|
156
|
+
tws('!bg-red-500 !text-white')
|
|
157
|
+
|
|
158
|
+
// Negative values
|
|
159
|
+
tws('-mt-4 -translate-x-2')
|
|
160
|
+
|
|
161
|
+
// Opacity modifier
|
|
162
|
+
tws('bg-blue-500/50 text-black/75')
|
|
109
163
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
// → '{"padding":"1rem","margin":"0.5rem"}'
|
|
164
|
+
// Decimal spacing
|
|
165
|
+
tws('p-0.5 m-1.5 gap-2.5')
|
|
113
166
|
```
|
|
114
167
|
|
|
115
|
-
|
|
168
|
+
**Use in React:**
|
|
116
169
|
|
|
117
|
-
|
|
170
|
+
```jsx
|
|
171
|
+
<div style={tws('flex items-center gap-4 bg-white p-6 rounded-xl shadow-md', true)}>
|
|
172
|
+
<h1 style={tws('text-2xl font-bold text-gray-900', true)}>Hello</h1>
|
|
173
|
+
</div>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
### `twsx()` — CSS-in-JS Engine
|
|
179
|
+
|
|
180
|
+
Generates real CSS from Tailwind classes with full selector support, SCSS-like nesting, and auto-injects a `<style>` tag into the DOM.
|
|
118
181
|
|
|
119
182
|
```javascript
|
|
120
183
|
import { twsx } from 'tailwind-to-style'
|
|
121
184
|
|
|
122
|
-
|
|
185
|
+
twsx({
|
|
123
186
|
'.button': [
|
|
124
187
|
'bg-blue-500 text-white px-6 py-3 rounded-lg font-medium transition-all',
|
|
125
188
|
{
|
|
126
|
-
'&:hover': 'bg-blue-600 transform scale-105',
|
|
189
|
+
'&:hover': 'bg-blue-600 shadow-lg transform scale-105',
|
|
127
190
|
'&:active': 'bg-blue-700 scale-95',
|
|
128
191
|
'&:disabled': 'bg-gray-400 opacity-50 cursor-not-allowed',
|
|
129
192
|
'&.large': 'px-8 py-4 text-lg',
|
|
130
|
-
'&.small': 'px-3 py-1.5 text-sm'
|
|
131
193
|
}
|
|
132
194
|
],
|
|
133
|
-
|
|
195
|
+
|
|
134
196
|
'.card': 'bg-white rounded-xl shadow-lg overflow-hidden',
|
|
135
197
|
'.card > .header': 'p-6 border-b border-gray-200',
|
|
136
198
|
'.card > .body': 'p-6',
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// Media queries at root level
|
|
199
|
+
|
|
200
|
+
// Media queries
|
|
140
201
|
'@media (max-width: 768px)': {
|
|
141
202
|
'.card': 'rounded-lg',
|
|
142
203
|
'.card > .header': 'p-4',
|
|
143
|
-
'.card > .body': 'p-4'
|
|
144
204
|
}
|
|
145
205
|
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Nesting syntax:**
|
|
209
|
+
|
|
210
|
+
| Pattern | Example | Description |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| `&:pseudo` | `'&:hover': 'bg-blue-600'` | Pseudo-classes |
|
|
213
|
+
| `&.modifier` | `'&.active': 'ring-2'` | Class modifiers |
|
|
214
|
+
| `> .child` | `'> .title': 'text-xl'` | Direct children |
|
|
215
|
+
| `.descendant` | `'.icon': 'w-5 h-5'` | Descendants |
|
|
216
|
+
| `@media` | `'@media (max-width: 768px)': { ... }` | Media queries |
|
|
217
|
+
|
|
218
|
+
**Options:**
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// Disable auto-injection (returns CSS string only)
|
|
222
|
+
const css = twsx({ '.btn': 'bg-blue-500 text-white' }, { inject: false })
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
#### `@css` Directive — Raw CSS Escape Hatch
|
|
226
|
+
|
|
227
|
+
For CSS that Tailwind can't express, use the `@css` directive:
|
|
228
|
+
|
|
229
|
+
**String form:**
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
twsx({
|
|
233
|
+
'.gradient-text': '@css { background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }',
|
|
234
|
+
})
|
|
235
|
+
```
|
|
146
236
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
237
|
+
**Object form (within arrays):**
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
twsx({
|
|
241
|
+
'.gradient-text': [
|
|
242
|
+
'text-3xl font-bold',
|
|
243
|
+
{
|
|
244
|
+
'@css': {
|
|
245
|
+
'background': 'linear-gradient(90deg, #ff6b6b, #feca57)',
|
|
246
|
+
'-webkit-background-clip': 'text',
|
|
247
|
+
'-webkit-text-fill-color': 'transparent',
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
})
|
|
150
252
|
```
|
|
151
253
|
|
|
152
|
-
|
|
153
|
-
- `'&:hover'` - Pseudo-classes
|
|
154
|
-
- `'&.class'` - Modifiers
|
|
155
|
-
- `'> .child'` - Direct children
|
|
156
|
-
- `'.nested'` - Descendants
|
|
157
|
-
- `'@media ...'` - Media queries (root level only)
|
|
254
|
+
---
|
|
158
255
|
|
|
159
|
-
### `twsxVariants(
|
|
256
|
+
### `twsxVariants()` — Component Variant System
|
|
160
257
|
|
|
161
|
-
|
|
258
|
+
A CVA-like API for building type-safe component variants. Auto-generates CSS for all combinations and returns a class name builder function.
|
|
162
259
|
|
|
163
260
|
```javascript
|
|
164
261
|
import { twsxVariants } from 'tailwind-to-style'
|
|
165
262
|
|
|
166
263
|
const btn = twsxVariants('.btn', {
|
|
167
|
-
base: 'px-4 py-2 rounded-lg font-medium transition-all',
|
|
264
|
+
base: 'px-4 py-2 rounded-lg font-medium transition-all border',
|
|
168
265
|
variants: {
|
|
169
266
|
variant: {
|
|
170
|
-
solid: '
|
|
267
|
+
solid: 'shadow-sm',
|
|
171
268
|
outline: 'bg-transparent border-2',
|
|
172
|
-
ghost: 'bg-transparent',
|
|
269
|
+
ghost: 'bg-transparent border-transparent',
|
|
173
270
|
},
|
|
174
271
|
color: {
|
|
175
|
-
primary: 'bg-blue-500 text-white
|
|
176
|
-
danger: 'bg-red-500 text-white
|
|
272
|
+
primary: 'bg-blue-500 text-white border-blue-500',
|
|
273
|
+
danger: 'bg-red-500 text-white border-red-500',
|
|
274
|
+
neutral: 'bg-gray-100 text-gray-900 border-gray-300',
|
|
177
275
|
},
|
|
178
276
|
size: {
|
|
179
277
|
sm: 'px-3 py-1.5 text-sm',
|
|
180
278
|
md: 'px-4 py-2 text-base',
|
|
181
279
|
lg: 'px-6 py-3 text-lg',
|
|
182
280
|
},
|
|
281
|
+
disabled: {
|
|
282
|
+
true: 'opacity-50 cursor-not-allowed pointer-events-none',
|
|
283
|
+
},
|
|
183
284
|
},
|
|
184
285
|
compoundVariants: [
|
|
185
|
-
{ variant: 'outline', color: 'primary', class: '
|
|
186
|
-
{ variant: 'outline', color: 'danger', class: '
|
|
286
|
+
{ variant: 'outline', color: 'primary', class: 'bg-transparent text-blue-600 border-blue-500' },
|
|
287
|
+
{ variant: 'outline', color: 'danger', class: 'bg-transparent text-red-600 border-red-500' },
|
|
187
288
|
],
|
|
188
|
-
defaultVariants: { variant: 'solid', color: 'primary', size: 'md' }
|
|
289
|
+
defaultVariants: { variant: 'solid', color: 'primary', size: 'md' },
|
|
189
290
|
})
|
|
190
291
|
|
|
191
|
-
// Usage
|
|
292
|
+
// Usage — returns class name string
|
|
192
293
|
btn() // "btn"
|
|
193
294
|
btn({ color: 'danger' }) // "btn btn-danger"
|
|
194
295
|
btn({ variant: 'outline', size: 'lg' }) // "btn btn-outline-lg"
|
|
195
|
-
|
|
196
|
-
// In React
|
|
197
|
-
const Button = ({ variant, color, size, children, ...props }) => (
|
|
198
|
-
<button className={btn({ variant, color, size })} {...props}>
|
|
199
|
-
{children}
|
|
200
|
-
</button>
|
|
201
|
-
)
|
|
202
296
|
```
|
|
203
297
|
|
|
204
|
-
**Nested
|
|
298
|
+
**Nested selectors** — style child elements:
|
|
205
299
|
|
|
206
300
|
```javascript
|
|
207
301
|
const alert = twsxVariants('.alert', {
|
|
208
302
|
base: 'p-4 rounded-lg border flex gap-3',
|
|
209
303
|
variants: {
|
|
210
304
|
status: {
|
|
211
|
-
info: 'bg-blue-50 text-blue-800',
|
|
212
|
-
error: 'bg-red-50 text-red-800',
|
|
305
|
+
info: 'bg-blue-50 border-blue-200 text-blue-800',
|
|
306
|
+
error: 'bg-red-50 border-red-200 text-red-800',
|
|
213
307
|
},
|
|
214
308
|
},
|
|
215
309
|
defaultVariants: { status: 'info' },
|
|
216
310
|
nested: {
|
|
217
311
|
'.alert-icon': 'flex-shrink-0 mt-0.5',
|
|
218
312
|
'.alert-content': 'flex-1',
|
|
219
|
-
'.alert-dismiss': 'p-1 rounded hover:bg-black/10',
|
|
313
|
+
'.alert-dismiss': 'p-1 rounded hover:bg-black/10 cursor-pointer',
|
|
220
314
|
}
|
|
221
315
|
})
|
|
316
|
+
// Generates: .alert .alert-icon { ... }, .alert .alert-content { ... }, etc.
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Class naming convention:**
|
|
320
|
+
|
|
321
|
+
| Call | Returns | Why |
|
|
322
|
+
|---|---|---|
|
|
323
|
+
| `btn()` | `"btn"` | All defaults |
|
|
324
|
+
| `btn({ color: 'danger' })` | `"btn btn-danger"` | One non-default |
|
|
325
|
+
| `btn({ variant: 'outline', color: 'danger', size: 'lg' })` | `"btn btn-outline-danger-lg"` | All non-defaults |
|
|
326
|
+
|
|
327
|
+
**TypeScript — full generics support:**
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { twsxVariants, type VariantProps } from 'tailwind-to-style'
|
|
331
|
+
|
|
332
|
+
const button = twsxVariants('.btn', {
|
|
333
|
+
base: 'px-4 py-2 rounded',
|
|
334
|
+
variants: {
|
|
335
|
+
variant: { solid: 'bg-blue-500', outline: 'border-2' },
|
|
336
|
+
size: { sm: 'text-sm', md: 'text-base', lg: 'text-lg' },
|
|
337
|
+
},
|
|
338
|
+
defaultVariants: { variant: 'solid', size: 'md' },
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
type ButtonProps = VariantProps<typeof button>
|
|
342
|
+
// → { variant?: 'solid' | 'outline', size?: 'sm' | 'md' | 'lg' }
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
### `cx()` — Conditional Class Builder
|
|
348
|
+
|
|
349
|
+
A built-in utility for conditionally joining class names — replaces `clsx`/`classnames`:
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
import { cx } from 'tailwind-to-style'
|
|
222
353
|
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
//
|
|
354
|
+
// Strings
|
|
355
|
+
cx('bg-blue-500', 'text-white')
|
|
356
|
+
// → 'bg-blue-500 text-white'
|
|
357
|
+
|
|
358
|
+
// Conditionals
|
|
359
|
+
cx('p-4', isActive && 'bg-blue-500', isDisabled && 'opacity-50')
|
|
360
|
+
// → 'p-4 bg-blue-500'
|
|
361
|
+
|
|
362
|
+
// Object syntax
|
|
363
|
+
cx('p-4', { 'bg-blue-500': isActive, 'opacity-50': isDisabled })
|
|
364
|
+
// → 'p-4 bg-blue-500'
|
|
365
|
+
|
|
366
|
+
// Arrays
|
|
367
|
+
cx(['p-4', 'bg-white'], isActive && ['ring-2', 'ring-blue-500'])
|
|
368
|
+
// → 'p-4 bg-white ring-2 ring-blue-500'
|
|
369
|
+
|
|
370
|
+
// Combined with tws()
|
|
371
|
+
const styles = tws(cx('p-4', isLarge && 'p-8', { 'bg-blue-500': isPrimary }))
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**`cx.with()` — Base class factory:**
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
const btnClass = cx.with('px-4 py-2 rounded font-medium transition-colors')
|
|
378
|
+
|
|
379
|
+
btnClass('bg-blue-500 text-white')
|
|
380
|
+
// → 'px-4 py-2 rounded font-medium transition-colors bg-blue-500 text-white'
|
|
381
|
+
|
|
382
|
+
btnClass({ 'opacity-50': disabled })
|
|
383
|
+
// → 'px-4 py-2 rounded font-medium transition-colors opacity-50'
|
|
226
384
|
```
|
|
227
385
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
- `.btn-outline-danger-lg` = multiple non-defaults
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Configuration & Plugins
|
|
232
389
|
|
|
233
|
-
### `configure(
|
|
390
|
+
### `configure()` — Custom Theme
|
|
234
391
|
|
|
235
|
-
|
|
392
|
+
Extend the default Tailwind theme with custom colors, spacing, fonts, and more.
|
|
236
393
|
|
|
237
394
|
```javascript
|
|
238
395
|
import { configure } from 'tailwind-to-style'
|
|
@@ -246,201 +403,215 @@ configure({
|
|
|
246
403
|
100: '#dbeafe',
|
|
247
404
|
500: '#3b82f6',
|
|
248
405
|
600: '#2563eb',
|
|
249
|
-
900: '#1e3a8a'
|
|
406
|
+
900: '#1e3a8a',
|
|
250
407
|
},
|
|
251
|
-
accent: '#f59e0b'
|
|
408
|
+
accent: '#f59e0b',
|
|
252
409
|
},
|
|
253
410
|
spacing: {
|
|
254
411
|
'128': '32rem',
|
|
255
|
-
'144': '36rem'
|
|
412
|
+
'144': '36rem',
|
|
256
413
|
},
|
|
257
414
|
fontFamily: {
|
|
258
415
|
sans: ['Inter', 'system-ui', 'sans-serif'],
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
},
|
|
263
419
|
})
|
|
264
420
|
|
|
265
|
-
// Now use
|
|
266
|
-
|
|
421
|
+
// Now use custom values
|
|
422
|
+
tws('bg-brand-500 text-brand-50 p-128 font-sans')
|
|
267
423
|
```
|
|
268
424
|
|
|
269
|
-
**
|
|
425
|
+
**Config API:**
|
|
426
|
+
|
|
427
|
+
| Function | Description |
|
|
428
|
+
|---|---|
|
|
429
|
+
| `configure(config)` | Apply custom configuration |
|
|
430
|
+
| `getConfig()` | Get current configuration |
|
|
431
|
+
| `resetConfig()` | Reset to defaults |
|
|
432
|
+
| `clearConfigCache()` | Clear cached config lookups |
|
|
270
433
|
|
|
271
|
-
|
|
434
|
+
### Plugin System
|
|
435
|
+
|
|
436
|
+
Create reusable plugins to extend the utility set:
|
|
272
437
|
|
|
273
438
|
```javascript
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
```
|
|
439
|
+
import { configure, createPlugin, createUtilityPlugin } from 'tailwind-to-style'
|
|
440
|
+
|
|
441
|
+
// Simple plugin — static utilities
|
|
442
|
+
const textShadow = createPlugin('text-shadow', {
|
|
443
|
+
utilities: {
|
|
444
|
+
'text-shadow-sm': { textShadow: '0 1px 2px rgba(0,0,0,0.05)' },
|
|
445
|
+
'text-shadow-md': { textShadow: '0 2px 4px rgba(0,0,0,0.1)' },
|
|
446
|
+
'text-shadow-lg': { textShadow: '0 4px 8px rgba(0,0,0,0.15)' },
|
|
447
|
+
},
|
|
448
|
+
})
|
|
285
449
|
|
|
286
|
-
|
|
450
|
+
// Dynamic plugin — value-based utilities
|
|
451
|
+
const glass = createUtilityPlugin('glass', {
|
|
452
|
+
prefix: 'glass',
|
|
453
|
+
values: { sm: '4px', md: '8px', lg: '16px' },
|
|
454
|
+
formatter: (value) => ({
|
|
455
|
+
backdropFilter: `blur(${value})`,
|
|
456
|
+
backgroundColor: 'rgba(255,255,255,0.1)',
|
|
457
|
+
}),
|
|
458
|
+
})
|
|
287
459
|
|
|
288
|
-
|
|
460
|
+
configure({ plugins: [textShadow, glass] })
|
|
289
461
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
import 'tailwind-to-style/preflight.css'
|
|
462
|
+
// Now use custom utilities
|
|
463
|
+
tws('text-shadow-md glass-lg')
|
|
293
464
|
```
|
|
294
465
|
|
|
295
|
-
|
|
296
|
-
<!-- Or in HTML -->
|
|
297
|
-
<link rel="stylesheet" href="node_modules/tailwind-to-style/preflight.css">
|
|
298
|
-
```
|
|
466
|
+
---
|
|
299
467
|
|
|
300
|
-
|
|
301
|
-
- Consistent box-sizing
|
|
302
|
-
- Reset margins and paddings
|
|
303
|
-
- Normalized form elements
|
|
304
|
-
- Better default font rendering
|
|
468
|
+
## SSR (Server-Side Rendering)
|
|
305
469
|
|
|
306
|
-
|
|
470
|
+
Collect CSS during server-side rendering instead of injecting into the DOM:
|
|
307
471
|
|
|
308
|
-
|
|
472
|
+
```javascript
|
|
473
|
+
import { startSSR, stopSSR, getSSRStyles, twsx } from 'tailwind-to-style'
|
|
309
474
|
|
|
310
|
-
|
|
475
|
+
// 1. Start collecting
|
|
476
|
+
startSSR()
|
|
311
477
|
|
|
312
|
-
|
|
478
|
+
// 2. Render your app (twsx() collects CSS instead of injecting)
|
|
479
|
+
twsx({ '.card': 'bg-white p-6 rounded-lg shadow-md' })
|
|
480
|
+
twsx({ '.btn': 'bg-blue-500 text-white px-4 py-2 rounded' })
|
|
481
|
+
const html = renderToString(<App />)
|
|
313
482
|
|
|
314
|
-
|
|
315
|
-
|
|
483
|
+
// 3. Get collected CSS
|
|
484
|
+
const css = stopSSR()
|
|
316
485
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
486
|
+
// 4. Inject into HTML response
|
|
487
|
+
const fullHtml = `
|
|
488
|
+
<html>
|
|
489
|
+
<head><style>${css}</style></head>
|
|
490
|
+
<body>${html}</body>
|
|
491
|
+
</html>
|
|
492
|
+
`
|
|
321
493
|
```
|
|
322
494
|
|
|
323
|
-
|
|
495
|
+
**SSR API:**
|
|
324
496
|
|
|
325
|
-
|
|
497
|
+
| Function | Description |
|
|
498
|
+
|---|---|
|
|
499
|
+
| `startSSR()` | Begin collecting CSS |
|
|
500
|
+
| `stopSSR()` | Stop collecting, return all CSS as string |
|
|
501
|
+
| `getSSRStyles()` | Peek at collected CSS without stopping |
|
|
502
|
+
| `IS_BROWSER` | `true` in browser environment |
|
|
503
|
+
| `IS_SERVER` | `true` in Node.js/server environment |
|
|
326
504
|
|
|
327
|
-
|
|
328
|
-
import { tws } from 'tailwind-to-style'
|
|
505
|
+
---
|
|
329
506
|
|
|
330
|
-
|
|
331
|
-
<div style="${tws('bg-white p-8 text-center', { format: 'css' })}">
|
|
332
|
-
<h1 style="${tws('text-2xl font-bold mb-4', { format: 'css' })}">
|
|
333
|
-
Welcome!
|
|
334
|
-
</h1>
|
|
335
|
-
</div>
|
|
336
|
-
`
|
|
337
|
-
```
|
|
507
|
+
## Animation System
|
|
338
508
|
|
|
339
|
-
###
|
|
509
|
+
### Built-in CSS Animations
|
|
340
510
|
|
|
341
511
|
```javascript
|
|
342
|
-
|
|
512
|
+
tws('animate-spin') // → animation: spin 1s linear infinite
|
|
513
|
+
tws('animate-bounce') // → animation: bounce 1s infinite
|
|
514
|
+
tws('animate-pulse') // → animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite
|
|
515
|
+
tws('animate-ping') // → animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite
|
|
516
|
+
```
|
|
343
517
|
|
|
344
|
-
|
|
345
|
-
'.app': [
|
|
346
|
-
'min-h-screen bg-gray-50',
|
|
347
|
-
{
|
|
348
|
-
'> .header': 'bg-white shadow-sm p-4',
|
|
349
|
-
'> .main': 'container mx-auto py-8',
|
|
350
|
-
'> .footer': 'bg-gray-900 text-white p-8'
|
|
351
|
-
}
|
|
352
|
-
]
|
|
353
|
-
})
|
|
518
|
+
### Web Animations API
|
|
354
519
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
520
|
+
```javascript
|
|
521
|
+
import { applyWebAnimation } from 'tailwind-to-style'
|
|
522
|
+
|
|
523
|
+
// Apply a named animation to a DOM element
|
|
524
|
+
applyWebAnimation(element, 'fadeIn')
|
|
525
|
+
applyWebAnimation(element, 'slideUp')
|
|
359
526
|
```
|
|
360
527
|
|
|
361
|
-
###
|
|
528
|
+
### Inline Animations
|
|
362
529
|
|
|
363
530
|
```javascript
|
|
364
|
-
import {
|
|
531
|
+
import { applyInlineAnimation, animateElement, chainAnimations, staggerAnimations } from 'tailwind-to-style'
|
|
365
532
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
})
|
|
533
|
+
// Single animation
|
|
534
|
+
applyInlineAnimation(element, 'fadeIn')
|
|
535
|
+
|
|
536
|
+
// Programmatic animation
|
|
537
|
+
animateElement(element, { opacity: [0, 1] }, { duration: 300 })
|
|
538
|
+
|
|
539
|
+
// Sequential chain
|
|
540
|
+
chainAnimations(element, ['fadeIn', 'slideUp', 'bounceIn'])
|
|
541
|
+
|
|
542
|
+
// Staggered across multiple elements
|
|
543
|
+
staggerAnimations('.card', 'fadeIn', { delay: 100 })
|
|
377
544
|
```
|
|
378
545
|
|
|
379
|
-
|
|
546
|
+
---
|
|
380
547
|
|
|
381
|
-
|
|
548
|
+
## Tree-Shakeable Imports
|
|
382
549
|
|
|
383
|
-
|
|
550
|
+
Import only what you need to reduce bundle size by **50-70%**:
|
|
384
551
|
|
|
385
552
|
```javascript
|
|
386
|
-
|
|
553
|
+
// Individual imports (recommended for production)
|
|
554
|
+
import { tws } from 'tailwind-to-style/tws' // ~3KB
|
|
555
|
+
import { twsx } from 'tailwind-to-style/twsx' // ~6KB
|
|
556
|
+
import { twsxVariants } from 'tailwind-to-style/twsx-variants' // ~6KB
|
|
557
|
+
import { cx } from 'tailwind-to-style/cx' // <1KB
|
|
558
|
+
|
|
559
|
+
// Full import (everything)
|
|
560
|
+
import { tws, twsx, twsxVariants, cx } from 'tailwind-to-style' // ~12KB
|
|
387
561
|
```
|
|
388
562
|
|
|
389
|
-
|
|
563
|
+
| Import Path | Includes | Size (minified) |
|
|
564
|
+
|---|---|---|
|
|
565
|
+
| `tailwind-to-style` | Everything | ~12KB |
|
|
566
|
+
| `tailwind-to-style/tws` | `tws()` only | ~3KB |
|
|
567
|
+
| `tailwind-to-style/twsx` | `twsx()` | ~6KB |
|
|
568
|
+
| `tailwind-to-style/twsx-variants` | `twsxVariants()` | ~6KB |
|
|
569
|
+
| `tailwind-to-style/cx` | `cx()` | <1KB |
|
|
570
|
+
| `tailwind-to-style/utils` | Logger, LRUCache, error handler | ~2KB |
|
|
390
571
|
|
|
391
|
-
|
|
572
|
+
All sub-paths provide ESM + CJS bundles with TypeScript type definitions.
|
|
392
573
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
h-[calc(100vh-64px)]
|
|
397
|
-
text-[#abc123]
|
|
398
|
-
bg-[url('/image.png')]
|
|
399
|
-
grid-cols-[1fr,2fr,1fr]
|
|
400
|
-
`)
|
|
401
|
-
```
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Preflight CSS
|
|
402
577
|
|
|
403
|
-
|
|
578
|
+
For best results, import Tailwind's preflight (base/reset styles):
|
|
404
579
|
|
|
405
580
|
```javascript
|
|
406
|
-
|
|
407
|
-
bg-blue-500
|
|
408
|
-
hover:bg-blue-600
|
|
409
|
-
focus:ring-2
|
|
410
|
-
active:scale-95
|
|
411
|
-
disabled:opacity-50
|
|
412
|
-
group-hover:text-white
|
|
413
|
-
`)
|
|
581
|
+
import 'tailwind-to-style/preflight.css'
|
|
414
582
|
```
|
|
415
583
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const styles = tws('!bg-red-500 !text-white')
|
|
420
|
-
// Forces these styles to take precedence
|
|
584
|
+
```html
|
|
585
|
+
<!-- Or in HTML -->
|
|
586
|
+
<link rel="stylesheet" href="node_modules/tailwind-to-style/preflight.css">
|
|
421
587
|
```
|
|
422
588
|
|
|
423
|
-
|
|
589
|
+
Provides consistent box-sizing, reset margins/paddings, normalized form elements, and better default font rendering. Skip this if you're already using Tailwind CSS in your project.
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## Framework Integration
|
|
424
594
|
|
|
425
595
|
### React
|
|
426
596
|
|
|
427
|
-
```
|
|
597
|
+
```jsx
|
|
428
598
|
import { tws, twsx } from 'tailwind-to-style'
|
|
429
599
|
import { useEffect } from 'react'
|
|
430
600
|
|
|
431
601
|
function App() {
|
|
602
|
+
// Inject CSS on mount
|
|
432
603
|
useEffect(() => {
|
|
433
|
-
|
|
434
|
-
'.
|
|
604
|
+
twsx({
|
|
605
|
+
'.card': ['bg-white rounded-xl shadow-md p-6', {
|
|
606
|
+
'&:hover': 'shadow-xl',
|
|
607
|
+
'> .title': 'text-xl font-bold',
|
|
608
|
+
}]
|
|
435
609
|
})
|
|
436
|
-
const style = document.createElement('style')
|
|
437
|
-
style.textContent = css
|
|
438
|
-
document.head.appendChild(style)
|
|
439
610
|
}, [])
|
|
440
611
|
|
|
441
612
|
return (
|
|
442
|
-
<div style={tws('flex items-center gap-4')}>
|
|
443
|
-
<button style={tws('bg-blue-500 text-white px-4 py-2 rounded')}>
|
|
613
|
+
<div style={tws('flex items-center gap-4', true)}>
|
|
614
|
+
<button style={tws('bg-blue-500 text-white px-4 py-2 rounded-lg', true)}>
|
|
444
615
|
Click me
|
|
445
616
|
</button>
|
|
446
617
|
</div>
|
|
@@ -453,109 +624,148 @@ function App() {
|
|
|
453
624
|
```vue
|
|
454
625
|
<script setup>
|
|
455
626
|
import { tws } from 'tailwind-to-style'
|
|
456
|
-
|
|
457
|
-
const buttonStyle = tws('bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600')
|
|
627
|
+
const btnStyle = tws('bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600', true)
|
|
458
628
|
</script>
|
|
459
629
|
|
|
460
630
|
<template>
|
|
461
|
-
<button :style="
|
|
631
|
+
<button :style="btnStyle">Click me</button>
|
|
462
632
|
</template>
|
|
463
633
|
```
|
|
464
634
|
|
|
635
|
+
### Svelte
|
|
636
|
+
|
|
637
|
+
```svelte
|
|
638
|
+
<script>
|
|
639
|
+
import { tws } from 'tailwind-to-style'
|
|
640
|
+
const style = tws('bg-blue-500 text-white px-4 py-2 rounded-lg', true)
|
|
641
|
+
</script>
|
|
642
|
+
|
|
643
|
+
<button style={Object.entries(style).map(([k,v]) => `${k}:${v}`).join(';')}>
|
|
644
|
+
Click me
|
|
645
|
+
</button>
|
|
646
|
+
```
|
|
647
|
+
|
|
465
648
|
### Vanilla JS
|
|
466
649
|
|
|
467
650
|
```javascript
|
|
468
651
|
import { tws, twsx } from 'tailwind-to-style'
|
|
469
652
|
|
|
470
|
-
//
|
|
471
|
-
const
|
|
472
|
-
Object.assign(
|
|
473
|
-
button.textContent = 'Click me'
|
|
653
|
+
// Inline styles
|
|
654
|
+
const el = document.createElement('button')
|
|
655
|
+
Object.assign(el.style, tws('bg-blue-500 text-white px-4 py-2 rounded-lg', true))
|
|
474
656
|
|
|
475
657
|
// Inject global styles
|
|
476
|
-
|
|
477
|
-
'.card': 'bg-white p-6 rounded-lg shadow-md'
|
|
658
|
+
twsx({
|
|
659
|
+
'.card': 'bg-white p-6 rounded-lg shadow-md',
|
|
660
|
+
'.card:hover': 'shadow-xl',
|
|
478
661
|
})
|
|
479
|
-
document.head.appendChild(Object.assign(document.createElement('style'), {
|
|
480
|
-
textContent: css
|
|
481
|
-
}))
|
|
482
662
|
```
|
|
483
663
|
|
|
484
|
-
|
|
664
|
+
---
|
|
485
665
|
|
|
486
|
-
|
|
487
|
-
- **Small bundle** - ~12KB minified (vs 45KB in v2)
|
|
488
|
-
- **No build step** - Instant development workflow
|
|
489
|
-
- **Tree-shakeable** - Only import what you use
|
|
666
|
+
## Performance
|
|
490
667
|
|
|
491
|
-
|
|
668
|
+
v3.2.0 includes major performance optimizations:
|
|
492
669
|
|
|
493
|
-
|
|
670
|
+
- **Pre-compiled regex** — compiled once at module load, reused for every call
|
|
671
|
+
- **Multi-level LRU caching** — class resolution, CSS generation, config lookups
|
|
672
|
+
- **Bounded caches** — Maps capped at 5,000 entries, Sets at 10,000 to prevent memory leaks
|
|
673
|
+
- **`sheet.insertRule()` injection** — avoids full stylesheet reparsing on each call
|
|
674
|
+
- **FNV-1a hashing** — 100x faster than `JSON.stringify` for cache keys
|
|
494
675
|
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
|
|
676
|
+
```
|
|
677
|
+
Parse 10,000 classes:
|
|
678
|
+
Cold: ~12ms
|
|
679
|
+
Cached: ~0.12ms (100x faster)
|
|
680
|
+
|
|
681
|
+
Bundle sizes:
|
|
682
|
+
Full import: ~12KB minified
|
|
683
|
+
tws() only: ~3KB minified
|
|
684
|
+
twsx() only: ~6KB minified
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
**Performance utilities:**
|
|
688
|
+
|
|
689
|
+
```javascript
|
|
690
|
+
import { performanceUtils } from 'tailwind-to-style'
|
|
498
691
|
|
|
499
|
-
|
|
500
|
-
|
|
692
|
+
// View cache stats
|
|
693
|
+
performanceUtils.getStats()
|
|
501
694
|
|
|
502
|
-
|
|
503
|
-
|
|
695
|
+
// Clear all caches
|
|
696
|
+
performanceUtils.clearCaches()
|
|
504
697
|
|
|
505
|
-
|
|
506
|
-
|
|
698
|
+
// Enable performance logging
|
|
699
|
+
performanceUtils.enablePerformanceLogging(true)
|
|
507
700
|
```
|
|
508
701
|
|
|
509
|
-
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## Debugging & Logging
|
|
705
|
+
|
|
706
|
+
Logging is disabled by default. Enable via environment variable or programmatically:
|
|
707
|
+
|
|
708
|
+
```bash
|
|
709
|
+
TWSX_LOG_LEVEL=debug npm start # debug, info, warn, error, silent
|
|
710
|
+
```
|
|
510
711
|
|
|
511
712
|
```javascript
|
|
512
713
|
import { logger } from 'tailwind-to-style'
|
|
513
714
|
|
|
514
|
-
|
|
515
|
-
logger.setLevel('debug') // 'debug' | 'info' | 'warn' | 'error' | 'silent'
|
|
516
|
-
|
|
517
|
-
// Check current level
|
|
715
|
+
logger.setLevel('debug')
|
|
518
716
|
console.log(logger.getLevel()) // → 'debug'
|
|
519
717
|
```
|
|
520
718
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
719
|
+
| Level | Description |
|
|
720
|
+
|---|---|
|
|
721
|
+
| `debug` | Detailed processing info |
|
|
722
|
+
| `info` | General information |
|
|
723
|
+
| `warn` | Performance warnings |
|
|
724
|
+
| `error` | Errors only |
|
|
725
|
+
| `silent` | No logging (default) |
|
|
527
726
|
|
|
528
|
-
|
|
727
|
+
---
|
|
529
728
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
|
533
|
-
|
|
534
|
-
|
|
|
535
|
-
|
|
|
536
|
-
|
|
|
537
|
-
|
|
|
538
|
-
|
|
|
729
|
+
## Comparison
|
|
730
|
+
|
|
731
|
+
| Feature | tailwind-to-style | Tailwind CSS | CSS-in-JS | tailwind-variants |
|
|
732
|
+
|---|:---:|:---:|:---:|:---:|
|
|
733
|
+
| Build Step | None | Required | None | Required |
|
|
734
|
+
| Bundle Size | 3-12KB | ~80KB+ | 20-40KB | ~15KB |
|
|
735
|
+
| Runtime Styles | Yes | No | Yes | Partial |
|
|
736
|
+
| Full Tailwind Support | Yes | Yes | No | Classes only |
|
|
737
|
+
| SSR Support | Yes | Yes | Depends | Yes |
|
|
738
|
+
| Variant System | Built-in | No | No | Yes |
|
|
739
|
+
| Conditional Classes | `cx()` | No | No | `tv()` |
|
|
740
|
+
| SCSS-like Nesting | Yes | Plugins | Yes | No |
|
|
741
|
+
| @css Raw Injection | Yes | No | Yes | No |
|
|
742
|
+
| Framework Agnostic | Yes | Yes | Depends | Yes |
|
|
743
|
+
| Tree-Shaking | Yes | Partial | Yes | Yes |
|
|
744
|
+
| TypeScript Generics | Yes | Yes | Yes | Yes |
|
|
745
|
+
| Zero Dependencies | Yes | PostCSS | No | tailwind-merge |
|
|
539
746
|
|
|
540
|
-
|
|
747
|
+
---
|
|
748
|
+
|
|
749
|
+
## Migration from v2
|
|
541
750
|
|
|
542
|
-
See [MIGRATION.md](MIGRATION.md) for detailed
|
|
751
|
+
See [MIGRATION.md](MIGRATION.md) for the detailed guide from v2.x to v3.x.
|
|
543
752
|
|
|
544
753
|
**Quick summary:**
|
|
545
|
-
- ✅ `tws()` - No changes
|
|
546
|
-
- ✅ `twsx()` - No changes
|
|
547
|
-
- ✅ `configure()` - No changes
|
|
548
|
-
- ❌ `styled()`, `tv()` - Removed (use emotion/styled-components)
|
|
549
|
-
- ❌ `useTwsx()`, `TwsxProvider` - Removed (use `twsx()` directly)
|
|
550
|
-
- ❌ CLI tools & plugins - Removed (not needed for runtime library)
|
|
551
754
|
|
|
552
|
-
|
|
755
|
+
| Status | API |
|
|
756
|
+
|---|---|
|
|
757
|
+
| No changes | `tws()`, `twsx()`, `configure()` |
|
|
758
|
+
| New in v3.1 | `twsxVariants()` |
|
|
759
|
+
| New in v3.2 | `cx()`, SSR, tree-shakeable imports |
|
|
760
|
+
| Removed | `styled()`, `tv()`, `useTwsx()`, `TwsxProvider`, CLI tools |
|
|
761
|
+
|
|
762
|
+
---
|
|
553
763
|
|
|
554
|
-
|
|
764
|
+
## Contributing
|
|
555
765
|
|
|
556
|
-
|
|
766
|
+
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for architecture overview, testing guidelines, and build output docs.
|
|
557
767
|
|
|
558
|
-
|
|
768
|
+
---
|
|
559
769
|
|
|
560
770
|
## 💖 Support
|
|
561
771
|
|
|
@@ -565,4 +775,10 @@ If you find this library helpful, consider supporting:
|
|
|
565
775
|
|
|
566
776
|
---
|
|
567
777
|
|
|
568
|
-
|
|
778
|
+
## License
|
|
779
|
+
|
|
780
|
+
MIT © [Bigetion](https://github.com/Bigetion)
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
**v3.2.0** — [Changelog](CHANGELOG.md) · [Architecture](ARCHITECTURE.md) · [Migration Guide](MIGRATION.md)
|