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