tailwind-to-style 2.12.6 → 3.1.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 CHANGED
@@ -7,327 +7,243 @@
7
7
  [![npm downloads](https://img.shields.io/npm/dm/tailwind-to-style.svg)](https://www.npmjs.com/package/tailwind-to-style)
8
8
  [![license](https://img.shields.io/npm/l/tailwind-to-style.svg)](https://github.com/Bigetion/tailwind-to-style/blob/main/LICENSE)
9
9
 
10
- `tailwind-to-style` is a JavaScript library designed to convert Tailwind CSS utility classes into inline styles or JavaScript objects. This is especially useful when you need to dynamically apply styles to elements in frameworks like React, where inline styles or style objects are frequently used.
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
13
 
12
- The library exposes two main functions and a CLI tool:
14
+ ## ⚡ Why tailwind-to-style?
13
15
 
14
- 1. **`tws`**: Converts Tailwind CSS classes into inline CSS styles or JavaScript objects (JSON).
15
- 2. **`twsx`**: A more advanced function that allows you to define nested and complex styles similar to SCSS, including support for responsive design, state variants, grouping, and enhanced CSS capabilities.
16
- 3. **`twsx-cli`**: A command-line tool for generating CSS files from `twsx.*.js` files with watch mode support.
16
+ - **🚀 Zero Build Step** - No PostCSS, no compilation, just JavaScript
17
+ - **ðŸ“Ķ Framework Agnostic** - Works with React, Vue, Svelte, vanilla JS
18
+ - **ðŸŽĻ Full Tailwind Support** - All utilities, responsive, pseudo-states, arbitrary values
19
+ - **ðŸ”Ĩ SCSS-like Nesting** - Write complex nested styles with ease
20
+ - **⚙ïļ Customizable** - Extend theme with your colors, spacing, fonts
21
+ - **💊 TypeScript Support** - Full type definitions included
22
+ - **ðŸŠķ Lightweight** - ~12KB minified (70% smaller than v2)
17
23
 
18
- ## âœĻ What's New in v2.12.4
24
+ ## ðŸ“Ĩ Installation
19
25
 
20
- - **🏷ïļ Custom Classname Prefix**: Full control over styled component classnames
21
- - **Configurable Prefix**: Change from `twsx-` to any prefix (e.g., `myapp-`)
22
- - **Custom Separator**: Use `-`, `_`, `__` or any separator
23
- - **Flexible Hash Length**: Adjust uniqueness vs size (4-8 characters)
24
- - **Component Name Toggle**: Include/exclude component type in classname
25
- - **Per-Component Override**: Different naming for specific components
26
- - **Design System Ready**: Perfect for branded design systems
27
-
28
- **Example:**
29
- ```javascript
30
- // Global config
31
- configure({ styled: { prefix: 'myapp', separator: '_' }})
32
-
33
- const Button = styled('button', { base: 'px-4 py-2' })
34
- // Generates: myapp_button_a3k9x (instead of twsx-button-a3k9x2)
26
+ ```bash
27
+ npm install tailwind-to-style
35
28
  ```
36
29
 
37
- **[📖 See Custom Prefix Guide →](#custom-classname-prefix-configuration)** | **[ðŸ’ŧ Examples →](examples/custom-prefix.js)**
38
-
39
- ### Previous Updates (v2.12.0)
40
-
41
- - **🚀 Complete Optimization Suite**: Production-ready performance tools
42
- - **Bundle Analysis**: Analyze size, get recommendations, export reports
43
- - **Build-time Extraction**: Static CSS generation for faster loads
44
- - **Critical CSS**: Above-the-fold CSS extraction for instant renders
45
- - **CSS Purging**: Automatic removal of unused styles (tree-shaking)
46
- - **Advanced Caching**: Persistent cache with compression (localStorage/IndexedDB)
47
- - **Optimization Manager**: Unified API with presets (minimal/balanced/aggressive)
48
-
49
- - **📊 Performance Benefits**:
50
- - Up to 82% bundle size reduction
51
- - 75% faster initial load times
52
- - 76% faster time to interactive
53
- - Automatic CSS deduplication
54
- - Memory-efficient LRU caching
55
-
56
- **[📖 See Full Optimization Guide →](OPTIMIZATION_GUIDE.md)**
57
-
58
- ### Previous Updates (v2.11.0)
59
-
60
- - **ðŸŽĻ Styled Components System**: Create reusable components with `styled()` factory
61
- - Variant-based styling inspired by styled-components and twin.macro
62
- - Tag helpers: `styled.div()`, `styled.button()`, etc.
63
- - Pseudo-state support: hover, focus, active, disabled
64
- - Nested styles with SCSS-like syntax
65
- - Polymorphic "as" prop for component flexibility
66
- - Full TypeScript support with type inference
67
-
68
- - **🎭 Type-safe Variants**: Framework-agnostic `tv()` for design systems
69
- - Compound variants for complex conditions
70
- - Default variants support
71
- - Full TypeScript integration
72
- - Works with any framework or vanilla JS
73
- - `createVariants()` for batch variant creation
74
-
75
- ### Previous Updates (v2.10.5)
76
-
77
- - **🎎 Complete Animation System**: Full support for Tailwind animations and transitions
78
- - Built-in animations: `animate-spin`, `animate-ping`, `animate-pulse`, `animate-bounce`
79
- - Complete transition utilities with duration, delay, and easing controls
80
- - Custom animations via theme configuration
81
- - Keyframes system with built-in and custom support
82
-
83
- - **ðŸŽĻ Theme Customization**: Extend default theme with custom colors, spacing, and more!
84
- - Deep merge support for nested theme values
85
- - Works seamlessly with existing Tailwind utilities
86
- - Brand-specific design systems
87
-
88
- - **🔌 Plugin API**: Create custom utilities with `createPlugin()` and `createUtilityPlugin()`
89
- - Simple utility plugins for custom styles
90
- - Dynamic utilities with multiple values
91
- - Unlimited custom utility classes
92
-
93
- - **⚙ïļ Configuration System**: Use `configure()` to set up theme and plugins
94
- - Support for `tailwind-to-style.config.js`
95
- - Prefix support and core plugin control
96
- - Easy configuration management
97
-
98
- - **🚀 Infrastructure Improvements**:
99
- - Updated dependencies (ESLint 9, Jest 30, Rollup 4)
100
- - LRU Cache for better memory management
101
- - Configurable logger system (production-safe)
102
- - Event-based error handling
103
- - Complete TypeScript definitions
104
- - Node.js 18.x, 20.x, 22.x LTS support
105
-
106
- - **ðŸ“ą Responsive Selector Syntax**: Intuitive `'md:.title': 'text-lg'` format
107
- - **🐛 Enhanced @css Directive**: Perfect CSS variables and functions preservation
30
+ ## ðŸŽŊ Quick Start
108
31
 
109
- All changes are **backward compatible** - your existing code continues to work!
32
+ ### Simple Conversion with `tws()`
110
33
 
111
- ## Quick Start: v2.11.0+ Features
112
-
113
- ### Styled Components
34
+ Convert Tailwind classes to style objects:
114
35
 
115
36
  ```javascript
116
- import { styled } from 'tailwind-to-style/react'
37
+ import { tws } from 'tailwind-to-style'
117
38
 
118
- const Button = styled('button', {
119
- base: 'px-4 py-2 rounded-lg font-medium',
120
- variants: {
121
- color: {
122
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
123
- danger: 'bg-red-500 text-white hover:bg-red-600'
124
- }
125
- }
126
- })
39
+ const styles = tws('bg-blue-500 text-white p-4 rounded-lg hover:bg-blue-600')
40
+
41
+ // Use in React
42
+ <div style={styles}>Hello World</div>
127
43
 
128
- <Button color="primary">Click me</Button>
44
+ // Use in vanilla JS
45
+ element.style = Object.assign(element.style, styles)
129
46
  ```
130
47
 
131
- ### Type-safe Variants
48
+ ### Nested Styles with `twsx()`
49
+
50
+ Create complex styles with SCSS-like nesting:
132
51
 
133
52
  ```javascript
134
- import { tv } from 'tailwind-to-style'
53
+ import { twsx } from 'tailwind-to-style'
135
54
 
136
- const button = tv({
137
- base: 'px-4 py-2 rounded font-medium',
138
- variants: {
139
- color: {
140
- primary: 'bg-blue-500 text-white',
141
- secondary: 'bg-gray-500 text-white'
55
+ const css = twsx({
56
+ '.card': [
57
+ 'bg-white p-6 rounded-lg shadow-md',
58
+ {
59
+ '&:hover': 'shadow-xl transform scale-105',
60
+ '> .title': 'text-2xl font-bold text-gray-900 mb-2',
61
+ '> .description': 'text-gray-600 leading-relaxed',
62
+ '> .button': [
63
+ 'bg-blue-500 text-white px-4 py-2 rounded',
64
+ {
65
+ '&:hover': 'bg-blue-600',
66
+ '&:active': 'bg-blue-700'
67
+ }
68
+ ]
142
69
  }
70
+ ],
71
+
72
+ // Media queries at root level
73
+ '@media (max-width: 768px)': {
74
+ '.card': 'p-4',
75
+ '.card > .title': 'text-xl'
143
76
  }
144
77
  })
145
78
 
146
- const className = button({ color: 'primary' })
79
+ // Inject to document
80
+ const style = document.createElement('style')
81
+ style.textContent = css
82
+ document.head.appendChild(style)
147
83
  ```
148
84
 
149
- **See full documentation:** [Styled Components](#styled-components) | [React Integration](#react-integration)
150
-
151
- ## Installation
85
+ ## 📚 Core API
152
86
 
153
- ```bash
154
- npm install tailwind-to-style
155
- ```
156
-
157
- ## Quick Start: Optimization (v2.12.0+)
87
+ ### `tws(classes, options?)`
158
88
 
159
- Optimize your production bundle with powerful built-in tools:
89
+ Convert Tailwind classes to inline style object.
160
90
 
161
91
  ```javascript
162
- import { optimize, createOptimizationManager } from 'tailwind-to-style';
163
-
164
- // Quick API - Analyze bundle size
165
- const analysis = await optimize.analyzeBundle();
166
- console.log(`Bundle: ${analysis.totalSize} bytes, Gzip: ${analysis.gzipSize} bytes`);
167
-
168
- // Quick API - Purge unused CSS (82% reduction!)
169
- const { css, stats } = await optimize.purgeCSS({
170
- content: ['src/**/*.{js,jsx,ts,tsx}'],
171
- css: yourCSSString
172
- });
173
- console.log(`Saved ${stats.rulesRemoved} rules, ${((1 - stats.purgedSize / stats.originalSize) * 100).toFixed(1)}% reduction`);
174
-
175
- // Quick API - Extract critical CSS
176
- const critical = await optimize.extractCritical({
177
- html: yourHTMLString,
178
- minify: true
179
- });
180
-
181
- // OR use Optimization Manager with presets
182
- const optimizer = createOptimizationManager('aggressive'); // or 'balanced', 'minimal'
183
- await optimizer.initialize();
184
-
185
- const results = await optimizer.optimize(css, ['src/**/*.jsx']);
186
- console.log(`Optimized: ${results.stats.overall.savings}% size reduction`);
187
- optimizer.generateReport(); // Detailed analysis
188
- ```
189
-
190
- **Performance Benefits:**
191
- - 🚀 Up to 82% bundle size reduction
192
- - ⚡ 75% faster initial load times
193
- - ðŸ“Ķ Automatic CSS deduplication
194
- - ðŸ’ū Persistent caching with compression
92
+ import { tws } from 'tailwind-to-style'
195
93
 
196
- **[📖 Full Optimization Guide →](OPTIMIZATION_GUIDE.md)** | **[ðŸ’ŧ Examples →](examples/optimization.js)**
94
+ // Basic usage
95
+ const styles = tws('flex items-center gap-4')
96
+ // → { display: 'flex', alignItems: 'center', gap: '1rem' }
197
97
 
198
- ### Optional: Import Tailwind Preflight CSS
98
+ // Responsive classes
99
+ const styles = tws('text-sm md:text-base lg:text-lg')
199
100
 
200
- For best results and consistent styling, import Tailwind's preflight (base styles):
101
+ // Pseudo-states
102
+ const styles = tws('bg-blue-500 hover:bg-blue-600 focus:ring-2')
201
103
 
202
- ```javascript
203
- // React (in your main entry file)
204
- import 'tailwind-to-style/preflight.css'
205
- import { TwsxProvider } from 'tailwind-to-style'
104
+ // Arbitrary values
105
+ const styles = tws('w-[123px] text-[#abc] m-[1.5rem]')
206
106
 
207
- function App() {
208
- return <TwsxProvider>{/* your app */}</TwsxProvider>
209
- }
210
- ```
107
+ // Important modifier
108
+ const styles = tws('!bg-red-500')
211
109
 
212
- ```html
213
- <!-- HTML (in your index.html) -->
214
- <link rel="stylesheet" href="node_modules/tailwind-to-style/preflight.css">
110
+ // Return as JSON string
111
+ const json = tws('p-4 m-2', { format: 'json' })
112
+ // → '{"padding":"1rem","margin":"0.5rem"}'
215
113
  ```
216
114
 
217
- The preflight CSS provides Tailwind's base styles including:
218
- - Consistent box-sizing
219
- - Reset margins and paddings
220
- - Normalized form elements
221
- - Better default font rendering
222
-
223
- **Note:** If you're already using Tailwind CSS in your project, you don't need to import this.
115
+ ### `twsx(styleObject, options?)`
224
116
 
225
- ## React Integration
226
-
227
- ### Quick Start with React
117
+ Generate CSS from nested style definitions with Tailwind classes.
228
118
 
229
119
  ```javascript
230
- import { useTwsx, TwsxProvider } from 'tailwind-to-style'
120
+ import { twsx } from 'tailwind-to-style'
231
121
 
232
- // Theme configuration
233
- const config = {
234
- theme: {
235
- extend: {
236
- colors: {
237
- brand: { 500: '#3b82f6', 600: '#2563eb' }
238
- }
122
+ const css = twsx({
123
+ '.button': [
124
+ 'bg-blue-500 text-white px-6 py-3 rounded-lg font-medium transition-all',
125
+ {
126
+ '&:hover': 'bg-blue-600 transform scale-105',
127
+ '&:active': 'bg-blue-700 scale-95',
128
+ '&:disabled': 'bg-gray-400 opacity-50 cursor-not-allowed',
129
+ '&.large': 'px-8 py-4 text-lg',
130
+ '&.small': 'px-3 py-1.5 text-sm'
239
131
  }
132
+ ],
133
+
134
+ '.card': 'bg-white rounded-xl shadow-lg overflow-hidden',
135
+ '.card > .header': 'p-6 border-b border-gray-200',
136
+ '.card > .body': 'p-6',
137
+ '.card > .footer': 'p-6 bg-gray-50',
138
+
139
+ // Media queries at root level
140
+ '@media (max-width: 768px)': {
141
+ '.card': 'rounded-lg',
142
+ '.card > .header': 'p-4',
143
+ '.card > .body': 'p-4'
240
144
  }
241
- }
145
+ })
242
146
 
243
- function App() {
244
- return (
245
- <TwsxProvider config={config}>
246
- <MyComponent />
247
- </TwsxProvider>
248
- )
249
- }
147
+ // Options
148
+ const minified = twsx(styles, { minify: true })
149
+ const formatted = twsx(styles, { format: 'pretty' })
150
+ ```
250
151
 
251
- function MyComponent() {
252
- // Auto-inject CSS into document head
253
- useTwsx({
254
- '.card': [
255
- 'bg-brand-500 text-white p-6 rounded-lg',
256
- {
257
- '&:hover': 'bg-brand-600 transform scale-105',
258
- '.title': 'text-xl font-bold mb-2'
259
- }
260
- ]
261
- })
152
+ **Nesting Syntax:**
153
+ - `'&:hover'` - Pseudo-classes
154
+ - `'&.class'` - Modifiers
155
+ - `'> .child'` - Direct children
156
+ - `'.nested'` - Descendants
157
+ - `'@media ...'` - Media queries (root level only)
262
158
 
263
- return (
264
- <div className="card">
265
- <h2 className="title">Interactive Card</h2>
266
- <p>Hover me to see the effect!</p>
267
- </div>
268
- )
269
- }
270
- ```
159
+ ### `twsxVariants(className, config)`
271
160
 
272
- ### Import Options
161
+ Create variant-based component styles with automatic CSS generation. Similar to `tailwind-variants` but with auto-injection.
273
162
 
274
163
  ```javascript
275
- // Import from main package (recommended)
276
- import { useTwsx, TwsxProvider } from 'tailwind-to-style'
164
+ import { twsxVariants } from 'tailwind-to-style'
277
165
 
278
- // Or from React subpath
279
- import { useTwsx, TwsxProvider } from 'tailwind-to-style/react'
280
- ```
166
+ const btn = twsxVariants('.btn', {
167
+ base: 'px-4 py-2 rounded-lg font-medium transition-all',
168
+ variants: {
169
+ variant: {
170
+ solid: 'border-transparent',
171
+ outline: 'bg-transparent border-2',
172
+ ghost: 'bg-transparent',
173
+ },
174
+ color: {
175
+ primary: 'bg-blue-500 text-white hover:bg-blue-600',
176
+ danger: 'bg-red-500 text-white hover:bg-red-600',
177
+ },
178
+ size: {
179
+ sm: 'px-3 py-1.5 text-sm',
180
+ md: 'px-4 py-2 text-base',
181
+ lg: 'px-6 py-3 text-lg',
182
+ },
183
+ },
184
+ compoundVariants: [
185
+ { variant: 'outline', color: 'primary', class: 'border-blue-500 text-blue-600' },
186
+ { variant: 'outline', color: 'danger', class: 'border-red-500 text-red-600' },
187
+ ],
188
+ defaultVariants: { variant: 'solid', color: 'primary', size: 'md' }
189
+ })
281
190
 
282
- ### `useTwsx()` Hook
191
+ // Usage - returns class name string
192
+ btn() // "btn"
193
+ btn({ color: 'danger' }) // "btn btn-danger"
194
+ 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
+ ```
283
203
 
284
- The main React hook for component styling:
204
+ **Nested Selectors** - Style child elements:
285
205
 
286
206
  ```javascript
287
- import { useTwsx } from 'tailwind-to-style'
288
-
289
- function MyComponent() {
290
- // Auto-inject CSS (default behavior)
291
- useTwsx({
292
- '.button': [
293
- 'bg-blue-500 text-white px-6 py-3 rounded-lg font-medium',
294
- {
295
- '&:hover': 'bg-blue-600 transform scale-105',
296
- '&:active': 'bg-blue-700 scale-95',
297
- '&:disabled': 'bg-gray-400 cursor-not-allowed'
298
- }
299
- ]
300
- })
301
-
302
- // Get CSS without injection
303
- const css = useTwsx({
304
- '.card': 'bg-white p-6 rounded-lg shadow-md'
305
- }, { inject: false })
207
+ const alert = twsxVariants('.alert', {
208
+ base: 'p-4 rounded-lg border flex gap-3',
209
+ variants: {
210
+ status: {
211
+ info: 'bg-blue-50 text-blue-800',
212
+ error: 'bg-red-50 text-red-800',
213
+ },
214
+ },
215
+ defaultVariants: { status: 'info' },
216
+ nested: {
217
+ '.alert-icon': 'flex-shrink-0 mt-0.5',
218
+ '.alert-content': 'flex-1',
219
+ '.alert-dismiss': 'p-1 rounded hover:bg-black/10',
220
+ }
221
+ })
306
222
 
307
- return (
308
- <>
309
- <style>{css}</style>
310
- <div className="card">
311
- <button className="button">Click me</button>
312
- </div>
313
- </>
314
- )
315
- }
223
+ // Generates CSS:
224
+ // .alert .alert-icon { ... }
225
+ // .alert .alert-content { ... }
316
226
  ```
317
227
 
318
- ### `TwsxProvider` - Theme Configuration
228
+ **Class Naming Convention:**
229
+ - `.btn` = all defaults
230
+ - `.btn-outline` = outline variant (non-default)
231
+ - `.btn-outline-danger-lg` = multiple non-defaults
232
+
233
+ ### `configure(config)`
319
234
 
320
- Provide global theme configuration and custom colors:
235
+ Customize theme with your colors, spacing, fonts, and more.
321
236
 
322
237
  ```javascript
323
- import { TwsxProvider, useTwsx } from 'tailwind-to-style'
238
+ import { configure } from 'tailwind-to-style'
324
239
 
325
- const themeConfig = {
240
+ configure({
326
241
  theme: {
327
242
  extend: {
328
243
  colors: {
329
244
  brand: {
330
245
  50: '#eff6ff',
246
+ 100: '#dbeafe',
331
247
  500: '#3b82f6',
332
248
  600: '#2563eb',
333
249
  900: '#1e3a8a'
@@ -337,2120 +253,279 @@ const themeConfig = {
337
253
  spacing: {
338
254
  '128': '32rem',
339
255
  '144': '36rem'
256
+ },
257
+ fontFamily: {
258
+ sans: ['Inter', 'system-ui', 'sans-serif'],
259
+ mono: ['Fira Code', 'monospace']
340
260
  }
341
261
  }
342
262
  }
343
- }
344
-
345
- function App() {
346
- return (
347
- <TwsxProvider config={themeConfig}>
348
- <Header />
349
- <Main />
350
- <Footer />
351
- </TwsxProvider>
352
- )
353
- }
354
-
355
- function Header() {
356
- useTwsx({
357
- '.header': [
358
- 'bg-brand-500 text-white p-128', // Uses custom spacing
359
- {
360
- '.logo': 'text-accent font-bold text-2xl', // Uses custom color
361
- '&:hover': 'bg-brand-600'
362
- }
363
- ]
364
- })
263
+ })
365
264
 
366
- return (
367
- <header className="header">
368
- <div className="logo">My Brand</div>
369
- </header>
370
- )
371
- }
265
+ // Now use your custom theme
266
+ const styles = tws('bg-brand-500 text-brand-50 p-128 font-sans')
372
267
  ```
373
268
 
374
- ### Dynamic Styling with State
269
+ **Configuration File:**
375
270
 
376
- Create dynamic styles that respond to component state:
271
+ Create `tailwind-to-style.config.js` in your project root:
377
272
 
378
273
  ```javascript
379
- import { useTwsx } from 'tailwind-to-style'
380
- import { useState } from 'react'
381
-
382
- function ThemeToggle() {
383
- const [theme, setTheme] = useState('light')
384
-
385
- useTwsx({
386
- '.theme-container': [
387
- `bg-${theme === 'dark' ? 'gray-900' : 'white'} p-6 rounded-lg transition-all duration-300`,
388
- {
389
- [`&.${theme}`]: theme === 'dark'
390
- ? 'text-white border-gray-700'
391
- : 'text-gray-900 border-gray-200',
392
- '.theme-title': 'text-2xl font-bold mb-4',
393
- '.theme-button': [
394
- 'px-4 py-2 rounded-lg font-medium transition-colors',
395
- theme === 'dark'
396
- ? 'bg-yellow-500 text-gray-900 hover:bg-yellow-400'
397
- : 'bg-gray-800 text-white hover:bg-gray-700'
398
- ]
274
+ export default {
275
+ theme: {
276
+ extend: {
277
+ colors: {
278
+ primary: '#3b82f6',
279
+ secondary: '#10b981'
399
280
  }
400
- ]
401
- })
402
-
403
- return (
404
- <div className={`theme-container ${theme}`}>
405
- <h2 className="theme-title">🌓 Dynamic Theme</h2>
406
- <button
407
- className="theme-button"
408
- onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
409
- >
410
- Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
411
- </button>
412
- </div>
413
- )
281
+ }
282
+ }
414
283
  }
415
284
  ```
416
285
 
417
- ### Available React Hooks
286
+ ## ðŸŽĻ Preflight CSS (Base Styles)
287
+
288
+ For best results, import Tailwind's preflight (base styles):
418
289
 
419
290
  ```javascript
420
- import {
421
- useTwsx, // Main hook for styling
422
- TwsxProvider, // Context provider
423
- useTwsxContext, // Access provider context
424
- useTwsxConfig, // Get current config
425
- useUpdateTwsxConfig // Update config
426
- } from 'tailwind-to-style'
427
-
428
- // Example usage
429
- function ConfigAwareComponent() {
430
- const { config, isConfigured } = useTwsxConfig()
431
- const updateConfig = useUpdateTwsxConfig()
432
-
433
- if (!isConfigured) {
434
- return <div>Loading theme...</div>
435
- }
436
-
437
- return (
438
- <div>
439
- <p>Current theme: {config.theme?.extend?.colors?.brand ? 'Custom' : 'Default'}</p>
440
- <button onClick={() => updateConfig({
441
- theme: { extend: { colors: { brand: { 500: '#ef4444' } } } }
442
- })}>
443
- Change Brand Color
444
- </button>
445
- </div>
446
- )
447
- }
291
+ // In your main entry file
292
+ import 'tailwind-to-style/preflight.css'
293
+ ```
294
+
295
+ ```html
296
+ <!-- Or in HTML -->
297
+ <link rel="stylesheet" href="node_modules/tailwind-to-style/preflight.css">
448
298
  ```
449
299
 
450
- ## Styled Components
300
+ The preflight CSS provides:
301
+ - Consistent box-sizing
302
+ - Reset margins and paddings
303
+ - Normalized form elements
304
+ - Better default font rendering
451
305
 
452
- **New in v2.11.0** - Create reusable, variant-based components inspired by styled-components and tailwind-variants.
306
+ **Note:** Skip this if you're already using Tailwind CSS in your project.
453
307
 
454
- ### Key Features
308
+ ## ðŸ’Ą Use Cases
455
309
 
456
- - ⚡ **Deterministic Class Names**: Hash-based naming ensures consistent class names across renders and SSR
457
- - 🚀 **Optimized CSS Injection**: Global cache prevents duplicate styles, single `<style>` tag for better performance
458
- - ðŸŽŊ **Type-safe Variants**: Full TypeScript support with automatic type inference
459
- - 🔄 **SSR-Compatible**: Same class names on server and client, no hydration mismatches
460
- - ðŸ“Ķ **Zero Runtime Overhead**: Styles are generated once and cached efficiently
310
+ ### 1. Dynamic Styling
461
311
 
462
- ### Basic Usage
312
+ Generate styles from user input or runtime data:
463
313
 
464
314
  ```javascript
465
- import { styled } from 'tailwind-to-style/react'
466
-
467
- const Button = styled('button', {
468
- base: 'px-4 py-2 rounded-lg font-medium transition-all',
469
- variants: {
470
- color: {
471
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
472
- secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
473
- danger: 'bg-red-500 text-white hover:bg-red-600'
474
- },
475
- size: {
476
- sm: 'text-sm px-3 py-1.5',
477
- md: 'text-base px-4 py-2',
478
- lg: 'text-lg px-6 py-3'
479
- },
480
- outlined: {
481
- true: 'bg-transparent border-2'
482
- }
483
- },
484
- defaultVariants: {
485
- color: 'primary',
486
- size: 'md'
487
- }
488
- })
315
+ import { tws } from 'tailwind-to-style'
489
316
 
490
- // Usage
491
- function App() {
492
- return (
493
- <>
494
- <Button>Default Button</Button>
495
- <Button color="secondary" size="lg">Large Secondary</Button>
496
- <Button color="danger" outlined>Outlined Danger</Button>
497
- </>
498
- )
317
+ function UserCard({ user }) {
318
+ const styles = tws(`bg-${user.color}-500 p-4 rounded-lg`)
319
+ return <div style={styles}>{user.name}</div>
499
320
  }
500
321
  ```
501
322
 
502
- ### Tag Helpers
323
+ ### 2. Email Templates
503
324
 
504
- Convenient helpers for common HTML elements:
325
+ Generate inline styles for email HTML:
505
326
 
506
327
  ```javascript
507
- import { styled } from 'tailwind-to-style/react'
508
-
509
- const Container = styled.div({
510
- base: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8'
511
- })
512
-
513
- const Title = styled.h1({
514
- base: 'text-4xl font-bold text-gray-900',
515
- variants: {
516
- centered: {
517
- true: 'text-center'
518
- }
519
- }
520
- })
521
-
522
- const Card = styled.article({
523
- base: 'bg-white rounded-lg shadow-md p-6',
524
- hover: 'shadow-xl transform scale-105',
525
- active: 'shadow-lg scale-100'
526
- })
328
+ import { tws } from 'tailwind-to-style'
527
329
 
528
- function HomePage() {
529
- return (
530
- <Container>
531
- <Title centered>Welcome</Title>
532
- <Card>
533
- <p>This card has hover effects!</p>
534
- </Card>
535
- </Container>
536
- )
537
- }
330
+ const emailHTML = `
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
+ `
538
337
  ```
539
338
 
540
- **Available tag helpers**: `div`, `span`, `p`, `a`, `button`, `input`, `label`, `form`, `section`, `article`, `header`, `footer`, `nav`, `main`, `aside`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `ul`, `ol`, `li`, `img`, `video`
541
-
542
- ### Pseudo-state Variants
543
-
544
- Define styles for hover, focus, active, and disabled states:
339
+ ### 3. CSS-in-JS Alternative
545
340
 
546
341
  ```javascript
547
- const Input = styled.input({
548
- base: 'w-full px-4 py-2 border border-gray-300 rounded-lg transition-all',
549
- focus: 'border-blue-500 outline-none ring-2 ring-blue-200',
550
- disabled: 'bg-gray-100 cursor-not-allowed opacity-60',
551
- variants: {
552
- error: {
553
- true: 'border-red-500 focus:border-red-600 focus:ring-red-200'
554
- }
555
- }
556
- })
342
+ import { twsx } from 'tailwind-to-style'
557
343
 
558
- const LinkButton = styled.a({
559
- base: 'inline-block px-6 py-3 rounded-lg font-semibold',
560
- hover: 'transform scale-105',
561
- active: 'scale-95',
562
- focus: 'outline-none ring-4 ring-blue-300',
563
- variants: {
564
- variant: {
565
- solid: 'bg-blue-600 text-white',
566
- ghost: 'bg-transparent text-blue-600 border border-blue-600'
344
+ const styles = twsx({
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'
567
351
  }
568
- }
352
+ ]
569
353
  })
570
354
 
571
- // Usage
572
- <Input placeholder="Enter email" />
573
- <Input error placeholder="Invalid email" disabled />
574
- <LinkButton href="/signup" variant="solid">Sign Up</LinkButton>
355
+ // Inject once at app startup
356
+ document.head.appendChild(Object.assign(document.createElement('style'), {
357
+ textContent: styles
358
+ }))
575
359
  ```
576
360
 
577
- ### Nested Styles (SCSS-like)
578
-
579
- Create complex components with nested selectors:
361
+ ### 4. Component Library Styling
580
362
 
581
363
  ```javascript
582
- const Card = styled.div({
583
- base: 'bg-white rounded-lg shadow-md p-6',
584
- nested: {
585
- '.card-header': [
586
- 'border-b border-gray-200 pb-4 mb-4',
587
- {
588
- '.card-title': 'text-2xl font-bold text-gray-900',
589
- '.card-subtitle': 'text-sm text-gray-500 mt-1'
590
- }
591
- ],
592
- '.card-body': 'text-gray-700 leading-relaxed',
593
- '.card-footer': [
594
- 'border-t border-gray-200 pt-4 mt-4 flex justify-end gap-2',
595
- {
596
- 'button': 'px-4 py-2 rounded-lg transition-colors',
597
- 'button.primary': 'bg-blue-500 text-white hover:bg-blue-600',
598
- 'button.secondary': 'bg-gray-200 text-gray-800 hover:bg-gray-300'
599
- }
600
- ]
601
- }
602
- })
603
-
604
- // Usage
605
- function ProfileCard() {
606
- return (
607
- <Card>
608
- <div className="card-header">
609
- <h2 className="card-title">John Doe</h2>
610
- <p className="card-subtitle">Software Engineer</p>
611
- </div>
612
- <div className="card-body">
613
- Passionate developer with 10 years of experience...
614
- </div>
615
- <div className="card-footer">
616
- <button className="secondary">Cancel</button>
617
- <button className="primary">Save</button>
618
- </div>
619
- </Card>
620
- )
621
- }
622
- ```
623
-
624
- ### Compound Variants
625
-
626
- Apply styles based on multiple variant combinations:
364
+ import { twsx } from 'tailwind-to-style'
627
365
 
628
- ```javascript
629
- const Button = styled('button', {
630
- base: 'px-4 py-2 rounded-lg font-medium',
631
- variants: {
632
- color: {
633
- primary: 'bg-blue-500 text-white',
634
- secondary: 'bg-gray-500 text-white'
635
- },
636
- size: {
637
- sm: 'text-sm',
638
- lg: 'text-lg'
639
- },
640
- outlined: {
641
- true: 'bg-transparent border-2'
642
- }
643
- },
644
- compoundVariants: [
645
- {
646
- color: 'primary',
647
- outlined: true,
648
- class: 'border-blue-500 text-blue-500 hover:bg-blue-50'
649
- },
650
- {
651
- color: 'secondary',
652
- outlined: true,
653
- class: 'border-gray-500 text-gray-500 hover:bg-gray-50'
654
- },
366
+ export const buttonStyles = twsx({
367
+ '.btn': [
368
+ 'px-4 py-2 rounded-lg font-medium transition-colors',
655
369
  {
656
- size: 'lg',
657
- outlined: true,
658
- class: 'border-4' // Larger borders for large outlined buttons
370
+ '&.btn-primary': 'bg-blue-500 text-white hover:bg-blue-600',
371
+ '&.btn-secondary': 'bg-gray-200 text-gray-900 hover:bg-gray-300',
372
+ '&.btn-lg': 'px-6 py-3 text-lg',
373
+ '&.btn-sm': 'px-2 py-1 text-sm'
659
374
  }
660
375
  ]
661
376
  })
662
-
663
- // Usage
664
- <Button color="primary" outlined>Outlined Primary</Button>
665
- <Button color="secondary" size="lg" outlined>Large Outlined</Button>
666
377
  ```
667
378
 
668
- ### Polymorphic "as" Prop
379
+ ## 🔧 Advanced Features
669
380
 
670
- Change the underlying element while keeping styles:
381
+ ### Responsive Design
671
382
 
672
- ```javascript
673
- const Button = styled('button', {
674
- base: 'px-4 py-2 rounded-lg bg-blue-500 text-white font-medium'
675
- })
383
+ All Tailwind breakpoints work out of the box:
676
384
 
677
- function Navigation() {
678
- return (
679
- <>
680
- {/* Renders as <button> */}
681
- <Button onClick={() => alert('Clicked!')}>
682
- Click Me
683
- </Button>
684
-
685
- {/* Renders as <a> with same styles */}
686
- <Button as="a" href="/signup">
687
- Sign Up
688
- </Button>
689
-
690
- {/* Renders as custom component */}
691
- <Button as={Link} to="/dashboard">
692
- Dashboard
693
- </Button>
694
- </>
695
- )
696
- }
385
+ ```javascript
386
+ const styles = tws('text-sm sm:text-base md:text-lg lg:text-xl xl:text-2xl')
697
387
  ```
698
388
 
699
- ### Extending Styled Components
389
+ ### Arbitrary Values
700
390
 
701
- Extend existing styled components:
391
+ Use any custom value with square brackets:
702
392
 
703
393
  ```javascript
704
- const BaseButton = styled('button', {
705
- base: 'px-4 py-2 rounded-lg font-medium transition-colors'
706
- })
394
+ const styles = tws(`
395
+ w-[123px]
396
+ h-[calc(100vh-64px)]
397
+ text-[#abc123]
398
+ bg-[url('/image.png')]
399
+ grid-cols-[1fr,2fr,1fr]
400
+ `)
401
+ ```
707
402
 
708
- const PrimaryButton = styled(BaseButton, {
709
- base: 'bg-blue-500 text-white hover:bg-blue-600'
710
- })
403
+ ### State Variants
711
404
 
712
- const IconButton = styled(PrimaryButton, {
713
- base: 'flex items-center gap-2',
714
- nested: {
715
- 'svg': 'w-5 h-5'
716
- }
717
- })
405
+ ```javascript
406
+ const styles = tws(`
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
+ `)
414
+ ```
718
415
 
719
- // Usage
720
- <IconButton>
721
- <svg>...</svg>
722
- Save Changes
723
- </IconButton>
416
+ ### Important Modifier
417
+
418
+ ```javascript
419
+ const styles = tws('!bg-red-500 !text-white')
420
+ // Forces these styles to take precedence
724
421
  ```
725
422
 
726
- ### Type-safe Variants with `tv()`
423
+ ## 🎭 Framework Integration
727
424
 
728
- Framework-agnostic variant system for design systems:
425
+ ### React
729
426
 
730
427
  ```javascript
731
- import { tv } from 'tailwind-to-style'
428
+ import { tws, twsx } from 'tailwind-to-style'
429
+ import { useEffect } from 'react'
732
430
 
733
- // Create a variant function
734
- const buttonVariants = tv({
735
- base: 'px-4 py-2 rounded-lg font-medium transition-all',
736
- variants: {
737
- intent: {
738
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
739
- secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
740
- danger: 'bg-red-500 text-white hover:bg-red-600'
741
- },
742
- size: {
743
- sm: 'text-sm px-3 py-1.5',
744
- md: 'text-base px-4 py-2',
745
- lg: 'text-lg px-6 py-3'
746
- },
747
- fullWidth: {
748
- true: 'w-full'
749
- }
750
- },
751
- compoundVariants: [
752
- {
753
- intent: 'primary',
754
- size: 'lg',
755
- class: 'shadow-lg hover:shadow-xl'
756
- }
757
- ],
758
- defaultVariants: {
759
- intent: 'primary',
760
- size: 'md'
761
- }
762
- })
431
+ function App() {
432
+ useEffect(() => {
433
+ const css = twsx({
434
+ '.custom': 'bg-blue-500 text-white p-4'
435
+ })
436
+ const style = document.createElement('style')
437
+ style.textContent = css
438
+ document.head.appendChild(style)
439
+ }, [])
763
440
 
764
- // Use in React
765
- function Button({ intent, size, fullWidth, children, ...props }) {
766
441
  return (
767
- <button
768
- className={buttonVariants({ intent, size, fullWidth })}
769
- {...props}
770
- >
771
- {children}
772
- </button>
442
+ <div style={tws('flex items-center gap-4')}>
443
+ <button style={tws('bg-blue-500 text-white px-4 py-2 rounded')}>
444
+ Click me
445
+ </button>
446
+ </div>
773
447
  )
774
448
  }
449
+ ```
775
450
 
776
- // Use in vanilla JS
777
- const className = buttonVariants({ intent: 'danger', size: 'lg' })
778
- document.querySelector('.my-button').className = className
451
+ ### Vue
452
+
453
+ ```vue
454
+ <script setup>
455
+ 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')
458
+ </script>
779
459
 
780
- // Use in Vue
781
460
  <template>
782
- <button :class="buttonVariants({ intent: 'primary', fullWidth: true })">
783
- Click me
784
- </button>
461
+ <button :style="buttonStyle">Click me</button>
785
462
  </template>
786
463
  ```
787
464
 
788
- ### Custom Classname Prefix Configuration
465
+ ### Vanilla JS
789
466
 
790
- **New in v2.12.4** - Customize how styled components generate classnames with configurable prefix, separator, and naming options.
791
-
792
- #### Global Configuration
467
+ ```javascript
468
+ import { tws, twsx } from 'tailwind-to-style'
793
469
 
794
- Set global defaults for all styled components:
470
+ // Create element with styles
471
+ const button = document.createElement('button')
472
+ Object.assign(button.style, tws('bg-blue-500 text-white px-4 py-2 rounded'))
473
+ button.textContent = 'Click me'
795
474
 
796
- ```javascript
797
- import { configure } from 'tailwind-to-style'
798
-
799
- configure({
800
- styled: {
801
- prefix: 'myapp', // Default: 'twsx'
802
- separator: '_', // Default: '-'
803
- hashLength: 5, // Default: 6
804
- includeComponentName: true // Default: true
805
- }
806
- })
807
-
808
- const Button = styled('button', {
809
- base: 'px-4 py-2 rounded-lg'
810
- })
811
- // Generates: myapp_button_a3k9x (instead of twsx-button-a3k9x2)
812
- // Variants: myapp_color_primary (instead of twsx-color-primary)
813
- ```
814
-
815
- #### Per-Component Override
816
-
817
- Override naming for specific components:
818
-
819
- ```javascript
820
- const CustomButton = styled('button',
821
- {
822
- base: 'px-4 py-2 rounded-lg',
823
- variants: {
824
- variant: {
825
- solid: 'bg-blue-500',
826
- outline: 'border border-blue-500'
827
- }
828
- }
829
- },
830
- {
831
- // Component-specific naming options
832
- prefix: 'btn',
833
- separator: '-',
834
- hashLength: 8,
835
- includeComponentName: false
836
- }
837
- )
838
- // Generates: btn-a3k9x2f1 (no component type)
839
- // Variants: btn-variant-solid
840
- ```
841
-
842
- #### Use Cases
843
-
844
- **1. Brand-specific Prefix:**
845
- ```javascript
846
- configure({ styled: { prefix: 'shopify' }})
847
- // shopify-button-a3k9x2
848
- ```
849
-
850
- **2. Minimal Classnames:**
851
- ```javascript
852
- configure({
853
- styled: {
854
- prefix: 'c',
855
- separator: '',
856
- hashLength: 4,
857
- includeComponentName: false
858
- }
859
- })
860
- // c1a2b (super compact!)
861
- ```
862
-
863
- **3. Monorepo Isolation:**
864
- ```javascript
865
- // Admin app
866
- configure({ styled: { prefix: 'admin' }})
867
- // admin-button-xxx
868
-
869
- // Customer portal
870
- configure({ styled: { prefix: 'portal' }})
871
- // portal-button-yyy
872
- ```
873
-
874
- **4. BEM-like Convention:**
875
- ```javascript
876
- configure({ styled: { separator: '__' }})
877
- // twsx__button__a3k9x2
878
- ```
879
-
880
- **5. Design System:**
881
- ```javascript
882
- configure({ styled: { prefix: 'ds' }})
883
- const Button = styled('button', config)
884
- const Card = styled('div', config)
885
- // ds-button-a3k9x2, ds-card-f8d2k1
886
- ```
887
-
888
- #### HTML Output Examples
889
-
890
- ```html
891
- <!-- Default (prefix: 'twsx', separator: '-') -->
892
- <button class="twsx-button-a3k9x2 twsx-color-primary">Click</button>
893
-
894
- <!-- Custom (prefix: 'myapp', separator: '_') -->
895
- <button class="myapp_button_a3k9 myapp_color_primary">Click</button>
896
-
897
- <!-- Minimal (prefix: 'c', no component name) -->
898
- <button class="c-1a2b c-color-primary">Click</button>
899
-
900
- <!-- BEM-like (separator: '__') -->
901
- <button class="twsx__button__a3k9x2 twsx__color__primary">Click</button>
902
- ```
903
-
904
- **[📖 Full Example →](examples/custom-prefix.js)**
905
-
906
- ### Batch Variant Creation
907
-
908
- Create multiple variant functions at once:
909
-
910
- ```javascript
911
- import { createVariants } from 'tailwind-to-style'
912
-
913
- const components = createVariants({
914
- button: {
915
- base: 'px-4 py-2 rounded font-medium',
916
- variants: {
917
- color: {
918
- primary: 'bg-blue-500 text-white',
919
- secondary: 'bg-gray-500 text-white'
920
- }
921
- }
922
- },
923
- badge: {
924
- base: 'px-2 py-1 text-xs rounded-full font-semibold',
925
- variants: {
926
- color: {
927
- success: 'bg-green-100 text-green-800',
928
- error: 'bg-red-100 text-red-800',
929
- warning: 'bg-yellow-100 text-yellow-800'
930
- }
931
- }
932
- },
933
- input: {
934
- base: 'w-full px-3 py-2 border rounded',
935
- variants: {
936
- error: {
937
- true: 'border-red-500',
938
- false: 'border-gray-300'
939
- }
940
- }
941
- }
942
- })
943
-
944
- // Use the variants
945
- const buttonClass = components.button({ color: 'primary' })
946
- const badgeClass = components.badge({ color: 'success' })
947
- const inputClass = components.input({ error: true })
948
- ```
949
-
950
- ### TypeScript Support
951
-
952
- Full type inference for variants and props:
953
-
954
- ```typescript
955
- import { styled, tv } from 'tailwind-to-style/react'
956
- import type { StyledProps } from 'tailwind-to-style/react'
957
-
958
- // Styled components have inferred types
959
- const Button = styled('button', {
960
- variants: {
961
- color: {
962
- primary: 'bg-blue-500',
963
- secondary: 'bg-gray-500'
964
- },
965
- size: {
966
- sm: 'text-sm',
967
- lg: 'text-lg'
968
- }
969
- }
970
- })
971
-
972
- // Props are fully typed
973
- function App() {
974
- return (
975
- <>
976
- <Button color="primary" size="lg">Typed!</Button>
977
- {/* @ts-expect-error - invalid variant */}
978
- <Button color="invalid">Error</Button>
979
- </>
980
- )
981
- }
982
-
983
- // Extract prop types
984
- type ButtonProps = StyledProps<typeof Button>
985
- // { color?: 'primary' | 'secondary', size?: 'sm' | 'lg', as?: any, ... }
986
-
987
- // tv() also has full type inference
988
- const cardVariants = tv({
989
- variants: {
990
- elevated: {
991
- true: 'shadow-lg',
992
- false: 'shadow-none'
993
- }
994
- }
995
- })
996
-
997
- // Type-safe variant props
998
- const className = cardVariants({ elevated: true }) // ✅
999
- const invalid = cardVariants({ elevated: 'yes' }) // ❌ Type error
1000
- ```
1001
-
1002
- ### Performance & Class Naming
1003
-
1004
- #### Deterministic Hash-based Class Names
1005
-
1006
- `styled()` components generate **deterministic class names** based on the component's configuration. This ensures:
1007
-
1008
- - **Stability**: Same config = same class name across all renders
1009
- - **SSR Compatibility**: Server and client generate identical class names, preventing hydration mismatches
1010
- - **Predictability**: Class names are consistent across environments and builds
1011
-
1012
- ```javascript
1013
- const Button = styled('button', {
1014
- base: 'px-4 py-2 rounded bg-blue-500'
1015
- })
1016
- // Generates: twsx-button-a1b2c3 (deterministic hash)
1017
- ```
1018
-
1019
- #### Optimized CSS Injection
1020
-
1021
- The library uses a **global CSS cache** with hash-based deduplication:
1022
-
1023
- - **Single Style Tag**: All component styles are injected into one `<style data-twsx-global>` tag
1024
- - **No Duplicate CSS**: Same styles are cached and reused across components
1025
- - **Efficient Updates**: Only new styles are added, existing styles are preserved
1026
- - **Memory Efficient**: CSS content hashing prevents redundant injections
1027
-
1028
- ```javascript
1029
- // Multiple instances share the same cached styles
1030
- function App() {
1031
- return (
1032
- <>
1033
- <Button>First</Button> {/* Injects CSS */}
1034
- <Button>Second</Button> {/* Reuses cached CSS */}
1035
- <Button>Third</Button> {/* Reuses cached CSS */}
1036
- </>
1037
- )
1038
- }
1039
- ```
1040
-
1041
- #### Best Practices
1042
-
1043
- 1. **Define components outside render** - Component definitions should be at module level:
1044
- ```javascript
1045
- // ✅ Good - defined once at module level
1046
- const Button = styled('button', { base: 'px-4 py-2' })
1047
-
1048
- function App() {
1049
- return <Button>Click</Button>
1050
- }
1051
-
1052
- // ❌ Bad - redefined on every render
1053
- function App() {
1054
- const Button = styled('button', { base: 'px-4 py-2' })
1055
- return <Button>Click</Button>
1056
- }
1057
- ```
1058
-
1059
- 2. **Use `tv()` for dynamic variants** - When you need runtime flexibility:
1060
- ```javascript
1061
- const buttonVariants = tv({
1062
- variants: { color: { primary: '...', secondary: '...' } }
475
+ // Inject global styles
476
+ const css = twsx({
477
+ '.card': 'bg-white p-6 rounded-lg shadow-md'
1063
478
  })
1064
-
1065
- function DynamicButton({ color }) {
1066
- return <button className={buttonVariants({ color })}>Click</button>
1067
- }
1068
- ```
1069
-
1070
- 3. **SSR Considerations** - Class names are deterministic, ensuring proper hydration:
1071
- ```javascript
1072
- // Server renders: <button class="twsx-button-a1b2c3">
1073
- // Client hydrates: <button class="twsx-button-a1b2c3"> ✅ No mismatch!
1074
- ```
1075
-
1076
-
1077
-
1078
- ### 1. `tws`
1079
-
1080
- The `tws` function is designed to convert Tailwind CSS utility classes into either **inline CSS** or **JSON style objects**. This makes it particularly useful for applying styles dynamically in React or similar frameworks where inline styles or style objects are often needed.
1081
-
1082
- #### Features of `tws`:
1083
-
1084
- - Converts Tailwind utility classes into **inline CSS** or **JSON style objects**.
1085
-
1086
- #### Usage
1087
-
1088
- ```javascript
1089
- import { tws } from "tailwind-to-style";
1090
-
1091
- // Convert Tailwind classes to inline CSS
1092
- const styleInline = tws("bg-white mx-auto");
1093
- // Output: background-color:rgba(255, 255, 255, 1); margin-left:auto; margin-right:auto;
1094
-
1095
- // Convert Tailwind classes to JSON style object
1096
- const styleJSON = tws("bg-white mx-auto", 1);
1097
- // Output: { backgroundColor: 'rgba(255, 255, 255, 1)', marginLeft: 'auto', marginRight: 'auto' }
1098
- ```
1099
-
1100
- - **First argument**: The string of Tailwind classes to convert.
1101
- - **Second argument (optional)**: Pass `1` to get the result as a JSON object (default is inline CSS when omitted).
1102
-
1103
- #### Example in React:
1104
-
1105
- ```javascript
1106
- import React from "react";
1107
- import { tws } from "tailwind-to-style";
1108
-
1109
- const App = () => {
1110
- return (
1111
- <div style={tws("text-red-500 bg-blue-200 p-4", 1)}>
1112
- Hello, this is styled using tailwind-to-style
1113
- </div>
1114
- );
1115
- };
1116
-
1117
- export default App;
1118
- ```
1119
-
1120
- This will apply the Tailwind classes directly as inline styles in the React component.
1121
-
1122
- ## Advanced Features (v2.10.0+)
1123
-
1124
- ### Logger Configuration
1125
-
1126
- Control logging behavior for production environments:
1127
-
1128
- ```javascript
1129
- import { logger } from "tailwind-to-style";
1130
-
1131
- // Set log level (debug, info, warn, error, silent)
1132
- logger.setLevel('error'); // Only show errors in production
1133
-
1134
- // Default is 'warn' in development, 'error' in production
1135
- ```
1136
-
1137
- ### Error Handling
1138
-
1139
- Subscribe to errors for monitoring and debugging:
1140
-
1141
- ```javascript
1142
- import { onError, TwsError } from "tailwind-to-style";
1143
-
1144
- // Subscribe to errors
1145
- const unsubscribe = onError((error) => {
1146
- console.log(error.message);
1147
- console.log(error.context); // Additional context
1148
- console.log(error.timestamp); // When it occurred
1149
-
1150
- // Send to error tracking service
1151
- // Sentry.captureException(error);
1152
- });
1153
-
1154
- // Unsubscribe when done
1155
- unsubscribe();
1156
- ```
1157
-
1158
- ### Cache Management
1159
-
1160
- For testing or memory management:
1161
-
1162
- ```javascript
1163
- import { getTailwindCache, resetTailwindCache } from "tailwind-to-style";
1164
-
1165
- // Get cache instance
1166
- const cache = getTailwindCache();
1167
-
1168
- // Check if initialized
1169
- if (cache.isInitialized()) {
1170
- console.log("Cache is ready");
1171
- }
1172
-
1173
- // Reset cache (useful for testing)
1174
- resetTailwindCache();
1175
- ```
1176
-
1177
- ### Custom Logger Instance
1178
-
1179
- Create your own logger with custom settings:
1180
-
1181
- ```javascript
1182
- import { Logger } from "tailwind-to-style";
1183
-
1184
- const customLogger = new Logger('debug');
1185
- customLogger.debug('Custom message');
1186
- customLogger.setLevel('silent'); // Disable all logging
1187
- ```
1188
-
1189
- ## Animations & Transitions (v2.10.0+)
1190
-
1191
- Full support for Tailwind CSS animations and transitions!
1192
-
1193
- ### Built-in Animations
1194
-
1195
- ```javascript
1196
- import { tws } from "tailwind-to-style";
1197
-
1198
- // Spin animation (loading spinners)
1199
- const spinner = tws("animate-spin", 1);
1200
- // { animation: "spin 1s linear infinite" }
1201
-
1202
- // Ping animation (notification badges)
1203
- const badge = tws("animate-ping", 1);
1204
- // { animation: "ping 1s cubic-bezier(0, 0, 0.2, 1) infinite" }
1205
-
1206
- // Pulse animation (breathing effect)
1207
- const pulse = tws("animate-pulse", 1);
1208
- // { animation: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite" }
1209
-
1210
- // Bounce animation
1211
- const bounce = tws("animate-bounce", 1);
1212
- // { animation: "bounce 1s infinite" }
1213
-
1214
- // Disable animation
1215
- const none = tws("animate-none", 1);
1216
- // { animation: "none" }
1217
- ```
1218
-
1219
- ### Transition Utilities
1220
-
1221
- ```javascript
1222
- // Basic transition
1223
- const button = tws("transition duration-300 ease-in-out", 1);
1224
- // {
1225
- // transitionProperty: "color, background-color, border-color, ...",
1226
- // transitionDuration: "300ms",
1227
- // transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)"
1228
- // }
1229
-
1230
- // Transition specific properties
1231
- tws("transition-colors", 1); // Only colors
1232
- tws("transition-opacity", 1); // Only opacity
1233
- tws("transition-shadow", 1); // Only box-shadow
1234
- tws("transition-transform", 1); // Only transform
1235
- tws("transition-all", 1); // All properties
1236
-
1237
- // Duration
1238
- tws("duration-75", 1); // 75ms
1239
- tws("duration-150", 1); // 150ms
1240
- tws("duration-300", 1); // 300ms
1241
- tws("duration-500", 1); // 500ms
1242
- tws("duration-1000", 1); // 1000ms
1243
-
1244
- // Timing functions
1245
- tws("ease-linear", 1); // linear
1246
- tws("ease-in", 1); // cubic-bezier(0.4, 0, 1, 1)
1247
- tws("ease-out", 1); // cubic-bezier(0, 0, 0.2, 1)
1248
- tws("ease-in-out", 1); // cubic-bezier(0.4, 0, 0.2, 1)
1249
-
1250
- // Delay
1251
- tws("delay-75", 1); // 75ms
1252
- tws("delay-150", 1); // 150ms
1253
- tws("delay-300", 1); // 300ms
1254
- tws("delay-500", 1); // 500ms
1255
- ```
1256
-
1257
- ### Custom Animations
1258
-
1259
- Create your own animations using `configure()`:
1260
-
1261
- ```javascript
1262
- import { configure, tws } from "tailwind-to-style";
1263
-
1264
- configure({
1265
- theme: {
1266
- extend: {
1267
- animation: {
1268
- 'fade-in': 'fadeIn 1s ease-in forwards',
1269
- 'slide-up': 'slideUp 0.5s ease-out',
1270
- 'wiggle': 'wiggle 1s ease-in-out infinite',
1271
- },
1272
- keyframes: {
1273
- fadeIn: {
1274
- '0%': { opacity: '0' },
1275
- '100%': { opacity: '1' },
1276
- },
1277
- slideUp: {
1278
- '0%': { transform: 'translateY(100%)' },
1279
- '100%': { transform: 'translateY(0)' },
1280
- },
1281
- wiggle: {
1282
- '0%, 100%': { transform: 'rotate(-3deg)' },
1283
- '50%': { transform: 'rotate(3deg)' },
1284
- },
1285
- },
1286
- },
1287
- },
1288
- });
1289
-
1290
- // Use custom animations
1291
- const modal = tws("animate-fade-in", 1);
1292
- // { animation: "fadeIn 1s ease-in forwards" }
1293
-
1294
- const notification = tws("animate-slide-up", 1);
1295
- // { animation: "slideUp 0.5s ease-out" }
1296
- ```
1297
-
1298
- ### Real-World Examples
1299
-
1300
- ```javascript
1301
- // Button with hover transition
1302
- const button = tws(
1303
- "bg-blue-500 hover:bg-blue-600 transition-colors duration-200",
1304
- 1
1305
- );
1306
-
1307
- // Loading spinner
1308
- const spinner = tws(
1309
- "animate-spin w-8 h-8 border-2 border-blue-500 rounded-full",
1310
- 1
1311
- );
1312
-
1313
- // Notification with fade in
1314
- const notification = tws(
1315
- "animate-fade-in bg-green-500 text-white p-4 rounded shadow-lg",
1316
- 1
1317
- );
1318
-
1319
- // Menu with slide transition
1320
- const menu = tws(
1321
- "transition-transform duration-300 ease-out transform translate-x-0",
1322
- 1
1323
- );
1324
-
1325
- // Icon with hover wiggle
1326
- const icon = tws("hover:animate-wiggle cursor-pointer", 1);
1327
- ```
1328
-
1329
- See [examples/animations.js](examples/animations.js) for more examples!
1330
-
1331
- ## Theme Customization (v2.10.0+)
1332
-
1333
- Extend the default Tailwind theme with your own custom values:
1334
-
1335
- ### Basic Theme Extension
1336
-
1337
- ```javascript
1338
- import { configure, tws } from "tailwind-to-style";
1339
-
1340
- // Configure custom theme
1341
- configure({
1342
- theme: {
1343
- extend: {
1344
- colors: {
1345
- brand: {
1346
- 500: '#0ea5e9',
1347
- 600: '#0284c7',
1348
- },
1349
- accent: '#ff6b6b',
1350
- },
1351
- spacing: {
1352
- '128': '32rem',
1353
- '144': '36rem',
1354
- },
1355
- borderRadius: {
1356
- '4xl': '2rem',
1357
- },
1358
- },
1359
- },
1360
- });
1361
-
1362
- // Now use your custom values
1363
- const button = tws('bg-brand-500 hover:bg-brand-600 p-128 rounded-4xl', 1);
1364
- // Works! Uses your custom colors, spacing, and border radius
1365
- ```
1366
-
1367
- ### Theme Configuration Options
1368
-
1369
- ```javascript
1370
- configure({
1371
- theme: {
1372
- extend: {
1373
- colors: { /* custom colors */ },
1374
- spacing: { /* custom spacing */ },
1375
- borderRadius: { /* custom border radius */ },
1376
- fontSize: { /* custom font sizes */ },
1377
- // ... any Tailwind theme property
1378
- },
1379
- },
1380
-
1381
- // Optional: Add prefix to all classes
1382
- prefix: 'tw-',
1383
-
1384
- // Optional: Disable specific core plugins
1385
- corePlugins: {
1386
- float: false,
1387
- clear: false,
1388
- },
1389
- });
479
+ document.head.appendChild(Object.assign(document.createElement('style'), {
480
+ textContent: css
481
+ }))
1390
482
  ```
1391
483
 
1392
- ### Using Config File
1393
-
1394
- Create `tailwind-to-style.config.js`:
1395
-
1396
- ```javascript
1397
- export default {
1398
- theme: {
1399
- extend: {
1400
- colors: {
1401
- brand: {
1402
- 500: '#0ea5e9',
1403
- },
1404
- },
1405
- },
1406
- },
1407
- // Styled components configuration
1408
- styled: {
1409
- prefix: 'myapp', // Customize classname prefix
1410
- separator: '-', // Customize separator
1411
- hashLength: 6, // Hash length (4-8 recommended)
1412
- includeComponentName: true // Include component type in classname
1413
- }
1414
- };
1415
- ```
1416
-
1417
- Then import and use it:
1418
-
1419
- ```javascript
1420
- import { configure } from "tailwind-to-style";
1421
- import config from "./tailwind-to-style.config.js";
1422
-
1423
- configure(config);
1424
- ```
1425
-
1426
- ### Configuration Options
1427
-
1428
- ```javascript
1429
- configure({
1430
- // Theme customization
1431
- theme: {
1432
- extend: {
1433
- colors: { /* custom colors */ },
1434
- spacing: { /* custom spacing */ },
1435
- borderRadius: { /* custom border radius */ },
1436
- fontSize: { /* custom font sizes */ },
1437
- // ... any Tailwind theme property
1438
- },
1439
- },
1440
-
1441
- // Optional: Add prefix to utility classes
1442
- prefix: 'tw-',
1443
-
1444
- // Optional: Disable specific core plugins
1445
- corePlugins: {
1446
- float: false,
1447
- clear: false,
1448
- },
1449
-
1450
- // NEW: Styled components naming configuration
1451
- styled: {
1452
- prefix: 'twsx', // Global prefix (default: 'twsx')
1453
- separator: '-', // Separator between parts (default: '-')
1454
- hashLength: 6, // Hash length 4-8 (default: 6)
1455
- includeComponentName: true // Include component type (default: true)
1456
- }
1457
- });
1458
- ```
1459
-
1460
- **Examples:**
1461
-
1462
- ```javascript
1463
- // Brand-specific prefix
1464
- configure({ styled: { prefix: 'myapp' }})
1465
- // Generated: myapp-button-a3k9x2
1466
-
1467
- // Minimal classnames
1468
- configure({
1469
- styled: {
1470
- prefix: 'c',
1471
- separator: '',
1472
- hashLength: 4,
1473
- includeComponentName: false
1474
- }
1475
- })
1476
- // Generated: c1a2b
1477
-
1478
- // BEM-like style
1479
- configure({ styled: { separator: '__' }})
1480
- // Generated: twsx__button__a3k9x2
1481
- ```
1482
-
1483
- See [Custom Classname Prefix Configuration](#custom-classname-prefix-configuration) for more details.
1484
-
1485
- ## Custom Plugins (v2.10.0+)
1486
-
1487
- Create custom utility classes with the plugin API:
1488
-
1489
- ### Simple Utility Plugin
1490
-
1491
- ```javascript
1492
- import { createPlugin, configure, tws } from "tailwind-to-style";
1493
-
1494
- // Create a text gradient plugin
1495
- const textGradientPlugin = createPlugin('text-gradient', {
1496
- utilities: {
1497
- '.text-gradient': {
1498
- 'background-clip': 'text',
1499
- '-webkit-background-clip': 'text',
1500
- '-webkit-text-fill-color': 'transparent',
1501
- 'background-image': 'linear-gradient(to right, #3b82f6, #8b5cf6)',
1502
- },
1503
- },
1504
- });
1505
-
1506
- // Register the plugin
1507
- configure({
1508
- plugins: [textGradientPlugin],
1509
- });
1510
-
1511
- // Use it!
1512
- const heading = tws('text-gradient text-4xl font-bold', 1);
1513
- ```
1514
-
1515
- ### Dynamic Utility Plugin
1516
-
1517
- ```javascript
1518
- import { createUtilityPlugin, configure } from "tailwind-to-style";
1519
-
1520
- // Create a text-shadow plugin with multiple values
1521
- const textShadowPlugin = createUtilityPlugin('text-shadow', {
1522
- prefix: 'text-shadow',
1523
- values: {
1524
- sm: '1px 1px 2px rgba(0,0,0,0.1)',
1525
- md: '2px 2px 4px rgba(0,0,0,0.15)',
1526
- lg: '4px 4px 8px rgba(0,0,0,0.2)',
1527
- xl: '6px 6px 12px rgba(0,0,0,0.25)',
1528
- },
1529
- formatter: (value) => ({
1530
- 'text-shadow': value,
1531
- }),
1532
- });
1533
-
1534
- configure({
1535
- plugins: [textShadowPlugin],
1536
- });
1537
-
1538
- // Use with different sizes
1539
- tws('text-shadow-sm'); // Small shadow
1540
- tws('text-shadow-lg'); // Large shadow
1541
- ```
1542
-
1543
- ### Glassmorphism Plugin Example
1544
-
1545
- ```javascript
1546
- const glassmorphismPlugin = createPlugin('glassmorphism', {
1547
- utilities: {
1548
- '.glass': {
1549
- 'backdrop-filter': 'blur(10px)',
1550
- '-webkit-backdrop-filter': 'blur(10px)',
1551
- 'background-color': 'rgba(255, 255, 255, 0.1)',
1552
- 'border': '1px solid rgba(255, 255, 255, 0.2)',
1553
- },
1554
- '.glass-dark': {
1555
- 'backdrop-filter': 'blur(10px)',
1556
- '-webkit-backdrop-filter': 'blur(10px)',
1557
- 'background-color': 'rgba(0, 0, 0, 0.1)',
1558
- 'border': '1px solid rgba(255, 255, 255, 0.1)',
1559
- },
1560
- },
1561
- });
1562
-
1563
- configure({
1564
- plugins: [glassmorphismPlugin],
1565
- });
1566
-
1567
- // Use glassmorphism effects
1568
- const card = tws('glass p-6 rounded-lg', 1);
1569
- ```
1570
-
1571
- ### Complete Configuration Example
1572
-
1573
- ```javascript
1574
- import { configure, createPlugin, createUtilityPlugin } from "tailwind-to-style";
1575
-
1576
- const textShadowPlugin = createUtilityPlugin('text-shadow', {
1577
- prefix: 'text-shadow',
1578
- values: {
1579
- sm: '1px 1px 2px rgba(0,0,0,0.1)',
1580
- md: '2px 2px 4px rgba(0,0,0,0.15)',
1581
- lg: '4px 4px 8px rgba(0,0,0,0.2)',
1582
- },
1583
- formatter: (value) => ({ 'text-shadow': value }),
1584
- });
1585
-
1586
- const glassmorphismPlugin = createPlugin('glassmorphism', {
1587
- utilities: {
1588
- '.glass': {
1589
- 'backdrop-filter': 'blur(10px)',
1590
- 'background-color': 'rgba(255, 255, 255, 0.1)',
1591
- },
1592
- },
1593
- });
1594
-
1595
- configure({
1596
- theme: {
1597
- extend: {
1598
- colors: {
1599
- brand: {
1600
- 500: '#0ea5e9',
1601
- },
1602
- },
1603
- spacing: {
1604
- '128': '32rem',
1605
- },
1606
- },
1607
- },
1608
- plugins: [textShadowPlugin, glassmorphismPlugin],
1609
- });
1610
- ```
1611
-
1612
- ### 2. `twsx`
1613
-
1614
- `twsx` is an advanced function that builds on `tws` by allowing you to define **nested styles** and more complex CSS structures. It supports **grouping**, **responsive variants**, **state variants**, **dynamic utilities**, and **direct CSS properties** via the `@css` directive, making it ideal for more advanced styling needs.
1615
-
1616
- #### Features of `twsx`:
1617
-
1618
- - ✅ **Nested styles** similar to SCSS, enabling more complex CSS structures
1619
- - ✅ **Grouping**: Supports grouping utilities inside parentheses `hover:(bg-blue-600 scale-105)`
1620
- - ✅ **Responsive variants** (`sm`, `md`, `lg`, `xl`, `2xl`) in standard and grouping syntax
1621
- - ✅ **🆕 Responsive selector syntax** (v2.9.0+): `'md:.title': 'text-lg'` format for intuitive responsive styling
1622
- - ✅ **State variants** like `hover`, `focus`, `active`, `disabled`, etc.
1623
- - ✅ **Dynamic utilities** such as `w-[300px]`, `bg-[rgba(0,0,0,0.5)]`, `text-[14px]`
1624
- - ✅ **!important support** with `!text-red-500`, `!bg-blue-500`
1625
- - ✅ **🆕 Enhanced @css directive** (v2.9.0+): Perfect CSS variables, functions, and complex expressions support
1626
-
1627
- #### Basic Usage
1628
-
1629
- ```javascript
1630
- import { twsx } from "tailwind-to-style";
1631
-
1632
- const styles = twsx({
1633
- ".card": [
1634
- "bg-white p-4 rounded-lg shadow-md",
1635
- {
1636
- "&:hover": "shadow-xl scale-105",
1637
- ".title": "text-lg font-bold text-gray-900",
1638
- ".desc": "text-sm text-gray-600 mt-2",
1639
- },
1640
- ],
1641
- });
1642
-
1643
- console.log(styles);
1644
- ```
1645
-
1646
- **Output**:
1647
-
1648
- ```css
1649
- .card {
1650
- background-color: rgba(255, 255, 255, var(--bg-opacity));
1651
- padding: 1rem;
1652
- border-radius: 0.5rem;
1653
- box-shadow:
1654
- 0 4px 6px -1px rgb(0 0 0 / 0.1),
1655
- 0 2px 4px -2px rgb(0 0 0 / 0.1);
1656
- }
1657
- .card:hover {
1658
- box-shadow:
1659
- 0 20px 25px -5px rgb(0 0 0 / 0.1),
1660
- 0 8px 10px -6px rgb(0 0 0 / 0.1);
1661
- transform: scale(1.05);
1662
- }
1663
- .card .title {
1664
- font-size: 1.125rem;
1665
- font-weight: 700;
1666
- color: rgba(17, 24, 39, var(--text-opacity));
1667
- }
1668
- .card .desc {
1669
- font-size: 0.875rem;
1670
- color: rgba(75, 85, 99, var(--text-opacity));
1671
- margin-top: 0.5rem;
1672
- }
1673
- ```
1674
-
1675
- #### Grouping Support
1676
-
1677
- Group related utilities together inside parentheses for better readability and organization:
1678
-
1679
- ```javascript
1680
- const styles = twsx({
1681
- ".button": [
1682
- "bg-blue-500 text-white px-6 py-3 rounded-lg",
1683
- "hover:(bg-blue-600 scale-105 shadow-lg)",
1684
- "focus:(ring-2 ring-blue-300 outline-none)",
1685
- "active:(bg-blue-700 scale-95)",
1686
- ],
1687
- });
1688
- ```
1689
-
1690
- **Output**:
1691
-
1692
- ```css
1693
- .button {
1694
- background-color: rgba(59, 130, 246, var(--bg-opacity));
1695
- color: rgba(255, 255, 255, var(--text-opacity));
1696
- padding: 0.75rem 1.5rem;
1697
- border-radius: 0.5rem;
1698
- }
1699
- .button:hover {
1700
- background-color: rgba(37, 99, 235, var(--bg-opacity));
1701
- transform: scale(1.05);
1702
- box-shadow:
1703
- 0 10px 15px -3px rgb(0 0 0 / 0.1),
1704
- 0 4px 6px -4px rgb(0 0 0 / 0.1);
1705
- }
1706
- .button:focus {
1707
- box-shadow: var(--ring-offset-shadow), var(--ring-shadow);
1708
- outline: none;
1709
- }
1710
- .button:active {
1711
- background-color: rgba(29, 78, 216, var(--bg-opacity));
1712
- transform: scale(0.95);
1713
- }
1714
- ```
1715
-
1716
- #### Responsive Variants
1717
-
1718
- Responsive variants work seamlessly with both standard syntax and grouping syntax:
1719
-
1720
- ```javascript
1721
- const styles = twsx({
1722
- ".hero": [
1723
- // Standard responsive syntax
1724
- "text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl",
1725
- "w-full md:w-1/2 lg:w-1/3 p-4",
1726
- // Grouped responsive syntax
1727
- "sm:(py-16 px-4)",
1728
- "md:(py-20 px-6)",
1729
- "lg:(py-24 px-8)",
1730
- {
1731
- h1: "font-bold text-gray-900",
1732
- p: "text-gray-600 mt-4",
1733
- },
1734
- ],
1735
- });
1736
- ```
1737
-
1738
- **Output**:
1739
-
1740
- ```css
1741
- .hero {
1742
- font-size: 1.5rem;
1743
- width: 100%;
1744
- padding: 1rem;
1745
- }
1746
- @media (min-width: 640px) {
1747
- .hero {
1748
- font-size: 1.875rem;
1749
- padding: 4rem 1rem;
1750
- }
1751
- }
1752
- @media (min-width: 768px) {
1753
- .hero {
1754
- font-size: 2.25rem;
1755
- width: 50%;
1756
- padding: 5rem 1.5rem;
1757
- }
1758
- }
1759
- @media (min-width: 1024px) {
1760
- .hero {
1761
- font-size: 3rem;
1762
- width: 33.333333%;
1763
- padding: 6rem 2rem;
1764
- }
1765
- }
1766
- @media (min-width: 1280px) {
1767
- .hero {
1768
- font-size: 3.75rem;
1769
- }
1770
- }
1771
- .hero h1 {
1772
- font-weight: 700;
1773
- color: rgba(17, 24, 39, var(--text-opacity));
1774
- }
1775
- .hero p {
1776
- color: rgba(75, 85, 99, var(--text-opacity));
1777
- margin-top: 1rem;
1778
- }
1779
- ```
1780
-
1781
- #### 🆕 Responsive Selector Syntax (v2.9.0+)
1782
-
1783
- **New feature**: You can now use responsive breakpoints directly in selectors for more intuitive responsive styling:
1784
-
1785
- ```javascript
1786
- const styles = twsx({
1787
- // New responsive selector syntax
1788
- "md:.title": "text-lg font-bold",
1789
- "lg:.title": "text-xl",
1790
- "xl:.title": "text-2xl",
1791
-
1792
- // Equivalent to the traditional syntax:
1793
- ".title": "md:text-lg md:font-bold lg:text-xl xl:text-2xl"
1794
- });
1795
- ```
1796
-
1797
- This new syntax automatically converts responsive selectors to traditional Tailwind responsive classes and generates proper media queries:
1798
-
1799
- ```css
1800
- .title {
1801
- /* Base styles if any */
1802
- }
1803
- @media (min-width: 768px) {
1804
- .title {
1805
- font-size: 1.125rem;
1806
- font-weight: 700;
1807
- }
1808
- }
1809
- @media (min-width: 1024px) {
1810
- .title {
1811
- font-size: 1.25rem;
1812
- }
1813
- }
1814
- @media (min-width: 1280px) {
1815
- .title {
1816
- font-size: 1.5rem;
1817
- }
1818
- }
1819
- ```
1820
-
1821
- **Benefits of Responsive Selector Syntax:**
1822
- - ✅ More intuitive and organized responsive code
1823
- - ✅ Better separation of breakpoint-specific styles
1824
- - ✅ Easier to maintain complex responsive designs
1825
- - ✅ Backward compatible with existing syntax
1826
- - ✅ Works with all breakpoints: `sm`, `md`, `lg`, `xl`, `2xl`
1827
-
1828
- #### Handling Dark and Light Mode
1829
-
1830
- `twsx` supports writing styles for dark and light mode easily, similar to Tailwind CSS. You can use the `dark:` prefix, `.dark` selector, grouping, or nested selector.
1831
-
1832
- **Usage Example:**
1833
-
1834
- ```javascript
1835
- import { twsx } from "tailwind-to-style";
1836
-
1837
- const styles = twsx({
1838
- ".card": [
1839
- "bg-white text-gray-900 dark:bg-gray-900 dark:text-white", // Using dark: prefix
1840
- { ".dark &": "bg-gray-900 text-white border-gray-700" }, // Or .dark selector
1841
- ],
1842
- // Grouping is also supported
1843
- ".button": "bg-blue-500 text-white dark:(bg-gray-900 text-yellow-200)",
1844
- });
1845
- ```
1846
-
1847
- **Explanation:**
1848
- - The `dark:` prefix will automatically generate CSS that is only active if the parent has the `dark` class (e.g. `<html class="dark">`).
1849
- - The `.dark &` selector can also be used for more flexibility.
1850
- - Grouping `dark:(...)` will be automatically expanded into multiple dark classes.
1851
-
1852
- **CSS Output:**
1853
- ```css
1854
- .card {
1855
- background-color: #fff;
1856
- color: #111827;
1857
- }
1858
- .dark .card {
1859
- background-color: #111827;
1860
- color: #fff;
1861
- border-color: #374151;
1862
- }
1863
- .button {
1864
- background-color: #3b82f6;
1865
- color: #fff;
1866
- }
1867
- .dark .button {
1868
- background-color: #111827;
1869
- color: #fde68a;
1870
- }
1871
- ```
1872
-
1873
- **Enable dark mode** by adding the `dark` class to the root element (usually `<html class="dark">`).
1874
-
1875
- ### Performance Utilities
1876
-
1877
- The library includes performance optimization features:
1878
-
1879
- #### Inject Option
1880
-
1881
- Control CSS output location with the `inject` option:
1882
-
1883
- ```javascript
1884
- import { tws, twsx } from "tailwind-to-style";
1885
-
1886
- // Auto-inject into document head (default)
1887
- const styles1 = tws("bg-blue-500 text-white p-4");
1888
-
1889
- // Skip injection - returns CSS only
1890
- const styles2 = tws("bg-red-500 text-black p-2", { inject: false });
1891
-
1892
- // Custom injection target
1893
- const targetElement = document.getElementById("custom-styles");
1894
- const styles3 = tws("bg-green-500 text-yellow p-3", { inject: targetElement });
1895
- ```
1896
-
1897
- #### Performance Monitoring
1898
-
1899
- ```javascript
1900
- import { tws } from "tailwind-to-style";
1901
-
1902
- // Enable performance logging
1903
- const start = performance.now();
1904
- const styles = tws("complex-classes here...");
1905
- const end = performance.now();
1906
- console.log(`Generation time: ${end - start}ms`);
1907
- ```
1908
-
1909
- ## Advanced `@css` Directive
1910
-
1911
- The `@css` directive allows you to write custom CSS properties that aren't available as Tailwind utilities. **Starting from v2.9.0**, the `@css` directive has been significantly enhanced with improved CSS syntax preservation.
1912
-
1913
- ### 🆕 Enhanced CSS Support (v2.9.0+)
1914
-
1915
- **Major improvements in CSS handling:**
1916
- - ✅ **Perfect CSS Variables**: `var(--custom-property)` syntax fully preserved
1917
- - ✅ **CSS Functions**: `calc()`, `rgba()`, `linear-gradient()`, `clamp()` etc. work flawlessly
1918
- - ✅ **Complex Expressions**: Multi-function CSS expressions preserved accurately
1919
- - ✅ **Zero Corruption**: Fixed critical bug where CSS values were being corrupted
1920
-
1921
- **Before v2.9.0** (corrupted):
1922
- ```css
1923
- /* This would be corrupted */
1924
- background: -var--primary; /* ❌ WRONG */
1925
- color: rgba-255,0,0,0.5; /* ❌ WRONG */
1926
- ```
1927
-
1928
- **v2.9.0+** (perfect preservation):
1929
- ```css
1930
- /* Now works perfectly */
1931
- background: var(--primary); /* ✅ CORRECT */
1932
- color: rgba(255,0,0,0.5); /* ✅ CORRECT */
1933
- transform: calc(100% - 20px); /* ✅ CORRECT */
1934
- ```
1935
-
1936
- ### Usage Examples
1937
-
1938
- There are several ways to use the `@css` feature:
1939
-
1940
- 1. **As a nested object inside selectors**:
1941
-
1942
- ```javascript
1943
- const styles = twsx({
1944
- ".button": [
1945
- "bg-blue-500 text-white rounded-md",
1946
- {
1947
- "@css": {
1948
- transition: "all 0.3s ease-in-out",
1949
- "will-change": "transform, opacity",
1950
- },
1951
- "&:hover": "bg-blue-600",
1952
- },
1953
- ],
1954
- });
1955
- ```
1956
-
1957
- **Output**:
1958
-
1959
- ```css
1960
- .button {
1961
- background-color: #3b82f6;
1962
- color: white;
1963
- border-radius: 0.375rem;
1964
- transition: all 0.3s ease-in-out;
1965
- will-change: transform, opacity;
1966
- }
1967
- .button:hover {
1968
- background-color: #2563eb;
1969
- }
1970
- ```
1971
-
1972
- 2. **As a direct property in the selector**:
1973
-
1974
- ```javascript
1975
- const styles = twsx({
1976
- ".button @css transition": "all 0.3s ease-in-out",
1977
- ".button": "bg-blue-500 text-white rounded-md",
1978
- ".button:hover": "bg-blue-600",
1979
- });
1980
- ```
1981
-
1982
- This syntax is especially useful when you need to add just a single CSS property that isn't available in Tailwind.
1983
-
1984
- The `@css` feature is particularly helpful for properties that require complex values with spaces (like transitions, animations, and transforms) which can't be represented with standard Tailwind utility classes.
1985
-
1986
- #### Advanced `@css` Examples:
1987
-
1988
- You can combine `@css` with state variants:
1989
-
1990
- ```javascript
1991
- const styles = twsx({
1992
- ".modal": [
1993
- "bg-white rounded-lg shadow-xl",
1994
- {
1995
- "@css": {
1996
- transform: "translateX(0px)",
1997
- transition: "all 0.3s ease-out",
1998
- "will-change": "transform, opacity",
1999
- },
2000
- "&.hidden": [
2001
- "opacity-0",
2002
- {
2003
- "@css": {
2004
- transform: "translateX(-100px)",
2005
- },
2006
- },
2007
- ],
2008
- },
2009
- ],
2010
- });
2011
- ```
2012
-
2013
- **Output**:
2014
-
2015
- ```css
2016
- .modal {
2017
- background-color: white;
2018
- border-radius: 0.5rem;
2019
- box-shadow:
2020
- 0 20px 25px -5px rgba(0, 0, 0, 0.1),
2021
- 0 10px 10px -5px rgba(0, 0, 0, 0.04);
2022
- transform: translateX(0px);
2023
- transition: all 0.3s ease-out;
2024
- will-change: transform, opacity;
2025
- }
2026
- .modal.hidden {
2027
- opacity: 0;
2028
- transform: translateX(-100px);
2029
- }
2030
- ```
2031
-
2032
- #### 🆕 CSS Variables & Functions Examples (v2.9.0+)
2033
-
2034
- With the enhanced `@css` directive, you can now use complex CSS features:
2035
-
2036
- ```javascript
2037
- const styles = twsx({
2038
- ".theme-component": {
2039
- "@css": {
2040
- // CSS Variables - now work perfectly!
2041
- "--primary-color": "#3b82f6",
2042
- "--secondary-color": "#8b5cf6",
2043
- "--border-radius": "0.5rem",
2044
-
2045
- // CSS Functions - fully preserved!
2046
- "background": "linear-gradient(135deg, var(--primary-color), var(--secondary-color))",
2047
- "border-radius": "var(--border-radius)",
2048
- "box-shadow": "0 4px 20px rgba(0, 0, 0, 0.15)",
2049
- "transform": "translateY(calc(-1 * var(--spacing, 10px)))",
2050
-
2051
- // Complex CSS expressions
2052
- "width": "clamp(200px, 50vw, 800px)",
2053
- "padding": "calc(1rem + 2vw)",
2054
- "color": "hsl(220, 100%, 50%)"
2055
- }
2056
- },
2057
-
2058
- ".dynamic-grid": {
2059
- "@css": {
2060
- "display": "grid",
2061
- "grid-template-columns": "repeat(auto-fit, minmax(250px, 1fr))",
2062
- "gap": "clamp(1rem, 5vw, 3rem)",
2063
- "grid-auto-rows": "minmax(200px, auto)"
2064
- }
2065
- }
2066
- });
2067
- ```
2068
-
2069
- **Output** (perfectly preserved CSS):
2070
-
2071
- ```css
2072
- .theme-component {
2073
- --primary-color: #3b82f6;
2074
- --secondary-color: #8b5cf6;
2075
- --border-radius: 0.5rem;
2076
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
2077
- border-radius: var(--border-radius);
2078
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
2079
- transform: translateY(calc(-1 * var(--spacing, 10px)));
2080
- width: clamp(200px, 50vw, 800px);
2081
- padding: calc(1rem + 2vw);
2082
- color: hsl(220, 100%, 50%);
2083
- }
2084
- .dynamic-grid {
2085
- display: grid;
2086
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
2087
- gap: clamp(1rem, 5vw, 3rem);
2088
- grid-auto-rows: minmax(200px, auto);
2089
- }
2090
- ```
2091
-
2092
- For responsive styles, you can use standard Tailwind responsive utilities within your classes:
2093
-
2094
- ```javascript
2095
- const styles = twsx({
2096
- ".responsive-box": "w-full md:w-1/2 lg:w-1/3 p-4 bg-blue-500",
2097
- });
2098
- ```
2099
-
2100
- The `@css` feature provides a powerful way to bridge the gap between Tailwind's utility classes and custom CSS when needed, without leaving the `twsx` syntax.
2101
-
2102
- ### Inject Option (Browser Only)
2103
-
2104
- By default, every call to `twsx` in the browser will automatically inject the generated CSS into a `<style id="twsx-auto-style">` tag in the document `<head>`. This makes it easy to use dynamic styles in browser or CDN scenarios without manual CSS management.
2105
-
2106
- You can control this behavior with the `inject` option:
2107
-
2108
- ```js
2109
- // Auto-inject (default)
2110
- twsx({ ... }) // CSS is injected automatically
2111
-
2112
- // Disable auto-inject
2113
- twsx({ ... }, { inject: false }) // CSS is NOT injected, just returned as string
2114
- ```
2115
-
2116
- - **inject: true** (default): CSS is injected into the page (browser only).
2117
- - **inject: false**: CSS is only returned as a string, not injected. Useful for SSR, testing, or custom handling.
2118
-
2119
- > Note: This option only affects browser usage. In Node.js or SSR, no injection occurs.
2120
-
2121
- ## Performance Monitoring & Debugging (v2.7.0+)
2122
-
2123
- Starting from version 2.7.0, `tailwind-to-style` includes built-in performance monitoring and debugging utilities to help you optimize your application and troubleshoot issues.
2124
-
2125
- ### Performance Utils
2126
-
2127
- ```javascript
2128
- import { performanceUtils } from "tailwind-to-style";
2129
-
2130
- // Enable performance logging (logs operations > 5ms as warnings)
2131
- performanceUtils.enablePerformanceLogging(true);
2132
-
2133
- // Get cache and injection statistics
2134
- const stats = performanceUtils.getStats();
2135
- console.log(stats);
2136
- // Output:
2137
- // {
2138
- // cacheStats: {
2139
- // cssResolution: 45,
2140
- // configOptions: 2,
2141
- // parseSelector: 23,
2142
- // encodeBracket: 12,
2143
- // decodeBracket: 8
2144
- // },
2145
- // injectionStats: {
2146
- // uniqueStylesheets: 15
2147
- // }
2148
- // }
2149
-
2150
- // Clear all caches (useful for memory management)
2151
- performanceUtils.clearCaches();
2152
- ```
2153
-
2154
- ### Performance Metrics
2155
-
2156
- The library automatically tracks performance for key operations:
2157
-
2158
- - **tws:total** - Total execution time for `tws()`
2159
- - **tws:parse** - Time spent parsing classes
2160
- - **tws:process** - Time spent processing classes
2161
- - **twsx:total** - Total execution time for `twsx()`
2162
- - **twsx:flatten** - Time spent flattening objects
2163
- - **twsx:generate** - Time spent generating CSS
2164
- - **css:inject** - Time spent injecting CSS to DOM
2165
-
2166
- ### Debounced Functions
2167
-
2168
- For high-frequency usage, use the debounced versions:
2169
-
2170
- ```javascript
2171
- import { debouncedTws, debouncedTwsx } from "tailwind-to-style";
2172
-
2173
- // Debounced versions (50ms for tws, 100ms for twsx)
2174
- const styles = debouncedTws("bg-red-500 p-4");
2175
- const complexStyles = debouncedTwsx({ ".card": "bg-white p-6" });
2176
- ```
2177
-
2178
- ### Example: Performance Monitoring
2179
-
2180
- ```javascript
2181
- import { tws, twsx, performanceUtils } from "tailwind-to-style";
2182
-
2183
- // Enable monitoring
2184
- performanceUtils.enablePerformanceLogging(true);
2185
-
2186
- // Your code that uses tws/twsx
2187
- const styles = tws("bg-gradient-to-r from-purple-400 to-pink-500 p-8");
2188
- const complexStyles = twsx({
2189
- ".hero": [
2190
- "bg-gradient-to-br from-indigo-900 to-purple-900 min-h-screen",
2191
- {
2192
- h1: "text-6xl font-bold text-white md:text-4xl",
2193
- "@css": {
2194
- transition: "font-size 0.3s ease-in-out",
2195
- },
2196
- },
2197
- ],
2198
- });
2199
-
2200
- // Check performance stats
2201
- console.log(performanceUtils.getStats());
2202
- ```
2203
-
2204
- This will automatically log warnings for operations taking longer than 5ms and provide insights into cache usage and performance bottlenecks.
2205
-
2206
- # Build-Time Plugins: Vite & Webpack
2207
-
2208
- ### Automated Modular CSS Generation
2209
-
2210
- 1. Create JS files with `twsx.` prefix in your project (e.g., `twsx.card.js`, `twsx.button.js`) anywhere in your `src/` folder.
2211
- 2. Use the Vite/Webpack plugin from the `plugins/` folder to automatically generate CSS on every build/rebuild.
2212
- 3. Each JS file will generate its own CSS file in the specified output directory (default: `src/styles/`).
2213
- 4. Import the generated CSS files directly in your components or bundle them as needed.
2214
-
2215
- #### Vite Plugin Usage Example
2216
-
2217
- Add the plugin to your `vite.config.js`:
2218
- ```js
2219
- import twsxPlugin from 'tailwind-to-style/plugins/vite-twsx';
2220
-
2221
- export default {
2222
- plugins: [
2223
- twsxPlugin({
2224
- inputDir: 'src',
2225
- outputDir: 'src/styles',
2226
- preserveStructure: false // Set to true to generate CSS next to JS files
2227
- })
2228
- ]
2229
- };
2230
- ```
2231
-
2232
- **Configuration Options:**
2233
- - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
2234
- - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
2235
- - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
2236
-
2237
- **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
2238
- **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
2239
-
2240
- Import in your components:
2241
- ```js
2242
- // Default mode
2243
- import './styles/twsx.card.css';
2244
- import './styles/twsx.button.css';
2245
-
2246
- // Preserve structure mode
2247
- import './twsx.card.css'; // If in same directory
2248
- ```
2249
-
2250
- #### Webpack Plugin Usage Example
2251
-
2252
- Add the plugin to your `webpack.config.js`:
2253
- ```js
2254
- import TwsxPlugin from 'tailwind-to-style/plugins/webpack-twsx';
2255
-
2256
- module.exports = {
2257
- plugins: [
2258
- new TwsxPlugin({
2259
- inputDir: 'src',
2260
- outputDir: 'src/styles',
2261
- preserveStructure: false // Set to true to generate CSS next to JS files
2262
- })
2263
- ]
2264
- };
2265
- ```
2266
-
2267
- **Configuration Options:**
2268
- - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
2269
- - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
2270
- - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
2271
-
2272
- **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
2273
- **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
2274
-
2275
- Import in your components:
2276
- ```js
2277
- // Default mode
2278
- import './styles/twsx.card.css';
2279
- import './styles/twsx.button.css';
2280
-
2281
- // Preserve structure mode
2282
- import './twsx.card.css'; // If in same directory
2283
- ```
2284
-
2285
- ## Build-Time CSS Generation via Script
2286
-
2287
- In addition to using the Vite/Webpack plugin, you can also use a Node.js script to generate CSS files from `twsx.*.js` files manually or as part of your build workflow.
2288
-
2289
- ### Script: tailwind-to-style/lib/twsx-cli.js (Legacy)
2290
-
2291
- > **ðŸ’Ą Recommended:** Use `npx twsx-cli` instead of calling the script directly.
2292
-
2293
- This script will recursively scan for all `twsx.*.js` files in your project, generate CSS using the `twsx` function, and write individual CSS files to the specified output directory.
2294
-
2295
- #### How to Use
2296
-
2297
- 1. Create JS files with `twsx.` prefix containing style objects anywhere in your `src/` folder (e.g., `src/components/twsx.card.js`).
2298
-
2299
- 2. **One-time Build:**
2300
- ```bash
2301
- node tailwind-to-style/lib/twsx-cli.js
2302
- ```
2303
-
2304
- 3. **Watch Mode (Auto-rebuild on file changes):**
2305
- ```bash
2306
- node tailwind-to-style/lib/twsx-cli.js --watch
2307
- ```
2308
-
2309
- 4. **Preserve Structure Mode (Generate CSS next to JS files):**
2310
- ```bash
2311
- # One-time build with preserve structure
2312
- node tailwind-to-style/lib/twsx-cli.js --preserve-structure
2313
-
2314
- # Watch mode with preserve structure
2315
- node tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure
2316
- ```
2317
-
2318
- You can configure input and output directories using environment variables:
2319
- ```bash
2320
- TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/twsx-cli.js --watch
2321
- ```
2322
-
2323
- Or use environment variables for preserve structure:
2324
- ```bash
2325
- TWSX_PRESERVE_STRUCTURE=true node tailwind-to-style/lib/twsx-cli.js --watch
2326
- ```
2327
-
2328
- 5. **Output locations:**
2329
-
2330
- **Default mode:** CSS files will be in the output directory (default: `src/styles/`):
2331
- ```
2332
- src/styles/twsx.card.css
2333
- src/styles/twsx.button.css
2334
- ```
2335
-
2336
- **Preserve structure mode:** CSS files will be generated next to their JS counterparts:
2337
- ```
2338
- src/components/Button/twsx.button.js → src/components/Button/twsx.button.css
2339
- src/components/Card/twsx.card.js → src/components/Card/twsx.card.css
2340
- ```
2341
-
2342
- 5. Import the generated CSS files in your components:
2343
-
2344
- **Default mode:**
2345
- ```js
2346
- import './styles/twsx.card.css';
2347
- import './styles/twsx.button.css';
2348
- ```
2349
-
2350
- **Preserve structure mode:**
2351
- ```js
2352
- // In src/components/Button/Button.jsx
2353
- import './twsx.button.css';
2354
-
2355
- // In src/components/Card/Card.jsx
2356
- import './twsx.card.css';
2357
- ```
2358
-
2359
- #### Usage in Different Projects
2360
-
2361
- **React/Next.js/Vue/Any Project:**
2362
-
2363
- 1. Install the package:
2364
- ```bash
2365
- npm install tailwind-to-style
2366
- ```
2367
-
2368
- 2. Add to your `package.json`:
2369
- ```json
2370
- {
2371
- "scripts": {
2372
- "twsx:build": "node node_modules/tailwind-to-style/lib/twsx-cli.js",
2373
- "twsx:watch": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch",
2374
- "twsx:preserve": "node node_modules/tailwind-to-style/lib/twsx-cli.js --preserve-structure",
2375
- "twsx:dev": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure",
2376
- "dev": "npm run twsx:watch & next dev"
2377
- }
2378
- }
2379
- ```
2380
-
2381
- 3. For development with auto-rebuild:
2382
- ```bash
2383
- npm run twsx:watch
2384
- ```
2385
-
2386
- 4. For production build:
2387
- ```bash
2388
- npm run twsx:build
2389
- ```
2390
-
2391
- **VS Code Integration:**
2392
- Add to your workspace settings (`.vscode/settings.json`):
2393
- ```json
2394
- {
2395
- "emeraldwalk.runonsave": {
2396
- "commands": [
2397
- {
2398
- "match": "twsx\\..*\\.js$",
2399
- "cmd": "npm run twsx:build"
2400
- }
2401
- ]
2402
- }
2403
- }
2404
- ```
2405
-
2406
- #### Automatic Integration
2407
-
2408
- You can add this script to the build section in your `package.json`:
2409
-
2410
- ```json
2411
- {
2412
- "scripts": {
2413
- "build-css": "node tailwind-to-style/lib/twsx-cli.js"
2414
- }
2415
- }
2416
- ```
2417
-
2418
- Then run:
2419
-
2420
- ```bash
2421
- npm run build-css
2422
- ```
484
+ ## 📊 Performance
2423
485
 
2424
- This script is suitable for CI/CD workflows, pre-build steps, or manually generating CSS without a bundler plugin.
486
+ - **Parse & cache** - Styles are cached after first parse
487
+ - **Small bundle** - ~12KB minified (vs 45KB in v2)
488
+ - **No build step** - Instant development workflow
489
+ - **Tree-shakeable** - Only import what you use
2425
490
 
2426
- ## License
491
+ ## 🆚 Comparison
2427
492
 
2428
- ## Support
493
+ | Feature | tailwind-to-style | Tailwind CSS | CSS-in-JS |
494
+ |---------|------------------|--------------|-----------|
495
+ | Build Step | ❌ None | ✅ Required | ❌ None |
496
+ | Bundle Size | ðŸŸĒ 12KB | ðŸŸĄ ~80KB+ | ðŸŸĄ 20-40KB |
497
+ | Runtime | ✅ Yes | ❌ No | ✅ Yes |
498
+ | Full Tailwind Support | ✅ Yes | ✅ Yes | ❌ No |
499
+ | Framework Agnostic | ✅ Yes | ✅ Yes | ⚠ïļ Depends |
500
+ | Nesting Support | ✅ Yes | ⚠ïļ Plugins | ✅ Yes |
501
+ | TypeScript | ✅ Yes | ✅ Yes | ✅ Yes |
2429
502
 
2430
- If you find this library helpful and want to support its development, consider buying me a coffee:
503
+ ## 📖 Migration from v2
2431
504
 
2432
- [![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://buymeacoffee.com/bigetion)
505
+ See [MIGRATION.md](MIGRATION.md) for detailed migration guide from v2.x to v3.x.
2433
506
 
2434
- Your support helps maintain and improve this library! âĪïļ
507
+ **Quick summary:**
508
+ - ✅ `tws()` - No changes
509
+ - ✅ `twsx()` - No changes
510
+ - ✅ `configure()` - No changes
511
+ - ❌ `styled()`, `tv()` - Removed (use emotion/styled-components)
512
+ - ❌ `useTwsx()`, `TwsxProvider` - Removed (use `twsx()` directly)
513
+ - ❌ CLI tools & plugins - Removed (not needed for runtime library)
2435
514
 
2436
- ### Why Support?
515
+ ## ðŸĪ Contributing
2437
516
 
2438
- - 🔧 **Active Maintenance**: Regular updates and bug fixes
2439
- - ⚡ **New Features**: Continuous improvement based on community feedback
2440
- - 📚 **Documentation**: Better examples and tutorials
2441
- - 🚀 **Performance**: Optimization and new capabilities
2442
- - 💎 **Support**: Responsive community support
517
+ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details.
2443
518
 
2444
- Every contribution, no matter how small, is greatly appreciated and helps keep this project alive and growing!
519
+ ## 📄 License
2445
520
 
2446
- ## Contributing
521
+ MIT ÂĐ [Bigetion](https://github.com/Bigetion)
2447
522
 
2448
- Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
523
+ ## 💖 Support
2449
524
 
2450
- ## License
525
+ If you find this library helpful, consider supporting:
2451
526
 
2452
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
527
+ [☕ Buy me a coffee](https://buymeacoffee.com/bigetion)
2453
528
 
2454
529
  ---
2455
530
 
2456
- Feel free to contribute or raise issues on the [GitHub repository](https://github.com/Bigetion/tailwind-to-style).
531
+ **v3.0.0** - Focused, fast, and simple. Just the core. ðŸŽŊ