tailwind-to-style 2.9.0 → 2.9.2

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
@@ -1,864 +1,932 @@
1
- # tailwind-to-style
2
-
3
- [![npm version](https://img.shields.io/npm/v/tailwind-to-style.svg)](https://www.npmjs.com/package/tailwind-to-style)
4
- [![Build Status](https://github.com/Bigetion/tailwind-to-style/workflows/CI%2FCD/badge.svg)](https://github.com/Bigetion/tailwind-to-style/actions)
5
- [![npm downloads](https://img.shields.io/npm/dm/tailwind-to-style.svg)](https://www.npmjs.com/package/tailwind-to-style)
6
- [![license](https://img.shields.io/npm/l/tailwind-to-style.svg)](https://github.com/Bigetion/tailwind-to-style/blob/main/LICENSE)
7
-
8
- `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.
9
-
10
- The library exposes two main functions and a CLI tool:
11
-
12
- 1. **`tws`**: Converts Tailwind CSS classes into inline CSS styles or JavaScript objects (JSON).
13
- 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.
14
- 3. **`twsx-cli`**: A command-line tool for generating CSS files from `twsx.*.js` files with watch mode support.
15
-
16
- ## What's New in v2.9.0
17
-
18
- - 🆕 **Responsive Selector Syntax**: Intuitive `'md:.title': 'text-lg'` format for responsive styling
19
- - 🐛 **Critical @css Bug Fix**: Perfect preservation of CSS variables, functions, and complex expressions
20
- - **Enhanced Performance**: Improved processing for large datasets and concurrent operations
21
- - 🔧 **Better Error Handling**: 100% error recovery rate for malformed inputs
22
-
23
- ## Installation
24
-
25
- To use `tailwind-to-style`, install the library using either npm or yarn:
26
-
27
- ### Using npm
28
-
29
- ```bash
30
- npm install tailwind-to-style
31
- ```
32
-
33
- ### Using yarn
34
-
35
- ```bash
36
- yarn add tailwind-to-style
37
- ```
38
-
39
- ## Core Functions
40
-
41
- ### 1. `tws`
42
-
43
- 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.
44
-
45
- #### Features of `tws`:
46
-
47
- - Converts Tailwind utility classes into **inline CSS** or **JSON style objects**.
48
-
49
- #### Usage
50
-
51
- ```javascript
52
- import { tws } from "tailwind-to-style";
53
-
54
- // Convert Tailwind classes to inline CSS
55
- const styleInline = tws("bg-white mx-auto");
56
- // Output: background-color:rgba(255, 255, 255, 1); margin-left:auto; margin-right:auto;
57
-
58
- // Convert Tailwind classes to JSON style object
59
- const styleJSON = tws("bg-white mx-auto", 1);
60
- // Output: { backgroundColor: 'rgba(255, 255, 255, 1)', marginLeft: 'auto', marginRight: 'auto' }
61
- ```
62
-
63
- - **First argument**: The string of Tailwind classes to convert.
64
- - **Second argument (optional)**: Pass `1` to get the result as a JSON object (default is inline CSS when omitted).
65
-
66
- #### Example in React:
67
-
68
- ```javascript
69
- import React from "react";
70
- import { tws } from "tailwind-to-style";
71
-
72
- const App = () => {
73
- return (
74
- <div style={tws("text-red-500 bg-blue-200 p-4", 1)}>
75
- Hello, this is styled using tailwind-to-style
76
- </div>
77
- );
78
- };
79
-
80
- export default App;
81
- ```
82
-
83
- This will apply the Tailwind classes directly as inline styles in the React component.
84
-
85
- ### 2. `twsx`
86
-
87
- `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.
88
-
89
- #### Features of `twsx`:
90
-
91
- - ✅ **Nested styles** similar to SCSS, enabling more complex CSS structures
92
- - **Grouping**: Supports grouping utilities inside parentheses `hover:(bg-blue-600 scale-105)`
93
- - ✅ **Responsive variants** (`sm`, `md`, `lg`, `xl`, `2xl`) in standard and grouping syntax
94
- - ✅ **🆕 Responsive selector syntax** (v2.9.0+): `'md:.title': 'text-lg'` format for intuitive responsive styling
95
- - ✅ **State variants** like `hover`, `focus`, `active`, `disabled`, etc.
96
- - ✅ **Dynamic utilities** such as `w-[300px]`, `bg-[rgba(0,0,0,0.5)]`, `text-[14px]`
97
- - ✅ **!important support** with `!text-red-500`, `!bg-blue-500`
98
- - ✅ **🆕 Enhanced @css directive** (v2.9.0+): Perfect CSS variables, functions, and complex expressions support
99
-
100
- #### Basic Usage
101
-
102
- ```javascript
103
- import { twsx } from "tailwind-to-style";
104
-
105
- const styles = twsx({
106
- ".card": [
107
- "bg-white p-4 rounded-lg shadow-md",
108
- {
109
- "&:hover": "shadow-xl scale-105",
110
- ".title": "text-lg font-bold text-gray-900",
111
- ".desc": "text-sm text-gray-600 mt-2",
112
- },
113
- ],
114
- });
115
-
116
- console.log(styles);
117
- ```
118
-
119
- **Output**:
120
-
121
- ```css
122
- .card {
123
- background-color: rgba(255, 255, 255, var(--bg-opacity));
124
- padding: 1rem;
125
- border-radius: 0.5rem;
126
- box-shadow:
127
- 0 4px 6px -1px rgb(0 0 0 / 0.1),
128
- 0 2px 4px -2px rgb(0 0 0 / 0.1);
129
- }
130
- .card:hover {
131
- box-shadow:
132
- 0 20px 25px -5px rgb(0 0 0 / 0.1),
133
- 0 8px 10px -6px rgb(0 0 0 / 0.1);
134
- transform: scale(1.05);
135
- }
136
- .card .title {
137
- font-size: 1.125rem;
138
- font-weight: 700;
139
- color: rgba(17, 24, 39, var(--text-opacity));
140
- }
141
- .card .desc {
142
- font-size: 0.875rem;
143
- color: rgba(75, 85, 99, var(--text-opacity));
144
- margin-top: 0.5rem;
145
- }
146
- ```
147
-
148
- #### Grouping Support
149
-
150
- Group related utilities together inside parentheses for better readability and organization:
151
-
152
- ```javascript
153
- const styles = twsx({
154
- ".button": [
155
- "bg-blue-500 text-white px-6 py-3 rounded-lg",
156
- "hover:(bg-blue-600 scale-105 shadow-lg)",
157
- "focus:(ring-2 ring-blue-300 outline-none)",
158
- "active:(bg-blue-700 scale-95)",
159
- ],
160
- });
161
- ```
162
-
163
- **Output**:
164
-
165
- ```css
166
- .button {
167
- background-color: rgba(59, 130, 246, var(--bg-opacity));
168
- color: rgba(255, 255, 255, var(--text-opacity));
169
- padding: 0.75rem 1.5rem;
170
- border-radius: 0.5rem;
171
- }
172
- .button:hover {
173
- background-color: rgba(37, 99, 235, var(--bg-opacity));
174
- transform: scale(1.05);
175
- box-shadow:
176
- 0 10px 15px -3px rgb(0 0 0 / 0.1),
177
- 0 4px 6px -4px rgb(0 0 0 / 0.1);
178
- }
179
- .button:focus {
180
- box-shadow: var(--ring-offset-shadow), var(--ring-shadow);
181
- outline: none;
182
- }
183
- .button:active {
184
- background-color: rgba(29, 78, 216, var(--bg-opacity));
185
- transform: scale(0.95);
186
- }
187
- ```
188
-
189
- #### Responsive Variants
190
-
191
- Responsive variants work seamlessly with both standard syntax and grouping syntax:
192
-
193
- ```javascript
194
- const styles = twsx({
195
- ".hero": [
196
- // Standard responsive syntax
197
- "text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl",
198
- "w-full md:w-1/2 lg:w-1/3 p-4",
199
- // Grouped responsive syntax
200
- "sm:(py-16 px-4)",
201
- "md:(py-20 px-6)",
202
- "lg:(py-24 px-8)",
203
- {
204
- h1: "font-bold text-gray-900",
205
- p: "text-gray-600 mt-4",
206
- },
207
- ],
208
- });
209
- ```
210
-
211
- **Output**:
212
-
213
- ```css
214
- .hero {
215
- font-size: 1.5rem;
216
- width: 100%;
217
- padding: 1rem;
218
- }
219
- @media (min-width: 640px) {
220
- .hero {
221
- font-size: 1.875rem;
222
- padding: 4rem 1rem;
223
- }
224
- }
225
- @media (min-width: 768px) {
226
- .hero {
227
- font-size: 2.25rem;
228
- width: 50%;
229
- padding: 5rem 1.5rem;
230
- }
231
- }
232
- @media (min-width: 1024px) {
233
- .hero {
234
- font-size: 3rem;
235
- width: 33.333333%;
236
- padding: 6rem 2rem;
237
- }
238
- }
239
- @media (min-width: 1280px) {
240
- .hero {
241
- font-size: 3.75rem;
242
- }
243
- }
244
- .hero h1 {
245
- font-weight: 700;
246
- color: rgba(17, 24, 39, var(--text-opacity));
247
- }
248
- .hero p {
249
- color: rgba(75, 85, 99, var(--text-opacity));
250
- margin-top: 1rem;
251
- }
252
- ```
253
-
254
- #### 🆕 Responsive Selector Syntax (v2.9.0+)
255
-
256
- **New feature**: You can now use responsive breakpoints directly in selectors for more intuitive responsive styling:
257
-
258
- ```javascript
259
- const styles = twsx({
260
- // New responsive selector syntax
261
- "md:.title": "text-lg font-bold",
262
- "lg:.title": "text-xl",
263
- "xl:.title": "text-2xl",
264
-
265
- // Equivalent to the traditional syntax:
266
- ".title": "md:text-lg md:font-bold lg:text-xl xl:text-2xl"
267
- });
268
- ```
269
-
270
- This new syntax automatically converts responsive selectors to traditional Tailwind responsive classes and generates proper media queries:
271
-
272
- ```css
273
- .title {
274
- /* Base styles if any */
275
- }
276
- @media (min-width: 768px) {
277
- .title {
278
- font-size: 1.125rem;
279
- font-weight: 700;
280
- }
281
- }
282
- @media (min-width: 1024px) {
283
- .title {
284
- font-size: 1.25rem;
285
- }
286
- }
287
- @media (min-width: 1280px) {
288
- .title {
289
- font-size: 1.5rem;
290
- }
291
- }
292
- ```
293
-
294
- **Benefits of Responsive Selector Syntax:**
295
- - ✅ More intuitive and organized responsive code
296
- - ✅ Better separation of breakpoint-specific styles
297
- - Easier to maintain complex responsive designs
298
- - ✅ Backward compatible with existing syntax
299
- - ✅ Works with all breakpoints: `sm`, `md`, `lg`, `xl`, `2xl`
300
-
301
- ### Performance Utilities
302
-
303
- The library includes performance optimization features:
304
-
305
- #### Inject Option
306
-
307
- Control CSS output location with the `inject` option:
308
-
309
- ```javascript
310
- import { tws, twsx } from "tailwind-to-style";
311
-
312
- // Auto-inject into document head (default)
313
- const styles1 = tws("bg-blue-500 text-white p-4");
314
-
315
- // Skip injection - returns CSS only
316
- const styles2 = tws("bg-red-500 text-black p-2", { inject: false });
317
-
318
- // Custom injection target
319
- const targetElement = document.getElementById("custom-styles");
320
- const styles3 = tws("bg-green-500 text-yellow p-3", { inject: targetElement });
321
- ```
322
-
323
- #### Performance Monitoring
324
-
325
- ```javascript
326
- import { tws } from "tailwind-to-style";
327
-
328
- // Enable performance logging
329
- const start = performance.now();
330
- const styles = tws("complex-classes here...");
331
- const end = performance.now();
332
- console.log(`Generation time: ${end - start}ms`);
333
- ```
334
-
335
- ## Advanced `@css` Directive
336
-
337
- 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.
338
-
339
- ### 🆕 Enhanced CSS Support (v2.9.0+)
340
-
341
- **Major improvements in CSS handling:**
342
- - ✅ **Perfect CSS Variables**: `var(--custom-property)` syntax fully preserved
343
- - ✅ **CSS Functions**: `calc()`, `rgba()`, `linear-gradient()`, `clamp()` etc. work flawlessly
344
- - ✅ **Complex Expressions**: Multi-function CSS expressions preserved accurately
345
- - ✅ **Zero Corruption**: Fixed critical bug where CSS values were being corrupted
346
-
347
- **Before v2.9.0** (corrupted):
348
- ```css
349
- /* This would be corrupted */
350
- background: -var--primary; /* ❌ WRONG */
351
- color: rgba-255,0,0,0.5; /* ❌ WRONG */
352
- ```
353
-
354
- **v2.9.0+** (perfect preservation):
355
- ```css
356
- /* Now works perfectly */
357
- background: var(--primary); /* CORRECT */
358
- color: rgba(255,0,0,0.5); /* ✅ CORRECT */
359
- transform: calc(100% - 20px); /* ✅ CORRECT */
360
- ```
361
-
362
- ### Usage Examples
363
-
364
- There are several ways to use the `@css` feature:
365
-
366
- 1. **As a nested object inside selectors**:
367
-
368
- ```javascript
369
- const styles = twsx({
370
- ".button": [
371
- "bg-blue-500 text-white rounded-md",
372
- {
373
- "@css": {
374
- transition: "all 0.3s ease-in-out",
375
- "will-change": "transform, opacity",
376
- },
377
- "&:hover": "bg-blue-600",
378
- },
379
- ],
380
- });
381
- ```
382
-
383
- **Output**:
384
-
385
- ```css
386
- .button {
387
- background-color: #3b82f6;
388
- color: white;
389
- border-radius: 0.375rem;
390
- transition: all 0.3s ease-in-out;
391
- will-change: transform, opacity;
392
- }
393
- .button:hover {
394
- background-color: #2563eb;
395
- }
396
- ```
397
-
398
- 2. **As a direct property in the selector**:
399
-
400
- ```javascript
401
- const styles = twsx({
402
- ".button @css transition": "all 0.3s ease-in-out",
403
- ".button": "bg-blue-500 text-white rounded-md",
404
- ".button:hover": "bg-blue-600",
405
- });
406
- ```
407
-
408
- This syntax is especially useful when you need to add just a single CSS property that isn't available in Tailwind.
409
-
410
- 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.
411
-
412
- #### Advanced `@css` Examples:
413
-
414
- You can combine `@css` with state variants:
415
-
416
- ```javascript
417
- const styles = twsx({
418
- ".modal": [
419
- "bg-white rounded-lg shadow-xl",
420
- {
421
- "@css": {
422
- transform: "translateX(0px)",
423
- transition: "all 0.3s ease-out",
424
- "will-change": "transform, opacity",
425
- },
426
- "&.hidden": [
427
- "opacity-0",
428
- {
429
- "@css": {
430
- transform: "translateX(-100px)",
431
- },
432
- },
433
- ],
434
- },
435
- ],
436
- });
437
- ```
438
-
439
- **Output**:
440
-
441
- ```css
442
- .modal {
443
- background-color: white;
444
- border-radius: 0.5rem;
445
- box-shadow:
446
- 0 20px 25px -5px rgba(0, 0, 0, 0.1),
447
- 0 10px 10px -5px rgba(0, 0, 0, 0.04);
448
- transform: translateX(0px);
449
- transition: all 0.3s ease-out;
450
- will-change: transform, opacity;
451
- }
452
- .modal.hidden {
453
- opacity: 0;
454
- transform: translateX(-100px);
455
- }
456
- ```
457
-
458
- #### 🆕 CSS Variables & Functions Examples (v2.9.0+)
459
-
460
- With the enhanced `@css` directive, you can now use complex CSS features:
461
-
462
- ```javascript
463
- const styles = twsx({
464
- ".theme-component": {
465
- "@css": {
466
- // CSS Variables - now work perfectly!
467
- "--primary-color": "#3b82f6",
468
- "--secondary-color": "#8b5cf6",
469
- "--border-radius": "0.5rem",
470
-
471
- // CSS Functions - fully preserved!
472
- "background": "linear-gradient(135deg, var(--primary-color), var(--secondary-color))",
473
- "border-radius": "var(--border-radius)",
474
- "box-shadow": "0 4px 20px rgba(0, 0, 0, 0.15)",
475
- "transform": "translateY(calc(-1 * var(--spacing, 10px)))",
476
-
477
- // Complex CSS expressions
478
- "width": "clamp(200px, 50vw, 800px)",
479
- "padding": "calc(1rem + 2vw)",
480
- "color": "hsl(220, 100%, 50%)"
481
- }
482
- },
483
-
484
- ".dynamic-grid": {
485
- "@css": {
486
- "display": "grid",
487
- "grid-template-columns": "repeat(auto-fit, minmax(250px, 1fr))",
488
- "gap": "clamp(1rem, 5vw, 3rem)",
489
- "grid-auto-rows": "minmax(200px, auto)"
490
- }
491
- }
492
- });
493
- ```
494
-
495
- **Output** (perfectly preserved CSS):
496
-
497
- ```css
498
- .theme-component {
499
- --primary-color: #3b82f6;
500
- --secondary-color: #8b5cf6;
501
- --border-radius: 0.5rem;
502
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
503
- border-radius: var(--border-radius);
504
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
505
- transform: translateY(calc(-1 * var(--spacing, 10px)));
506
- width: clamp(200px, 50vw, 800px);
507
- padding: calc(1rem + 2vw);
508
- color: hsl(220, 100%, 50%);
509
- }
510
- .dynamic-grid {
511
- display: grid;
512
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
513
- gap: clamp(1rem, 5vw, 3rem);
514
- grid-auto-rows: minmax(200px, auto);
515
- }
516
- ```
517
-
518
- For responsive styles, you can use standard Tailwind responsive utilities within your classes:
519
-
520
- ```javascript
521
- const styles = twsx({
522
- ".responsive-box": "w-full md:w-1/2 lg:w-1/3 p-4 bg-blue-500",
523
- });
524
- ```
525
-
526
- 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.
527
-
528
- ### Inject Option (Browser Only)
529
-
530
- 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.
531
-
532
- You can control this behavior with the `inject` option:
533
-
534
- ```js
535
- // Auto-inject (default)
536
- twsx({ ... }) // CSS is injected automatically
537
-
538
- // Disable auto-inject
539
- twsx({ ... }, { inject: false }) // CSS is NOT injected, just returned as string
540
- ```
541
-
542
- - **inject: true** (default): CSS is injected into the page (browser only).
543
- - **inject: false**: CSS is only returned as a string, not injected. Useful for SSR, testing, or custom handling.
544
-
545
- > Note: This option only affects browser usage. In Node.js or SSR, no injection occurs.
546
-
547
- ## Performance Monitoring & Debugging (v2.7.0+)
548
-
549
- 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.
550
-
551
- ### Performance Utils
552
-
553
- ```javascript
554
- import { performanceUtils } from "tailwind-to-style";
555
-
556
- // Enable performance logging (logs operations > 5ms as warnings)
557
- performanceUtils.enablePerformanceLogging(true);
558
-
559
- // Get cache and injection statistics
560
- const stats = performanceUtils.getStats();
561
- console.log(stats);
562
- // Output:
563
- // {
564
- // cacheStats: {
565
- // cssResolution: 45,
566
- // configOptions: 2,
567
- // parseSelector: 23,
568
- // encodeBracket: 12,
569
- // decodeBracket: 8
570
- // },
571
- // injectionStats: {
572
- // uniqueStylesheets: 15
573
- // }
574
- // }
575
-
576
- // Clear all caches (useful for memory management)
577
- performanceUtils.clearCaches();
578
- ```
579
-
580
- ### Performance Metrics
581
-
582
- The library automatically tracks performance for key operations:
583
-
584
- - **tws:total** - Total execution time for `tws()`
585
- - **tws:parse** - Time spent parsing classes
586
- - **tws:process** - Time spent processing classes
587
- - **twsx:total** - Total execution time for `twsx()`
588
- - **twsx:flatten** - Time spent flattening objects
589
- - **twsx:generate** - Time spent generating CSS
590
- - **css:inject** - Time spent injecting CSS to DOM
591
-
592
- ### Debounced Functions
593
-
594
- For high-frequency usage, use the debounced versions:
595
-
596
- ```javascript
597
- import { debouncedTws, debouncedTwsx } from "tailwind-to-style";
598
-
599
- // Debounced versions (50ms for tws, 100ms for twsx)
600
- const styles = debouncedTws("bg-red-500 p-4");
601
- const complexStyles = debouncedTwsx({ ".card": "bg-white p-6" });
602
- ```
603
-
604
- ### Example: Performance Monitoring
605
-
606
- ```javascript
607
- import { tws, twsx, performanceUtils } from "tailwind-to-style";
608
-
609
- // Enable monitoring
610
- performanceUtils.enablePerformanceLogging(true);
611
-
612
- // Your code that uses tws/twsx
613
- const styles = tws("bg-gradient-to-r from-purple-400 to-pink-500 p-8");
614
- const complexStyles = twsx({
615
- ".hero": [
616
- "bg-gradient-to-br from-indigo-900 to-purple-900 min-h-screen",
617
- {
618
- h1: "text-6xl font-bold text-white md:text-4xl",
619
- "@css": {
620
- transition: "font-size 0.3s ease-in-out",
621
- },
622
- },
623
- ],
624
- });
625
-
626
- // Check performance stats
627
- console.log(performanceUtils.getStats());
628
- ```
629
-
630
- This will automatically log warnings for operations taking longer than 5ms and provide insights into cache usage and performance bottlenecks.
631
-
632
- # Build-Time Plugins: Vite & Webpack
633
-
634
- ### Automated Modular CSS Generation
635
-
636
- 1. Create JS files with `twsx.` prefix in your project (e.g., `twsx.card.js`, `twsx.button.js`) anywhere in your `src/` folder.
637
- 2. Use the Vite/Webpack plugin from the `plugins/` folder to automatically generate CSS on every build/rebuild.
638
- 3. Each JS file will generate its own CSS file in the specified output directory (default: `src/styles/`).
639
- 4. Import the generated CSS files directly in your components or bundle them as needed.
640
-
641
- #### Vite Plugin Usage Example
642
-
643
- Add the plugin to your `vite.config.js`:
644
- ```js
645
- import twsxPlugin from 'tailwind-to-style/plugins/vite-twsx';
646
-
647
- export default {
648
- plugins: [
649
- twsxPlugin({
650
- inputDir: 'src',
651
- outputDir: 'src/styles',
652
- preserveStructure: false // Set to true to generate CSS next to JS files
653
- })
654
- ]
655
- };
656
- ```
657
-
658
- **Configuration Options:**
659
- - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
660
- - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
661
- - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
662
-
663
- **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
664
- **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
665
-
666
- Import in your components:
667
- ```js
668
- // Default mode
669
- import './styles/twsx.card.css';
670
- import './styles/twsx.button.css';
671
-
672
- // Preserve structure mode
673
- import './twsx.card.css'; // If in same directory
674
- ```
675
-
676
- #### Webpack Plugin Usage Example
677
-
678
- Add the plugin to your `webpack.config.js`:
679
- ```js
680
- import TwsxPlugin from 'tailwind-to-style/plugins/webpack-twsx';
681
-
682
- module.exports = {
683
- plugins: [
684
- new TwsxPlugin({
685
- inputDir: 'src',
686
- outputDir: 'src/styles',
687
- preserveStructure: false // Set to true to generate CSS next to JS files
688
- })
689
- ]
690
- };
691
- ```
692
-
693
- **Configuration Options:**
694
- - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
695
- - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
696
- - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
697
-
698
- **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
699
- **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
700
-
701
- Import in your components:
702
- ```js
703
- // Default mode
704
- import './styles/twsx.card.css';
705
- import './styles/twsx.button.css';
706
-
707
- // Preserve structure mode
708
- import './twsx.card.css'; // If in same directory
709
- ```
710
-
711
- ## Build-Time CSS Generation via Script
712
-
713
- 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.
714
-
715
- ### Script: tailwind-to-style/lib/twsx-cli.js (Legacy)
716
-
717
- > **💡 Recommended:** Use `npx twsx-cli` instead of calling the script directly.
718
-
719
- 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.
720
-
721
- #### How to Use
722
-
723
- 1. Create JS files with `twsx.` prefix containing style objects anywhere in your `src/` folder (e.g., `src/components/twsx.card.js`).
724
-
725
- 2. **One-time Build:**
726
- ```bash
727
- node tailwind-to-style/lib/twsx-cli.js
728
- ```
729
-
730
- 3. **Watch Mode (Auto-rebuild on file changes):**
731
- ```bash
732
- node tailwind-to-style/lib/twsx-cli.js --watch
733
- ```
734
-
735
- 4. **Preserve Structure Mode (Generate CSS next to JS files):**
736
- ```bash
737
- # One-time build with preserve structure
738
- node tailwind-to-style/lib/twsx-cli.js --preserve-structure
739
-
740
- # Watch mode with preserve structure
741
- node tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure
742
- ```
743
-
744
- You can configure input and output directories using environment variables:
745
- ```bash
746
- TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/twsx-cli.js --watch
747
- ```
748
-
749
- Or use environment variables for preserve structure:
750
- ```bash
751
- TWSX_PRESERVE_STRUCTURE=true node tailwind-to-style/lib/twsx-cli.js --watch
752
- ```
753
-
754
- 5. **Output locations:**
755
-
756
- **Default mode:** CSS files will be in the output directory (default: `src/styles/`):
757
- ```
758
- src/styles/twsx.card.css
759
- src/styles/twsx.button.css
760
- ```
761
-
762
- **Preserve structure mode:** CSS files will be generated next to their JS counterparts:
763
- ```
764
- src/components/Button/twsx.button.js → src/components/Button/twsx.button.css
765
- src/components/Card/twsx.card.js → src/components/Card/twsx.card.css
766
- ```
767
-
768
- 5. Import the generated CSS files in your components:
769
-
770
- **Default mode:**
771
- ```js
772
- import './styles/twsx.card.css';
773
- import './styles/twsx.button.css';
774
- ```
775
-
776
- **Preserve structure mode:**
777
- ```js
778
- // In src/components/Button/Button.jsx
779
- import './twsx.button.css';
780
-
781
- // In src/components/Card/Card.jsx
782
- import './twsx.card.css';
783
- ```
784
-
785
- #### Usage in Different Projects
786
-
787
- **React/Next.js/Vue/Any Project:**
788
-
789
- 1. Install the package:
790
- ```bash
791
- npm install tailwind-to-style
792
- ```
793
-
794
- 2. Add to your `package.json`:
795
- ```json
796
- {
797
- "scripts": {
798
- "twsx:build": "node node_modules/tailwind-to-style/lib/twsx-cli.js",
799
- "twsx:watch": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch",
800
- "twsx:preserve": "node node_modules/tailwind-to-style/lib/twsx-cli.js --preserve-structure",
801
- "twsx:dev": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure",
802
- "dev": "npm run twsx:watch & next dev"
803
- }
804
- }
805
- ```
806
-
807
- 3. For development with auto-rebuild:
808
- ```bash
809
- npm run twsx:watch
810
- ```
811
-
812
- 4. For production build:
813
- ```bash
814
- npm run twsx:build
815
- ```
816
-
817
- **VS Code Integration:**
818
- Add to your workspace settings (`.vscode/settings.json`):
819
- ```json
820
- {
821
- "emeraldwalk.runonsave": {
822
- "commands": [
823
- {
824
- "match": "twsx\\..*\\.js$",
825
- "cmd": "npm run twsx:build"
826
- }
827
- ]
828
- }
829
- }
830
- ```
831
-
832
- #### Automatic Integration
833
-
834
- You can add this script to the build section in your `package.json`:
835
-
836
- ```json
837
- {
838
- "scripts": {
839
- "build-css": "node tailwind-to-style/lib/twsx-cli.js"
840
- }
841
- }
842
- ```
843
-
844
- Then run:
845
-
846
- ```bash
847
- npm run build-css
848
- ```
849
-
850
- This script is suitable for CI/CD workflows, pre-build steps, or manually generating CSS without a bundler plugin.
851
-
852
- ## License
853
-
854
- ## Contributing
855
-
856
- Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
857
-
858
- ## License
859
-
860
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
861
-
862
- ---
863
-
864
- Feel free to contribute or raise issues on the [GitHub repository](https://github.com/Bigetion/tailwind-to-style).
1
+ # tailwind-to-style
2
+
3
+ [📦 View on npm](https://www.npmjs.com/package/tailwind-to-style)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/tailwind-to-style.svg)](https://www.npmjs.com/package/tailwind-to-style)
6
+ [![Build Status](https://github.com/Bigetion/tailwind-to-style/workflows/CI%2FCD/badge.svg)](https://github.com/Bigetion/tailwind-to-style/actions)
7
+ [![npm downloads](https://img.shields.io/npm/dm/tailwind-to-style.svg)](https://www.npmjs.com/package/tailwind-to-style)
8
+ [![license](https://img.shields.io/npm/l/tailwind-to-style.svg)](https://github.com/Bigetion/tailwind-to-style/blob/main/LICENSE)
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.
11
+
12
+ The library exposes two main functions and a CLI tool:
13
+
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.
17
+
18
+ ## What's New in v2.9.0
19
+
20
+ - 🆕 **Responsive Selector Syntax**: Intuitive `'md:.title': 'text-lg'` format for responsive styling
21
+ - 🐛 **Critical @css Bug Fix**: Perfect preservation of CSS variables, functions, and complex expressions
22
+ - ⚡ **Enhanced Performance**: Improved processing for large datasets and concurrent operations
23
+ - 🔧 **Better Error Handling**: 100% error recovery rate for malformed inputs
24
+
25
+ ## Installation
26
+
27
+ To use `tailwind-to-style`, install the library using either npm or yarn:
28
+
29
+ ### Using npm
30
+
31
+ ```bash
32
+ npm install tailwind-to-style
33
+ ```
34
+
35
+ ### Using yarn
36
+
37
+ ```bash
38
+ yarn add tailwind-to-style
39
+ ```
40
+
41
+ ## Core Functions
42
+
43
+ ### 1. `tws`
44
+
45
+ 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.
46
+
47
+ #### Features of `tws`:
48
+
49
+ - Converts Tailwind utility classes into **inline CSS** or **JSON style objects**.
50
+
51
+ #### Usage
52
+
53
+ ```javascript
54
+ import { tws } from "tailwind-to-style";
55
+
56
+ // Convert Tailwind classes to inline CSS
57
+ const styleInline = tws("bg-white mx-auto");
58
+ // Output: background-color:rgba(255, 255, 255, 1); margin-left:auto; margin-right:auto;
59
+
60
+ // Convert Tailwind classes to JSON style object
61
+ const styleJSON = tws("bg-white mx-auto", 1);
62
+ // Output: { backgroundColor: 'rgba(255, 255, 255, 1)', marginLeft: 'auto', marginRight: 'auto' }
63
+ ```
64
+
65
+ - **First argument**: The string of Tailwind classes to convert.
66
+ - **Second argument (optional)**: Pass `1` to get the result as a JSON object (default is inline CSS when omitted).
67
+
68
+ #### Example in React:
69
+
70
+ ```javascript
71
+ import React from "react";
72
+ import { tws } from "tailwind-to-style";
73
+
74
+ const App = () => {
75
+ return (
76
+ <div style={tws("text-red-500 bg-blue-200 p-4", 1)}>
77
+ Hello, this is styled using tailwind-to-style
78
+ </div>
79
+ );
80
+ };
81
+
82
+ export default App;
83
+ ```
84
+
85
+ This will apply the Tailwind classes directly as inline styles in the React component.
86
+
87
+
88
+ ### 2. `twsx`
89
+
90
+ `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.
91
+
92
+ #### Features of `twsx`:
93
+
94
+ - ✅ **Nested styles** similar to SCSS, enabling more complex CSS structures
95
+ - ✅ **Grouping**: Supports grouping utilities inside parentheses `hover:(bg-blue-600 scale-105)`
96
+ - ✅ **Responsive variants** (`sm`, `md`, `lg`, `xl`, `2xl`) in standard and grouping syntax
97
+ - ✅ **🆕 Responsive selector syntax** (v2.9.0+): `'md:.title': 'text-lg'` format for intuitive responsive styling
98
+ - ✅ **State variants** like `hover`, `focus`, `active`, `disabled`, etc.
99
+ - ✅ **Dynamic utilities** such as `w-[300px]`, `bg-[rgba(0,0,0,0.5)]`, `text-[14px]`
100
+ - **!important support** with `!text-red-500`, `!bg-blue-500`
101
+ - ✅ **🆕 Enhanced @css directive** (v2.9.0+): Perfect CSS variables, functions, and complex expressions support
102
+
103
+ #### Basic Usage
104
+
105
+ ```javascript
106
+ import { twsx } from "tailwind-to-style";
107
+
108
+ const styles = twsx({
109
+ ".card": [
110
+ "bg-white p-4 rounded-lg shadow-md",
111
+ {
112
+ "&:hover": "shadow-xl scale-105",
113
+ ".title": "text-lg font-bold text-gray-900",
114
+ ".desc": "text-sm text-gray-600 mt-2",
115
+ },
116
+ ],
117
+ });
118
+
119
+ console.log(styles);
120
+ ```
121
+
122
+ **Output**:
123
+
124
+ ```css
125
+ .card {
126
+ background-color: rgba(255, 255, 255, var(--bg-opacity));
127
+ padding: 1rem;
128
+ border-radius: 0.5rem;
129
+ box-shadow:
130
+ 0 4px 6px -1px rgb(0 0 0 / 0.1),
131
+ 0 2px 4px -2px rgb(0 0 0 / 0.1);
132
+ }
133
+ .card:hover {
134
+ box-shadow:
135
+ 0 20px 25px -5px rgb(0 0 0 / 0.1),
136
+ 0 8px 10px -6px rgb(0 0 0 / 0.1);
137
+ transform: scale(1.05);
138
+ }
139
+ .card .title {
140
+ font-size: 1.125rem;
141
+ font-weight: 700;
142
+ color: rgba(17, 24, 39, var(--text-opacity));
143
+ }
144
+ .card .desc {
145
+ font-size: 0.875rem;
146
+ color: rgba(75, 85, 99, var(--text-opacity));
147
+ margin-top: 0.5rem;
148
+ }
149
+ ```
150
+
151
+ #### Grouping Support
152
+
153
+ Group related utilities together inside parentheses for better readability and organization:
154
+
155
+ ```javascript
156
+ const styles = twsx({
157
+ ".button": [
158
+ "bg-blue-500 text-white px-6 py-3 rounded-lg",
159
+ "hover:(bg-blue-600 scale-105 shadow-lg)",
160
+ "focus:(ring-2 ring-blue-300 outline-none)",
161
+ "active:(bg-blue-700 scale-95)",
162
+ ],
163
+ });
164
+ ```
165
+
166
+ **Output**:
167
+
168
+ ```css
169
+ .button {
170
+ background-color: rgba(59, 130, 246, var(--bg-opacity));
171
+ color: rgba(255, 255, 255, var(--text-opacity));
172
+ padding: 0.75rem 1.5rem;
173
+ border-radius: 0.5rem;
174
+ }
175
+ .button:hover {
176
+ background-color: rgba(37, 99, 235, var(--bg-opacity));
177
+ transform: scale(1.05);
178
+ box-shadow:
179
+ 0 10px 15px -3px rgb(0 0 0 / 0.1),
180
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
181
+ }
182
+ .button:focus {
183
+ box-shadow: var(--ring-offset-shadow), var(--ring-shadow);
184
+ outline: none;
185
+ }
186
+ .button:active {
187
+ background-color: rgba(29, 78, 216, var(--bg-opacity));
188
+ transform: scale(0.95);
189
+ }
190
+ ```
191
+
192
+ #### Responsive Variants
193
+
194
+ Responsive variants work seamlessly with both standard syntax and grouping syntax:
195
+
196
+ ```javascript
197
+ const styles = twsx({
198
+ ".hero": [
199
+ // Standard responsive syntax
200
+ "text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl",
201
+ "w-full md:w-1/2 lg:w-1/3 p-4",
202
+ // Grouped responsive syntax
203
+ "sm:(py-16 px-4)",
204
+ "md:(py-20 px-6)",
205
+ "lg:(py-24 px-8)",
206
+ {
207
+ h1: "font-bold text-gray-900",
208
+ p: "text-gray-600 mt-4",
209
+ },
210
+ ],
211
+ });
212
+ ```
213
+
214
+ **Output**:
215
+
216
+ ```css
217
+ .hero {
218
+ font-size: 1.5rem;
219
+ width: 100%;
220
+ padding: 1rem;
221
+ }
222
+ @media (min-width: 640px) {
223
+ .hero {
224
+ font-size: 1.875rem;
225
+ padding: 4rem 1rem;
226
+ }
227
+ }
228
+ @media (min-width: 768px) {
229
+ .hero {
230
+ font-size: 2.25rem;
231
+ width: 50%;
232
+ padding: 5rem 1.5rem;
233
+ }
234
+ }
235
+ @media (min-width: 1024px) {
236
+ .hero {
237
+ font-size: 3rem;
238
+ width: 33.333333%;
239
+ padding: 6rem 2rem;
240
+ }
241
+ }
242
+ @media (min-width: 1280px) {
243
+ .hero {
244
+ font-size: 3.75rem;
245
+ }
246
+ }
247
+ .hero h1 {
248
+ font-weight: 700;
249
+ color: rgba(17, 24, 39, var(--text-opacity));
250
+ }
251
+ .hero p {
252
+ color: rgba(75, 85, 99, var(--text-opacity));
253
+ margin-top: 1rem;
254
+ }
255
+ ```
256
+
257
+ #### 🆕 Responsive Selector Syntax (v2.9.0+)
258
+
259
+ **New feature**: You can now use responsive breakpoints directly in selectors for more intuitive responsive styling:
260
+
261
+ ```javascript
262
+ const styles = twsx({
263
+ // New responsive selector syntax
264
+ "md:.title": "text-lg font-bold",
265
+ "lg:.title": "text-xl",
266
+ "xl:.title": "text-2xl",
267
+
268
+ // Equivalent to the traditional syntax:
269
+ ".title": "md:text-lg md:font-bold lg:text-xl xl:text-2xl"
270
+ });
271
+ ```
272
+
273
+ This new syntax automatically converts responsive selectors to traditional Tailwind responsive classes and generates proper media queries:
274
+
275
+ ```css
276
+ .title {
277
+ /* Base styles if any */
278
+ }
279
+ @media (min-width: 768px) {
280
+ .title {
281
+ font-size: 1.125rem;
282
+ font-weight: 700;
283
+ }
284
+ }
285
+ @media (min-width: 1024px) {
286
+ .title {
287
+ font-size: 1.25rem;
288
+ }
289
+ }
290
+ @media (min-width: 1280px) {
291
+ .title {
292
+ font-size: 1.5rem;
293
+ }
294
+ }
295
+ ```
296
+
297
+ **Benefits of Responsive Selector Syntax:**
298
+ - ✅ More intuitive and organized responsive code
299
+ - ✅ Better separation of breakpoint-specific styles
300
+ - ✅ Easier to maintain complex responsive designs
301
+ - Backward compatible with existing syntax
302
+ - ✅ Works with all breakpoints: `sm`, `md`, `lg`, `xl`, `2xl`
303
+
304
+ #### Handling Dark and Light Mode
305
+
306
+ `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.
307
+
308
+ **Usage Example:**
309
+
310
+ ```javascript
311
+ import { twsx } from "tailwind-to-style";
312
+
313
+ const styles = twsx({
314
+ ".card": [
315
+ "bg-white text-gray-900 dark:bg-gray-900 dark:text-white", // Using dark: prefix
316
+ { ".dark &": "bg-gray-900 text-white border-gray-700" }, // Or .dark selector
317
+ ],
318
+ // Grouping is also supported
319
+ ".button": "bg-blue-500 text-white dark:(bg-gray-900 text-yellow-200)",
320
+ });
321
+ ```
322
+
323
+ **Explanation:**
324
+ - The `dark:` prefix will automatically generate CSS that is only active if the parent has the `dark` class (e.g. `<html class="dark">`).
325
+ - The `.dark &` selector can also be used for more flexibility.
326
+ - Grouping `dark:(...)` will be automatically expanded into multiple dark classes.
327
+
328
+ **CSS Output:**
329
+ ```css
330
+ .card {
331
+ background-color: #fff;
332
+ color: #111827;
333
+ }
334
+ .dark .card {
335
+ background-color: #111827;
336
+ color: #fff;
337
+ border-color: #374151;
338
+ }
339
+ .button {
340
+ background-color: #3b82f6;
341
+ color: #fff;
342
+ }
343
+ .dark .button {
344
+ background-color: #111827;
345
+ color: #fde68a;
346
+ }
347
+ ```
348
+
349
+ **Enable dark mode** by adding the `dark` class to the root element (usually `<html class="dark">`).
350
+
351
+ ### Performance Utilities
352
+
353
+ The library includes performance optimization features:
354
+
355
+ #### Inject Option
356
+
357
+ Control CSS output location with the `inject` option:
358
+
359
+ ```javascript
360
+ import { tws, twsx } from "tailwind-to-style";
361
+
362
+ // Auto-inject into document head (default)
363
+ const styles1 = tws("bg-blue-500 text-white p-4");
364
+
365
+ // Skip injection - returns CSS only
366
+ const styles2 = tws("bg-red-500 text-black p-2", { inject: false });
367
+
368
+ // Custom injection target
369
+ const targetElement = document.getElementById("custom-styles");
370
+ const styles3 = tws("bg-green-500 text-yellow p-3", { inject: targetElement });
371
+ ```
372
+
373
+ #### Performance Monitoring
374
+
375
+ ```javascript
376
+ import { tws } from "tailwind-to-style";
377
+
378
+ // Enable performance logging
379
+ const start = performance.now();
380
+ const styles = tws("complex-classes here...");
381
+ const end = performance.now();
382
+ console.log(`Generation time: ${end - start}ms`);
383
+ ```
384
+
385
+ ## Advanced `@css` Directive
386
+
387
+ 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.
388
+
389
+ ### 🆕 Enhanced CSS Support (v2.9.0+)
390
+
391
+ **Major improvements in CSS handling:**
392
+ - ✅ **Perfect CSS Variables**: `var(--custom-property)` syntax fully preserved
393
+ - ✅ **CSS Functions**: `calc()`, `rgba()`, `linear-gradient()`, `clamp()` etc. work flawlessly
394
+ - ✅ **Complex Expressions**: Multi-function CSS expressions preserved accurately
395
+ - ✅ **Zero Corruption**: Fixed critical bug where CSS values were being corrupted
396
+
397
+ **Before v2.9.0** (corrupted):
398
+ ```css
399
+ /* This would be corrupted */
400
+ background: -var--primary; /* ❌ WRONG */
401
+ color: rgba-255,0,0,0.5; /* WRONG */
402
+ ```
403
+
404
+ **v2.9.0+** (perfect preservation):
405
+ ```css
406
+ /* Now works perfectly */
407
+ background: var(--primary); /* ✅ CORRECT */
408
+ color: rgba(255,0,0,0.5); /* CORRECT */
409
+ transform: calc(100% - 20px); /* ✅ CORRECT */
410
+ ```
411
+
412
+ ### Usage Examples
413
+
414
+ There are several ways to use the `@css` feature:
415
+
416
+ 1. **As a nested object inside selectors**:
417
+
418
+ ```javascript
419
+ const styles = twsx({
420
+ ".button": [
421
+ "bg-blue-500 text-white rounded-md",
422
+ {
423
+ "@css": {
424
+ transition: "all 0.3s ease-in-out",
425
+ "will-change": "transform, opacity",
426
+ },
427
+ "&:hover": "bg-blue-600",
428
+ },
429
+ ],
430
+ });
431
+ ```
432
+
433
+ **Output**:
434
+
435
+ ```css
436
+ .button {
437
+ background-color: #3b82f6;
438
+ color: white;
439
+ border-radius: 0.375rem;
440
+ transition: all 0.3s ease-in-out;
441
+ will-change: transform, opacity;
442
+ }
443
+ .button:hover {
444
+ background-color: #2563eb;
445
+ }
446
+ ```
447
+
448
+ 2. **As a direct property in the selector**:
449
+
450
+ ```javascript
451
+ const styles = twsx({
452
+ ".button @css transition": "all 0.3s ease-in-out",
453
+ ".button": "bg-blue-500 text-white rounded-md",
454
+ ".button:hover": "bg-blue-600",
455
+ });
456
+ ```
457
+
458
+ This syntax is especially useful when you need to add just a single CSS property that isn't available in Tailwind.
459
+
460
+ 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.
461
+
462
+ #### Advanced `@css` Examples:
463
+
464
+ You can combine `@css` with state variants:
465
+
466
+ ```javascript
467
+ const styles = twsx({
468
+ ".modal": [
469
+ "bg-white rounded-lg shadow-xl",
470
+ {
471
+ "@css": {
472
+ transform: "translateX(0px)",
473
+ transition: "all 0.3s ease-out",
474
+ "will-change": "transform, opacity",
475
+ },
476
+ "&.hidden": [
477
+ "opacity-0",
478
+ {
479
+ "@css": {
480
+ transform: "translateX(-100px)",
481
+ },
482
+ },
483
+ ],
484
+ },
485
+ ],
486
+ });
487
+ ```
488
+
489
+ **Output**:
490
+
491
+ ```css
492
+ .modal {
493
+ background-color: white;
494
+ border-radius: 0.5rem;
495
+ box-shadow:
496
+ 0 20px 25px -5px rgba(0, 0, 0, 0.1),
497
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04);
498
+ transform: translateX(0px);
499
+ transition: all 0.3s ease-out;
500
+ will-change: transform, opacity;
501
+ }
502
+ .modal.hidden {
503
+ opacity: 0;
504
+ transform: translateX(-100px);
505
+ }
506
+ ```
507
+
508
+ #### 🆕 CSS Variables & Functions Examples (v2.9.0+)
509
+
510
+ With the enhanced `@css` directive, you can now use complex CSS features:
511
+
512
+ ```javascript
513
+ const styles = twsx({
514
+ ".theme-component": {
515
+ "@css": {
516
+ // CSS Variables - now work perfectly!
517
+ "--primary-color": "#3b82f6",
518
+ "--secondary-color": "#8b5cf6",
519
+ "--border-radius": "0.5rem",
520
+
521
+ // CSS Functions - fully preserved!
522
+ "background": "linear-gradient(135deg, var(--primary-color), var(--secondary-color))",
523
+ "border-radius": "var(--border-radius)",
524
+ "box-shadow": "0 4px 20px rgba(0, 0, 0, 0.15)",
525
+ "transform": "translateY(calc(-1 * var(--spacing, 10px)))",
526
+
527
+ // Complex CSS expressions
528
+ "width": "clamp(200px, 50vw, 800px)",
529
+ "padding": "calc(1rem + 2vw)",
530
+ "color": "hsl(220, 100%, 50%)"
531
+ }
532
+ },
533
+
534
+ ".dynamic-grid": {
535
+ "@css": {
536
+ "display": "grid",
537
+ "grid-template-columns": "repeat(auto-fit, minmax(250px, 1fr))",
538
+ "gap": "clamp(1rem, 5vw, 3rem)",
539
+ "grid-auto-rows": "minmax(200px, auto)"
540
+ }
541
+ }
542
+ });
543
+ ```
544
+
545
+ **Output** (perfectly preserved CSS):
546
+
547
+ ```css
548
+ .theme-component {
549
+ --primary-color: #3b82f6;
550
+ --secondary-color: #8b5cf6;
551
+ --border-radius: 0.5rem;
552
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
553
+ border-radius: var(--border-radius);
554
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
555
+ transform: translateY(calc(-1 * var(--spacing, 10px)));
556
+ width: clamp(200px, 50vw, 800px);
557
+ padding: calc(1rem + 2vw);
558
+ color: hsl(220, 100%, 50%);
559
+ }
560
+ .dynamic-grid {
561
+ display: grid;
562
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
563
+ gap: clamp(1rem, 5vw, 3rem);
564
+ grid-auto-rows: minmax(200px, auto);
565
+ }
566
+ ```
567
+
568
+ For responsive styles, you can use standard Tailwind responsive utilities within your classes:
569
+
570
+ ```javascript
571
+ const styles = twsx({
572
+ ".responsive-box": "w-full md:w-1/2 lg:w-1/3 p-4 bg-blue-500",
573
+ });
574
+ ```
575
+
576
+ 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.
577
+
578
+ ### Inject Option (Browser Only)
579
+
580
+ 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.
581
+
582
+ You can control this behavior with the `inject` option:
583
+
584
+ ```js
585
+ // Auto-inject (default)
586
+ twsx({ ... }) // CSS is injected automatically
587
+
588
+ // Disable auto-inject
589
+ twsx({ ... }, { inject: false }) // CSS is NOT injected, just returned as string
590
+ ```
591
+
592
+ - **inject: true** (default): CSS is injected into the page (browser only).
593
+ - **inject: false**: CSS is only returned as a string, not injected. Useful for SSR, testing, or custom handling.
594
+
595
+ > Note: This option only affects browser usage. In Node.js or SSR, no injection occurs.
596
+
597
+ ## Performance Monitoring & Debugging (v2.7.0+)
598
+
599
+ 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.
600
+
601
+ ### Performance Utils
602
+
603
+ ```javascript
604
+ import { performanceUtils } from "tailwind-to-style";
605
+
606
+ // Enable performance logging (logs operations > 5ms as warnings)
607
+ performanceUtils.enablePerformanceLogging(true);
608
+
609
+ // Get cache and injection statistics
610
+ const stats = performanceUtils.getStats();
611
+ console.log(stats);
612
+ // Output:
613
+ // {
614
+ // cacheStats: {
615
+ // cssResolution: 45,
616
+ // configOptions: 2,
617
+ // parseSelector: 23,
618
+ // encodeBracket: 12,
619
+ // decodeBracket: 8
620
+ // },
621
+ // injectionStats: {
622
+ // uniqueStylesheets: 15
623
+ // }
624
+ // }
625
+
626
+ // Clear all caches (useful for memory management)
627
+ performanceUtils.clearCaches();
628
+ ```
629
+
630
+ ### Performance Metrics
631
+
632
+ The library automatically tracks performance for key operations:
633
+
634
+ - **tws:total** - Total execution time for `tws()`
635
+ - **tws:parse** - Time spent parsing classes
636
+ - **tws:process** - Time spent processing classes
637
+ - **twsx:total** - Total execution time for `twsx()`
638
+ - **twsx:flatten** - Time spent flattening objects
639
+ - **twsx:generate** - Time spent generating CSS
640
+ - **css:inject** - Time spent injecting CSS to DOM
641
+
642
+ ### Debounced Functions
643
+
644
+ For high-frequency usage, use the debounced versions:
645
+
646
+ ```javascript
647
+ import { debouncedTws, debouncedTwsx } from "tailwind-to-style";
648
+
649
+ // Debounced versions (50ms for tws, 100ms for twsx)
650
+ const styles = debouncedTws("bg-red-500 p-4");
651
+ const complexStyles = debouncedTwsx({ ".card": "bg-white p-6" });
652
+ ```
653
+
654
+ ### Example: Performance Monitoring
655
+
656
+ ```javascript
657
+ import { tws, twsx, performanceUtils } from "tailwind-to-style";
658
+
659
+ // Enable monitoring
660
+ performanceUtils.enablePerformanceLogging(true);
661
+
662
+ // Your code that uses tws/twsx
663
+ const styles = tws("bg-gradient-to-r from-purple-400 to-pink-500 p-8");
664
+ const complexStyles = twsx({
665
+ ".hero": [
666
+ "bg-gradient-to-br from-indigo-900 to-purple-900 min-h-screen",
667
+ {
668
+ h1: "text-6xl font-bold text-white md:text-4xl",
669
+ "@css": {
670
+ transition: "font-size 0.3s ease-in-out",
671
+ },
672
+ },
673
+ ],
674
+ });
675
+
676
+ // Check performance stats
677
+ console.log(performanceUtils.getStats());
678
+ ```
679
+
680
+ This will automatically log warnings for operations taking longer than 5ms and provide insights into cache usage and performance bottlenecks.
681
+
682
+ # Build-Time Plugins: Vite & Webpack
683
+
684
+ ### Automated Modular CSS Generation
685
+
686
+ 1. Create JS files with `twsx.` prefix in your project (e.g., `twsx.card.js`, `twsx.button.js`) anywhere in your `src/` folder.
687
+ 2. Use the Vite/Webpack plugin from the `plugins/` folder to automatically generate CSS on every build/rebuild.
688
+ 3. Each JS file will generate its own CSS file in the specified output directory (default: `src/styles/`).
689
+ 4. Import the generated CSS files directly in your components or bundle them as needed.
690
+
691
+ #### Vite Plugin Usage Example
692
+
693
+ Add the plugin to your `vite.config.js`:
694
+ ```js
695
+ import twsxPlugin from 'tailwind-to-style/plugins/vite-twsx';
696
+
697
+ export default {
698
+ plugins: [
699
+ twsxPlugin({
700
+ inputDir: 'src',
701
+ outputDir: 'src/styles',
702
+ preserveStructure: false // Set to true to generate CSS next to JS files
703
+ })
704
+ ]
705
+ };
706
+ ```
707
+
708
+ **Configuration Options:**
709
+ - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
710
+ - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
711
+ - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
712
+
713
+ **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
714
+ **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
715
+
716
+ Import in your components:
717
+ ```js
718
+ // Default mode
719
+ import './styles/twsx.card.css';
720
+ import './styles/twsx.button.css';
721
+
722
+ // Preserve structure mode
723
+ import './twsx.card.css'; // If in same directory
724
+ ```
725
+
726
+ #### Webpack Plugin Usage Example
727
+
728
+ Add the plugin to your `webpack.config.js`:
729
+ ```js
730
+ import TwsxPlugin from 'tailwind-to-style/plugins/webpack-twsx';
731
+
732
+ module.exports = {
733
+ plugins: [
734
+ new TwsxPlugin({
735
+ inputDir: 'src',
736
+ outputDir: 'src/styles',
737
+ preserveStructure: false // Set to true to generate CSS next to JS files
738
+ })
739
+ ]
740
+ };
741
+ ```
742
+
743
+ **Configuration Options:**
744
+ - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
745
+ - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
746
+ - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
747
+
748
+ **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
749
+ **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
750
+
751
+ Import in your components:
752
+ ```js
753
+ // Default mode
754
+ import './styles/twsx.card.css';
755
+ import './styles/twsx.button.css';
756
+
757
+ // Preserve structure mode
758
+ import './twsx.card.css'; // If in same directory
759
+ ```
760
+
761
+ ## Build-Time CSS Generation via Script
762
+
763
+ 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.
764
+
765
+ ### Script: tailwind-to-style/lib/twsx-cli.js (Legacy)
766
+
767
+ > **💡 Recommended:** Use `npx twsx-cli` instead of calling the script directly.
768
+
769
+ 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.
770
+
771
+ #### How to Use
772
+
773
+ 1. Create JS files with `twsx.` prefix containing style objects anywhere in your `src/` folder (e.g., `src/components/twsx.card.js`).
774
+
775
+ 2. **One-time Build:**
776
+ ```bash
777
+ node tailwind-to-style/lib/twsx-cli.js
778
+ ```
779
+
780
+ 3. **Watch Mode (Auto-rebuild on file changes):**
781
+ ```bash
782
+ node tailwind-to-style/lib/twsx-cli.js --watch
783
+ ```
784
+
785
+ 4. **Preserve Structure Mode (Generate CSS next to JS files):**
786
+ ```bash
787
+ # One-time build with preserve structure
788
+ node tailwind-to-style/lib/twsx-cli.js --preserve-structure
789
+
790
+ # Watch mode with preserve structure
791
+ node tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure
792
+ ```
793
+
794
+ You can configure input and output directories using environment variables:
795
+ ```bash
796
+ TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/twsx-cli.js --watch
797
+ ```
798
+
799
+ Or use environment variables for preserve structure:
800
+ ```bash
801
+ TWSX_PRESERVE_STRUCTURE=true node tailwind-to-style/lib/twsx-cli.js --watch
802
+ ```
803
+
804
+ 5. **Output locations:**
805
+
806
+ **Default mode:** CSS files will be in the output directory (default: `src/styles/`):
807
+ ```
808
+ src/styles/twsx.card.css
809
+ src/styles/twsx.button.css
810
+ ```
811
+
812
+ **Preserve structure mode:** CSS files will be generated next to their JS counterparts:
813
+ ```
814
+ src/components/Button/twsx.button.js → src/components/Button/twsx.button.css
815
+ src/components/Card/twsx.card.js → src/components/Card/twsx.card.css
816
+ ```
817
+
818
+ 5. Import the generated CSS files in your components:
819
+
820
+ **Default mode:**
821
+ ```js
822
+ import './styles/twsx.card.css';
823
+ import './styles/twsx.button.css';
824
+ ```
825
+
826
+ **Preserve structure mode:**
827
+ ```js
828
+ // In src/components/Button/Button.jsx
829
+ import './twsx.button.css';
830
+
831
+ // In src/components/Card/Card.jsx
832
+ import './twsx.card.css';
833
+ ```
834
+
835
+ #### Usage in Different Projects
836
+
837
+ **React/Next.js/Vue/Any Project:**
838
+
839
+ 1. Install the package:
840
+ ```bash
841
+ npm install tailwind-to-style
842
+ ```
843
+
844
+ 2. Add to your `package.json`:
845
+ ```json
846
+ {
847
+ "scripts": {
848
+ "twsx:build": "node node_modules/tailwind-to-style/lib/twsx-cli.js",
849
+ "twsx:watch": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch",
850
+ "twsx:preserve": "node node_modules/tailwind-to-style/lib/twsx-cli.js --preserve-structure",
851
+ "twsx:dev": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure",
852
+ "dev": "npm run twsx:watch & next dev"
853
+ }
854
+ }
855
+ ```
856
+
857
+ 3. For development with auto-rebuild:
858
+ ```bash
859
+ npm run twsx:watch
860
+ ```
861
+
862
+ 4. For production build:
863
+ ```bash
864
+ npm run twsx:build
865
+ ```
866
+
867
+ **VS Code Integration:**
868
+ Add to your workspace settings (`.vscode/settings.json`):
869
+ ```json
870
+ {
871
+ "emeraldwalk.runonsave": {
872
+ "commands": [
873
+ {
874
+ "match": "twsx\\..*\\.js$",
875
+ "cmd": "npm run twsx:build"
876
+ }
877
+ ]
878
+ }
879
+ }
880
+ ```
881
+
882
+ #### Automatic Integration
883
+
884
+ You can add this script to the build section in your `package.json`:
885
+
886
+ ```json
887
+ {
888
+ "scripts": {
889
+ "build-css": "node tailwind-to-style/lib/twsx-cli.js"
890
+ }
891
+ }
892
+ ```
893
+
894
+ Then run:
895
+
896
+ ```bash
897
+ npm run build-css
898
+ ```
899
+
900
+ This script is suitable for CI/CD workflows, pre-build steps, or manually generating CSS without a bundler plugin.
901
+
902
+ ## License
903
+
904
+ ## Support
905
+
906
+ If you find this library helpful and want to support its development, consider buying me a coffee:
907
+
908
+ [![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)
909
+
910
+ Your support helps maintain and improve this library! ❤️
911
+
912
+ ### Why Support?
913
+
914
+ - 🔧 **Active Maintenance**: Regular updates and bug fixes
915
+ - ⚡ **New Features**: Continuous improvement based on community feedback
916
+ - 📚 **Documentation**: Better examples and tutorials
917
+ - 🚀 **Performance**: Optimization and new capabilities
918
+ - 💬 **Support**: Responsive community support
919
+
920
+ Every contribution, no matter how small, is greatly appreciated and helps keep this project alive and growing!
921
+
922
+ ## Contributing
923
+
924
+ Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
925
+
926
+ ## License
927
+
928
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
929
+
930
+ ---
931
+
932
+ Feel free to contribute or raise issues on the [GitHub repository](https://github.com/Bigetion/tailwind-to-style).