tailwind-to-style 2.8.6 → 2.8.9
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 +722 -722
- package/dist/index.browser.js +6 -4
- package/dist/index.cjs +6 -4
- package/dist/index.esm.js +6 -4
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/lib/twsx-cli.js +52 -19
- package/package.json +70 -70
- package/plugins/vite-twsx.js +56 -13
- package/plugins/webpack-twsx.js +20 -5
package/README.md
CHANGED
|
@@ -1,722 +1,722 @@
|
|
|
1
|
-
# tailwind-to-style
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/tailwind-to-style)
|
|
4
|
-
[](https://github.com/Bigetion/tailwind-to-style/actions)
|
|
5
|
-
[](https://www.npmjs.com/package/tailwind-to-style)
|
|
6
|
-
[](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, state variants, and grouping.
|
|
14
|
-
3. **`twsx-cli`**: A command-line tool for generating CSS files from `twsx.*.js` files with watch mode support.
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
To use `tailwind-to-style`, install the library using either npm or yarn:
|
|
19
|
-
|
|
20
|
-
### Using npm
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm install tailwind-to-style
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Using yarn
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
yarn add tailwind-to-style
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Core Functions
|
|
33
|
-
|
|
34
|
-
### 1. `tws`
|
|
35
|
-
|
|
36
|
-
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.
|
|
37
|
-
|
|
38
|
-
#### Features of `tws`:
|
|
39
|
-
|
|
40
|
-
- Converts Tailwind utility classes into **inline CSS** or **JSON style objects**.
|
|
41
|
-
|
|
42
|
-
#### Usage
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
import { tws } from "tailwind-to-style";
|
|
46
|
-
|
|
47
|
-
// Convert Tailwind classes to inline CSS
|
|
48
|
-
const styleInline = tws("bg-white mx-auto");
|
|
49
|
-
// Output: background-color:rgba(255, 255, 255, 1); margin-left:auto; margin-right:auto;
|
|
50
|
-
|
|
51
|
-
// Convert Tailwind classes to JSON style object
|
|
52
|
-
const styleJSON = tws("bg-white mx-auto", 1);
|
|
53
|
-
// Output: { backgroundColor: 'rgba(255, 255, 255, 1)', marginLeft: 'auto', marginRight: 'auto' }
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
- **First argument**: The string of Tailwind classes to convert.
|
|
57
|
-
- **Second argument (optional)**: Pass `1` to get the result as a JSON object (default is inline CSS when omitted).
|
|
58
|
-
|
|
59
|
-
#### Example in React:
|
|
60
|
-
|
|
61
|
-
```javascript
|
|
62
|
-
import React from "react";
|
|
63
|
-
import { tws } from "tailwind-to-style";
|
|
64
|
-
|
|
65
|
-
const App = () => {
|
|
66
|
-
return (
|
|
67
|
-
<div style={tws("text-red-500 bg-blue-200 p-4", 1)}>
|
|
68
|
-
Hello, this is styled using tailwind-to-style
|
|
69
|
-
</div>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export default App;
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
This will apply the Tailwind classes directly as inline styles in the React component.
|
|
77
|
-
|
|
78
|
-
### 2. `twsx`
|
|
79
|
-
|
|
80
|
-
`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.
|
|
81
|
-
|
|
82
|
-
#### Features of `twsx`:
|
|
83
|
-
|
|
84
|
-
- ✅ **Nested styles** similar to SCSS, enabling more complex CSS structures
|
|
85
|
-
- ✅ **Grouping**: Supports grouping utilities inside parentheses `hover:(bg-blue-600 scale-105)`
|
|
86
|
-
- ✅ **Responsive variants** (`sm`, `md`, `lg`, `xl`, `2xl`) in standard and grouping syntax
|
|
87
|
-
- ✅ **State variants** like `hover`, `focus`, `active`, `disabled`, etc.
|
|
88
|
-
- ✅ **Dynamic utilities** such as `w-[300px]`, `bg-[rgba(0,0,0,0.5)]`, `text-[14px]`
|
|
89
|
-
- ✅ **!important support** with `!text-red-500`, `!bg-blue-500`
|
|
90
|
-
- ✅ **@css directive**: Apply custom CSS properties for animations, transitions, and modern effects
|
|
91
|
-
|
|
92
|
-
#### Basic Usage
|
|
93
|
-
|
|
94
|
-
```javascript
|
|
95
|
-
import { twsx } from "tailwind-to-style";
|
|
96
|
-
|
|
97
|
-
const styles = twsx({
|
|
98
|
-
".card": [
|
|
99
|
-
"bg-white p-4 rounded-lg shadow-md",
|
|
100
|
-
{
|
|
101
|
-
"&:hover": "shadow-xl scale-105",
|
|
102
|
-
".title": "text-lg font-bold text-gray-900",
|
|
103
|
-
".desc": "text-sm text-gray-600 mt-2",
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
console.log(styles);
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Output**:
|
|
112
|
-
|
|
113
|
-
```css
|
|
114
|
-
.card {
|
|
115
|
-
background-color: rgba(255, 255, 255, var(--bg-opacity));
|
|
116
|
-
padding: 1rem;
|
|
117
|
-
border-radius: 0.5rem;
|
|
118
|
-
box-shadow:
|
|
119
|
-
0 4px 6px -1px rgb(0 0 0 / 0.1),
|
|
120
|
-
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
121
|
-
}
|
|
122
|
-
.card:hover {
|
|
123
|
-
box-shadow:
|
|
124
|
-
0 20px 25px -5px rgb(0 0 0 / 0.1),
|
|
125
|
-
0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
126
|
-
transform: scale(1.05);
|
|
127
|
-
}
|
|
128
|
-
.card .title {
|
|
129
|
-
font-size: 1.125rem;
|
|
130
|
-
font-weight: 700;
|
|
131
|
-
color: rgba(17, 24, 39, var(--text-opacity));
|
|
132
|
-
}
|
|
133
|
-
.card .desc {
|
|
134
|
-
font-size: 0.875rem;
|
|
135
|
-
color: rgba(75, 85, 99, var(--text-opacity));
|
|
136
|
-
margin-top: 0.5rem;
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
#### Grouping Support
|
|
141
|
-
|
|
142
|
-
Group related utilities together inside parentheses for better readability and organization:
|
|
143
|
-
|
|
144
|
-
```javascript
|
|
145
|
-
const styles = twsx({
|
|
146
|
-
".button": [
|
|
147
|
-
"bg-blue-500 text-white px-6 py-3 rounded-lg",
|
|
148
|
-
"hover:(bg-blue-600 scale-105 shadow-lg)",
|
|
149
|
-
"focus:(ring-2 ring-blue-300 outline-none)",
|
|
150
|
-
"active:(bg-blue-700 scale-95)",
|
|
151
|
-
],
|
|
152
|
-
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
**Output**:
|
|
156
|
-
|
|
157
|
-
```css
|
|
158
|
-
.button {
|
|
159
|
-
background-color: rgba(59, 130, 246, var(--bg-opacity));
|
|
160
|
-
color: rgba(255, 255, 255, var(--text-opacity));
|
|
161
|
-
padding: 0.75rem 1.5rem;
|
|
162
|
-
border-radius: 0.5rem;
|
|
163
|
-
}
|
|
164
|
-
.button:hover {
|
|
165
|
-
background-color: rgba(37, 99, 235, var(--bg-opacity));
|
|
166
|
-
transform: scale(1.05);
|
|
167
|
-
box-shadow:
|
|
168
|
-
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
169
|
-
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
170
|
-
}
|
|
171
|
-
.button:focus {
|
|
172
|
-
box-shadow: var(--ring-offset-shadow), var(--ring-shadow);
|
|
173
|
-
outline: none;
|
|
174
|
-
}
|
|
175
|
-
.button:active {
|
|
176
|
-
background-color: rgba(29, 78, 216, var(--bg-opacity));
|
|
177
|
-
transform: scale(0.95);
|
|
178
|
-
}
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
#### Responsive Variants
|
|
182
|
-
|
|
183
|
-
Responsive variants work seamlessly with both standard syntax and grouping syntax:
|
|
184
|
-
|
|
185
|
-
```javascript
|
|
186
|
-
const styles = twsx({
|
|
187
|
-
".hero": [
|
|
188
|
-
// Standard responsive syntax
|
|
189
|
-
"text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl",
|
|
190
|
-
"w-full md:w-1/2 lg:w-1/3 p-4",
|
|
191
|
-
// Grouped responsive syntax
|
|
192
|
-
"sm:(py-16 px-4)",
|
|
193
|
-
"md:(py-20 px-6)",
|
|
194
|
-
"lg:(py-24 px-8)",
|
|
195
|
-
{
|
|
196
|
-
h1: "font-bold text-gray-900",
|
|
197
|
-
p: "text-gray-600 mt-4",
|
|
198
|
-
},
|
|
199
|
-
],
|
|
200
|
-
});
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
**Output**:
|
|
204
|
-
|
|
205
|
-
```css
|
|
206
|
-
.hero {
|
|
207
|
-
font-size: 1.5rem;
|
|
208
|
-
width: 100%;
|
|
209
|
-
padding: 1rem;
|
|
210
|
-
}
|
|
211
|
-
@media (min-width: 640px) {
|
|
212
|
-
.hero {
|
|
213
|
-
font-size: 1.875rem;
|
|
214
|
-
padding: 4rem 1rem;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
@media (min-width: 768px) {
|
|
218
|
-
.hero {
|
|
219
|
-
font-size: 2.25rem;
|
|
220
|
-
width: 50%;
|
|
221
|
-
padding: 5rem 1.5rem;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
@media (min-width: 1024px) {
|
|
225
|
-
.hero {
|
|
226
|
-
font-size: 3rem;
|
|
227
|
-
width: 33.333333%;
|
|
228
|
-
padding: 6rem 2rem;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
@media (min-width: 1280px) {
|
|
232
|
-
.hero {
|
|
233
|
-
font-size: 3.75rem;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
.hero h1 {
|
|
237
|
-
font-weight: 700;
|
|
238
|
-
color: rgba(17, 24, 39, var(--text-opacity));
|
|
239
|
-
}
|
|
240
|
-
.hero p {
|
|
241
|
-
color: rgba(75, 85, 99, var(--text-opacity));
|
|
242
|
-
margin-top: 1rem;
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Performance Utilities
|
|
247
|
-
|
|
248
|
-
The library includes performance optimization features:
|
|
249
|
-
|
|
250
|
-
#### Inject Option
|
|
251
|
-
|
|
252
|
-
Control CSS output location with the `inject` option:
|
|
253
|
-
|
|
254
|
-
```javascript
|
|
255
|
-
import { tws, twsx } from "tailwind-to-style";
|
|
256
|
-
|
|
257
|
-
// Auto-inject into document head (default)
|
|
258
|
-
const styles1 = tws("bg-blue-500 text-white p-4");
|
|
259
|
-
|
|
260
|
-
// Skip injection - returns CSS only
|
|
261
|
-
const styles2 = tws("bg-red-500 text-black p-2", { inject: false });
|
|
262
|
-
|
|
263
|
-
// Custom injection target
|
|
264
|
-
const targetElement = document.getElementById("custom-styles");
|
|
265
|
-
const styles3 = tws("bg-green-500 text-yellow p-3", { inject: targetElement });
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
#### Performance Monitoring
|
|
269
|
-
|
|
270
|
-
```javascript
|
|
271
|
-
import { tws } from "tailwind-to-style";
|
|
272
|
-
|
|
273
|
-
// Enable performance logging
|
|
274
|
-
const start = performance.now();
|
|
275
|
-
const styles = tws("complex-classes here...");
|
|
276
|
-
const end = performance.now();
|
|
277
|
-
console.log(`Generation time: ${end - start}ms`);
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
## Advanced `@css` Directive
|
|
281
|
-
|
|
282
|
-
There are several ways to use the `@css` feature:
|
|
283
|
-
|
|
284
|
-
1. **As a nested object inside selectors**:
|
|
285
|
-
|
|
286
|
-
```javascript
|
|
287
|
-
const styles = twsx({
|
|
288
|
-
".button": [
|
|
289
|
-
"bg-blue-500 text-white rounded-md",
|
|
290
|
-
{
|
|
291
|
-
"@css": {
|
|
292
|
-
transition: "all 0.3s ease-in-out",
|
|
293
|
-
"will-change": "transform, opacity",
|
|
294
|
-
},
|
|
295
|
-
"&:hover": "bg-blue-600",
|
|
296
|
-
},
|
|
297
|
-
],
|
|
298
|
-
});
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
**Output**:
|
|
302
|
-
|
|
303
|
-
```css
|
|
304
|
-
.button {
|
|
305
|
-
background-color: #3b82f6;
|
|
306
|
-
color: white;
|
|
307
|
-
border-radius: 0.375rem;
|
|
308
|
-
transition: all 0.3s ease-in-out;
|
|
309
|
-
will-change: transform, opacity;
|
|
310
|
-
}
|
|
311
|
-
.button:hover {
|
|
312
|
-
background-color: #2563eb;
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
2. **As a direct property in the selector**:
|
|
317
|
-
|
|
318
|
-
```javascript
|
|
319
|
-
const styles = twsx({
|
|
320
|
-
".button @css transition": "all 0.3s ease-in-out",
|
|
321
|
-
".button": "bg-blue-500 text-white rounded-md",
|
|
322
|
-
".button:hover": "bg-blue-600",
|
|
323
|
-
});
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
This syntax is especially useful when you need to add just a single CSS property that isn't available in Tailwind.
|
|
327
|
-
|
|
328
|
-
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.
|
|
329
|
-
|
|
330
|
-
#### Advanced `@css` Examples:
|
|
331
|
-
|
|
332
|
-
You can combine `@css` with state variants:
|
|
333
|
-
|
|
334
|
-
```javascript
|
|
335
|
-
const styles = twsx({
|
|
336
|
-
".modal": [
|
|
337
|
-
"bg-white rounded-lg shadow-xl",
|
|
338
|
-
{
|
|
339
|
-
"@css": {
|
|
340
|
-
transform: "translateX(0px)",
|
|
341
|
-
transition: "all 0.3s ease-out",
|
|
342
|
-
"will-change": "transform, opacity",
|
|
343
|
-
},
|
|
344
|
-
"&.hidden": [
|
|
345
|
-
"opacity-0",
|
|
346
|
-
{
|
|
347
|
-
"@css": {
|
|
348
|
-
transform: "translateX(-100px)",
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
],
|
|
352
|
-
},
|
|
353
|
-
],
|
|
354
|
-
});
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**Output**:
|
|
358
|
-
|
|
359
|
-
```css
|
|
360
|
-
.modal {
|
|
361
|
-
background-color: white;
|
|
362
|
-
border-radius: 0.5rem;
|
|
363
|
-
box-shadow:
|
|
364
|
-
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
|
365
|
-
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
366
|
-
transform: translateX(0px);
|
|
367
|
-
transition: all 0.3s ease-out;
|
|
368
|
-
will-change: transform, opacity;
|
|
369
|
-
}
|
|
370
|
-
.modal.hidden {
|
|
371
|
-
opacity: 0;
|
|
372
|
-
transform: translateX(-100px);
|
|
373
|
-
}
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
For responsive styles, you can use standard Tailwind responsive utilities within your classes:
|
|
377
|
-
|
|
378
|
-
```javascript
|
|
379
|
-
const styles = twsx({
|
|
380
|
-
".responsive-box": "w-full md:w-1/2 lg:w-1/3 p-4 bg-blue-500",
|
|
381
|
-
});
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
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.
|
|
385
|
-
|
|
386
|
-
### Inject Option (Browser Only)
|
|
387
|
-
|
|
388
|
-
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.
|
|
389
|
-
|
|
390
|
-
You can control this behavior with the `inject` option:
|
|
391
|
-
|
|
392
|
-
```js
|
|
393
|
-
// Auto-inject (default)
|
|
394
|
-
twsx({ ... }) // CSS is injected automatically
|
|
395
|
-
|
|
396
|
-
// Disable auto-inject
|
|
397
|
-
twsx({ ... }, { inject: false }) // CSS is NOT injected, just returned as string
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
- **inject: true** (default): CSS is injected into the page (browser only).
|
|
401
|
-
- **inject: false**: CSS is only returned as a string, not injected. Useful for SSR, testing, or custom handling.
|
|
402
|
-
|
|
403
|
-
> Note: This option only affects browser usage. In Node.js or SSR, no injection occurs.
|
|
404
|
-
|
|
405
|
-
## Performance Monitoring & Debugging (v2.7.0+)
|
|
406
|
-
|
|
407
|
-
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.
|
|
408
|
-
|
|
409
|
-
### Performance Utils
|
|
410
|
-
|
|
411
|
-
```javascript
|
|
412
|
-
import { performanceUtils } from "tailwind-to-style";
|
|
413
|
-
|
|
414
|
-
// Enable performance logging (logs operations > 5ms as warnings)
|
|
415
|
-
performanceUtils.enablePerformanceLogging(true);
|
|
416
|
-
|
|
417
|
-
// Get cache and injection statistics
|
|
418
|
-
const stats = performanceUtils.getStats();
|
|
419
|
-
console.log(stats);
|
|
420
|
-
// Output:
|
|
421
|
-
// {
|
|
422
|
-
// cacheStats: {
|
|
423
|
-
// cssResolution: 45,
|
|
424
|
-
// configOptions: 2,
|
|
425
|
-
// parseSelector: 23,
|
|
426
|
-
// encodeBracket: 12,
|
|
427
|
-
// decodeBracket: 8
|
|
428
|
-
// },
|
|
429
|
-
// injectionStats: {
|
|
430
|
-
// uniqueStylesheets: 15
|
|
431
|
-
// }
|
|
432
|
-
// }
|
|
433
|
-
|
|
434
|
-
// Clear all caches (useful for memory management)
|
|
435
|
-
performanceUtils.clearCaches();
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### Performance Metrics
|
|
439
|
-
|
|
440
|
-
The library automatically tracks performance for key operations:
|
|
441
|
-
|
|
442
|
-
- **tws:total** - Total execution time for `tws()`
|
|
443
|
-
- **tws:parse** - Time spent parsing classes
|
|
444
|
-
- **tws:process** - Time spent processing classes
|
|
445
|
-
- **twsx:total** - Total execution time for `twsx()`
|
|
446
|
-
- **twsx:flatten** - Time spent flattening objects
|
|
447
|
-
- **twsx:generate** - Time spent generating CSS
|
|
448
|
-
- **css:inject** - Time spent injecting CSS to DOM
|
|
449
|
-
|
|
450
|
-
### Debounced Functions
|
|
451
|
-
|
|
452
|
-
For high-frequency usage, use the debounced versions:
|
|
453
|
-
|
|
454
|
-
```javascript
|
|
455
|
-
import { debouncedTws, debouncedTwsx } from "tailwind-to-style";
|
|
456
|
-
|
|
457
|
-
// Debounced versions (50ms for tws, 100ms for twsx)
|
|
458
|
-
const styles = debouncedTws("bg-red-500 p-4");
|
|
459
|
-
const complexStyles = debouncedTwsx({ ".card": "bg-white p-6" });
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Example: Performance Monitoring
|
|
463
|
-
|
|
464
|
-
```javascript
|
|
465
|
-
import { tws, twsx, performanceUtils } from "tailwind-to-style";
|
|
466
|
-
|
|
467
|
-
// Enable monitoring
|
|
468
|
-
performanceUtils.enablePerformanceLogging(true);
|
|
469
|
-
|
|
470
|
-
// Your code that uses tws/twsx
|
|
471
|
-
const styles = tws("bg-gradient-to-r from-purple-400 to-pink-500 p-8");
|
|
472
|
-
const complexStyles = twsx({
|
|
473
|
-
".hero": [
|
|
474
|
-
"bg-gradient-to-br from-indigo-900 to-purple-900 min-h-screen",
|
|
475
|
-
{
|
|
476
|
-
h1: "text-6xl font-bold text-white md:text-4xl",
|
|
477
|
-
"@css": {
|
|
478
|
-
transition: "font-size 0.3s ease-in-out",
|
|
479
|
-
},
|
|
480
|
-
},
|
|
481
|
-
],
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
// Check performance stats
|
|
485
|
-
console.log(performanceUtils.getStats());
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
This will automatically log warnings for operations taking longer than 5ms and provide insights into cache usage and performance bottlenecks.
|
|
489
|
-
|
|
490
|
-
# Build-Time Plugins: Vite & Webpack
|
|
491
|
-
|
|
492
|
-
### Automated Modular CSS Generation
|
|
493
|
-
|
|
494
|
-
1. Create JS files with `twsx.` prefix in your project (e.g., `twsx.card.js`, `twsx.button.js`) anywhere in your `src/` folder.
|
|
495
|
-
2. Use the Vite/Webpack plugin from the `plugins/` folder to automatically generate CSS on every build/rebuild.
|
|
496
|
-
3. Each JS file will generate its own CSS file in the specified output directory (default: `src/styles/`).
|
|
497
|
-
4. Import the generated CSS files directly in your components or bundle them as needed.
|
|
498
|
-
|
|
499
|
-
#### Vite Plugin Usage Example
|
|
500
|
-
|
|
501
|
-
Add the plugin to your `vite.config.js`:
|
|
502
|
-
```js
|
|
503
|
-
import twsxPlugin from 'tailwind-to-style/plugins/vite-twsx';
|
|
504
|
-
|
|
505
|
-
export default {
|
|
506
|
-
plugins: [
|
|
507
|
-
twsxPlugin({
|
|
508
|
-
inputDir: 'src',
|
|
509
|
-
outputDir: 'src/styles',
|
|
510
|
-
preserveStructure: false // Set to true to generate CSS next to JS files
|
|
511
|
-
})
|
|
512
|
-
]
|
|
513
|
-
};
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
**Configuration Options:**
|
|
517
|
-
- `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
|
|
518
|
-
- `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
|
|
519
|
-
- `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
|
|
520
|
-
|
|
521
|
-
**Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
|
|
522
|
-
**Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
|
|
523
|
-
|
|
524
|
-
Import in your components:
|
|
525
|
-
```js
|
|
526
|
-
// Default mode
|
|
527
|
-
import './styles/twsx.card.css';
|
|
528
|
-
import './styles/twsx.button.css';
|
|
529
|
-
|
|
530
|
-
// Preserve structure mode
|
|
531
|
-
import './twsx.card.css'; // If in same directory
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
#### Webpack Plugin Usage Example
|
|
535
|
-
|
|
536
|
-
Add the plugin to your `webpack.config.js`:
|
|
537
|
-
```js
|
|
538
|
-
import TwsxPlugin from 'tailwind-to-style/plugins/webpack-twsx';
|
|
539
|
-
|
|
540
|
-
module.exports = {
|
|
541
|
-
plugins: [
|
|
542
|
-
new TwsxPlugin({
|
|
543
|
-
inputDir: 'src',
|
|
544
|
-
outputDir: 'src/styles',
|
|
545
|
-
preserveStructure: false // Set to true to generate CSS next to JS files
|
|
546
|
-
})
|
|
547
|
-
]
|
|
548
|
-
};
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
**Configuration Options:**
|
|
552
|
-
- `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
|
|
553
|
-
- `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
|
|
554
|
-
- `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
|
|
555
|
-
|
|
556
|
-
**Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
|
|
557
|
-
**Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
|
|
558
|
-
|
|
559
|
-
Import in your components:
|
|
560
|
-
```js
|
|
561
|
-
// Default mode
|
|
562
|
-
import './styles/twsx.card.css';
|
|
563
|
-
import './styles/twsx.button.css';
|
|
564
|
-
|
|
565
|
-
// Preserve structure mode
|
|
566
|
-
import './twsx.card.css'; // If in same directory
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
## Build-Time CSS Generation via Script
|
|
570
|
-
|
|
571
|
-
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.
|
|
572
|
-
|
|
573
|
-
### Script: tailwind-to-style/lib/twsx-cli.js (Legacy)
|
|
574
|
-
|
|
575
|
-
> **💡 Recommended:** Use `npx twsx-cli` instead of calling the script directly.
|
|
576
|
-
|
|
577
|
-
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.
|
|
578
|
-
|
|
579
|
-
#### How to Use
|
|
580
|
-
|
|
581
|
-
1. Create JS files with `twsx.` prefix containing style objects anywhere in your `src/` folder (e.g., `src/components/twsx.card.js`).
|
|
582
|
-
|
|
583
|
-
2. **One-time Build:**
|
|
584
|
-
```bash
|
|
585
|
-
node tailwind-to-style/lib/twsx-cli.js
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
3. **Watch Mode (Auto-rebuild on file changes):**
|
|
589
|
-
```bash
|
|
590
|
-
node tailwind-to-style/lib/twsx-cli.js --watch
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
4. **Preserve Structure Mode (Generate CSS next to JS files):**
|
|
594
|
-
```bash
|
|
595
|
-
# One-time build with preserve structure
|
|
596
|
-
node tailwind-to-style/lib/twsx-cli.js --preserve-structure
|
|
597
|
-
|
|
598
|
-
# Watch mode with preserve structure
|
|
599
|
-
node tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
You can configure input and output directories using environment variables:
|
|
603
|
-
```bash
|
|
604
|
-
TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/twsx-cli.js --watch
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
Or use environment variables for preserve structure:
|
|
608
|
-
```bash
|
|
609
|
-
TWSX_PRESERVE_STRUCTURE=true node tailwind-to-style/lib/twsx-cli.js --watch
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
5. **Output locations:**
|
|
613
|
-
|
|
614
|
-
**Default mode:** CSS files will be in the output directory (default: `src/styles/`):
|
|
615
|
-
```
|
|
616
|
-
src/styles/twsx.card.css
|
|
617
|
-
src/styles/twsx.button.css
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
**Preserve structure mode:** CSS files will be generated next to their JS counterparts:
|
|
621
|
-
```
|
|
622
|
-
src/components/Button/twsx.button.js → src/components/Button/twsx.button.css
|
|
623
|
-
src/components/Card/twsx.card.js → src/components/Card/twsx.card.css
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
5. Import the generated CSS files in your components:
|
|
627
|
-
|
|
628
|
-
**Default mode:**
|
|
629
|
-
```js
|
|
630
|
-
import './styles/twsx.card.css';
|
|
631
|
-
import './styles/twsx.button.css';
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
**Preserve structure mode:**
|
|
635
|
-
```js
|
|
636
|
-
// In src/components/Button/Button.jsx
|
|
637
|
-
import './twsx.button.css';
|
|
638
|
-
|
|
639
|
-
// In src/components/Card/Card.jsx
|
|
640
|
-
import './twsx.card.css';
|
|
641
|
-
```
|
|
642
|
-
|
|
643
|
-
#### Usage in Different Projects
|
|
644
|
-
|
|
645
|
-
**React/Next.js/Vue/Any Project:**
|
|
646
|
-
|
|
647
|
-
1. Install the package:
|
|
648
|
-
```bash
|
|
649
|
-
npm install tailwind-to-style
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
2. Add to your `package.json`:
|
|
653
|
-
```json
|
|
654
|
-
{
|
|
655
|
-
"scripts": {
|
|
656
|
-
"twsx:build": "node node_modules/tailwind-to-style/lib/twsx-cli.js",
|
|
657
|
-
"twsx:watch": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch",
|
|
658
|
-
"twsx:preserve": "node node_modules/tailwind-to-style/lib/twsx-cli.js --preserve-structure",
|
|
659
|
-
"twsx:dev": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure",
|
|
660
|
-
"dev": "npm run twsx:watch & next dev"
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
3. For development with auto-rebuild:
|
|
666
|
-
```bash
|
|
667
|
-
npm run twsx:watch
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
4. For production build:
|
|
671
|
-
```bash
|
|
672
|
-
npm run twsx:build
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
**VS Code Integration:**
|
|
676
|
-
Add to your workspace settings (`.vscode/settings.json`):
|
|
677
|
-
```json
|
|
678
|
-
{
|
|
679
|
-
"emeraldwalk.runonsave": {
|
|
680
|
-
"commands": [
|
|
681
|
-
{
|
|
682
|
-
"match": "twsx\\..*\\.js$",
|
|
683
|
-
"cmd": "npm run twsx:build"
|
|
684
|
-
}
|
|
685
|
-
]
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
#### Automatic Integration
|
|
691
|
-
|
|
692
|
-
You can add this script to the build section in your `package.json`:
|
|
693
|
-
|
|
694
|
-
```json
|
|
695
|
-
{
|
|
696
|
-
"scripts": {
|
|
697
|
-
"build-css": "node tailwind-to-style/lib/twsx-cli.js"
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
Then run:
|
|
703
|
-
|
|
704
|
-
```bash
|
|
705
|
-
npm run build-css
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
This script is suitable for CI/CD workflows, pre-build steps, or manually generating CSS without a bundler plugin.
|
|
709
|
-
|
|
710
|
-
## License
|
|
711
|
-
|
|
712
|
-
## Contributing
|
|
713
|
-
|
|
714
|
-
Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
|
|
715
|
-
|
|
716
|
-
## License
|
|
717
|
-
|
|
718
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
719
|
-
|
|
720
|
-
---
|
|
721
|
-
|
|
722
|
-
Feel free to contribute or raise issues on the [GitHub repository](https://github.com/Bigetion/tailwind-to-style).
|
|
1
|
+
# tailwind-to-style
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/tailwind-to-style)
|
|
4
|
+
[](https://github.com/Bigetion/tailwind-to-style/actions)
|
|
5
|
+
[](https://www.npmjs.com/package/tailwind-to-style)
|
|
6
|
+
[](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, state variants, and grouping.
|
|
14
|
+
3. **`twsx-cli`**: A command-line tool for generating CSS files from `twsx.*.js` files with watch mode support.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
To use `tailwind-to-style`, install the library using either npm or yarn:
|
|
19
|
+
|
|
20
|
+
### Using npm
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install tailwind-to-style
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Using yarn
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
yarn add tailwind-to-style
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Core Functions
|
|
33
|
+
|
|
34
|
+
### 1. `tws`
|
|
35
|
+
|
|
36
|
+
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.
|
|
37
|
+
|
|
38
|
+
#### Features of `tws`:
|
|
39
|
+
|
|
40
|
+
- Converts Tailwind utility classes into **inline CSS** or **JSON style objects**.
|
|
41
|
+
|
|
42
|
+
#### Usage
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
import { tws } from "tailwind-to-style";
|
|
46
|
+
|
|
47
|
+
// Convert Tailwind classes to inline CSS
|
|
48
|
+
const styleInline = tws("bg-white mx-auto");
|
|
49
|
+
// Output: background-color:rgba(255, 255, 255, 1); margin-left:auto; margin-right:auto;
|
|
50
|
+
|
|
51
|
+
// Convert Tailwind classes to JSON style object
|
|
52
|
+
const styleJSON = tws("bg-white mx-auto", 1);
|
|
53
|
+
// Output: { backgroundColor: 'rgba(255, 255, 255, 1)', marginLeft: 'auto', marginRight: 'auto' }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- **First argument**: The string of Tailwind classes to convert.
|
|
57
|
+
- **Second argument (optional)**: Pass `1` to get the result as a JSON object (default is inline CSS when omitted).
|
|
58
|
+
|
|
59
|
+
#### Example in React:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
import React from "react";
|
|
63
|
+
import { tws } from "tailwind-to-style";
|
|
64
|
+
|
|
65
|
+
const App = () => {
|
|
66
|
+
return (
|
|
67
|
+
<div style={tws("text-red-500 bg-blue-200 p-4", 1)}>
|
|
68
|
+
Hello, this is styled using tailwind-to-style
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default App;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This will apply the Tailwind classes directly as inline styles in the React component.
|
|
77
|
+
|
|
78
|
+
### 2. `twsx`
|
|
79
|
+
|
|
80
|
+
`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.
|
|
81
|
+
|
|
82
|
+
#### Features of `twsx`:
|
|
83
|
+
|
|
84
|
+
- ✅ **Nested styles** similar to SCSS, enabling more complex CSS structures
|
|
85
|
+
- ✅ **Grouping**: Supports grouping utilities inside parentheses `hover:(bg-blue-600 scale-105)`
|
|
86
|
+
- ✅ **Responsive variants** (`sm`, `md`, `lg`, `xl`, `2xl`) in standard and grouping syntax
|
|
87
|
+
- ✅ **State variants** like `hover`, `focus`, `active`, `disabled`, etc.
|
|
88
|
+
- ✅ **Dynamic utilities** such as `w-[300px]`, `bg-[rgba(0,0,0,0.5)]`, `text-[14px]`
|
|
89
|
+
- ✅ **!important support** with `!text-red-500`, `!bg-blue-500`
|
|
90
|
+
- ✅ **@css directive**: Apply custom CSS properties for animations, transitions, and modern effects
|
|
91
|
+
|
|
92
|
+
#### Basic Usage
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
import { twsx } from "tailwind-to-style";
|
|
96
|
+
|
|
97
|
+
const styles = twsx({
|
|
98
|
+
".card": [
|
|
99
|
+
"bg-white p-4 rounded-lg shadow-md",
|
|
100
|
+
{
|
|
101
|
+
"&:hover": "shadow-xl scale-105",
|
|
102
|
+
".title": "text-lg font-bold text-gray-900",
|
|
103
|
+
".desc": "text-sm text-gray-600 mt-2",
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
console.log(styles);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Output**:
|
|
112
|
+
|
|
113
|
+
```css
|
|
114
|
+
.card {
|
|
115
|
+
background-color: rgba(255, 255, 255, var(--bg-opacity));
|
|
116
|
+
padding: 1rem;
|
|
117
|
+
border-radius: 0.5rem;
|
|
118
|
+
box-shadow:
|
|
119
|
+
0 4px 6px -1px rgb(0 0 0 / 0.1),
|
|
120
|
+
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
121
|
+
}
|
|
122
|
+
.card:hover {
|
|
123
|
+
box-shadow:
|
|
124
|
+
0 20px 25px -5px rgb(0 0 0 / 0.1),
|
|
125
|
+
0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
126
|
+
transform: scale(1.05);
|
|
127
|
+
}
|
|
128
|
+
.card .title {
|
|
129
|
+
font-size: 1.125rem;
|
|
130
|
+
font-weight: 700;
|
|
131
|
+
color: rgba(17, 24, 39, var(--text-opacity));
|
|
132
|
+
}
|
|
133
|
+
.card .desc {
|
|
134
|
+
font-size: 0.875rem;
|
|
135
|
+
color: rgba(75, 85, 99, var(--text-opacity));
|
|
136
|
+
margin-top: 0.5rem;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### Grouping Support
|
|
141
|
+
|
|
142
|
+
Group related utilities together inside parentheses for better readability and organization:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const styles = twsx({
|
|
146
|
+
".button": [
|
|
147
|
+
"bg-blue-500 text-white px-6 py-3 rounded-lg",
|
|
148
|
+
"hover:(bg-blue-600 scale-105 shadow-lg)",
|
|
149
|
+
"focus:(ring-2 ring-blue-300 outline-none)",
|
|
150
|
+
"active:(bg-blue-700 scale-95)",
|
|
151
|
+
],
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Output**:
|
|
156
|
+
|
|
157
|
+
```css
|
|
158
|
+
.button {
|
|
159
|
+
background-color: rgba(59, 130, 246, var(--bg-opacity));
|
|
160
|
+
color: rgba(255, 255, 255, var(--text-opacity));
|
|
161
|
+
padding: 0.75rem 1.5rem;
|
|
162
|
+
border-radius: 0.5rem;
|
|
163
|
+
}
|
|
164
|
+
.button:hover {
|
|
165
|
+
background-color: rgba(37, 99, 235, var(--bg-opacity));
|
|
166
|
+
transform: scale(1.05);
|
|
167
|
+
box-shadow:
|
|
168
|
+
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
169
|
+
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
170
|
+
}
|
|
171
|
+
.button:focus {
|
|
172
|
+
box-shadow: var(--ring-offset-shadow), var(--ring-shadow);
|
|
173
|
+
outline: none;
|
|
174
|
+
}
|
|
175
|
+
.button:active {
|
|
176
|
+
background-color: rgba(29, 78, 216, var(--bg-opacity));
|
|
177
|
+
transform: scale(0.95);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### Responsive Variants
|
|
182
|
+
|
|
183
|
+
Responsive variants work seamlessly with both standard syntax and grouping syntax:
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
const styles = twsx({
|
|
187
|
+
".hero": [
|
|
188
|
+
// Standard responsive syntax
|
|
189
|
+
"text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl",
|
|
190
|
+
"w-full md:w-1/2 lg:w-1/3 p-4",
|
|
191
|
+
// Grouped responsive syntax
|
|
192
|
+
"sm:(py-16 px-4)",
|
|
193
|
+
"md:(py-20 px-6)",
|
|
194
|
+
"lg:(py-24 px-8)",
|
|
195
|
+
{
|
|
196
|
+
h1: "font-bold text-gray-900",
|
|
197
|
+
p: "text-gray-600 mt-4",
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Output**:
|
|
204
|
+
|
|
205
|
+
```css
|
|
206
|
+
.hero {
|
|
207
|
+
font-size: 1.5rem;
|
|
208
|
+
width: 100%;
|
|
209
|
+
padding: 1rem;
|
|
210
|
+
}
|
|
211
|
+
@media (min-width: 640px) {
|
|
212
|
+
.hero {
|
|
213
|
+
font-size: 1.875rem;
|
|
214
|
+
padding: 4rem 1rem;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
@media (min-width: 768px) {
|
|
218
|
+
.hero {
|
|
219
|
+
font-size: 2.25rem;
|
|
220
|
+
width: 50%;
|
|
221
|
+
padding: 5rem 1.5rem;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
@media (min-width: 1024px) {
|
|
225
|
+
.hero {
|
|
226
|
+
font-size: 3rem;
|
|
227
|
+
width: 33.333333%;
|
|
228
|
+
padding: 6rem 2rem;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
@media (min-width: 1280px) {
|
|
232
|
+
.hero {
|
|
233
|
+
font-size: 3.75rem;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
.hero h1 {
|
|
237
|
+
font-weight: 700;
|
|
238
|
+
color: rgba(17, 24, 39, var(--text-opacity));
|
|
239
|
+
}
|
|
240
|
+
.hero p {
|
|
241
|
+
color: rgba(75, 85, 99, var(--text-opacity));
|
|
242
|
+
margin-top: 1rem;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Performance Utilities
|
|
247
|
+
|
|
248
|
+
The library includes performance optimization features:
|
|
249
|
+
|
|
250
|
+
#### Inject Option
|
|
251
|
+
|
|
252
|
+
Control CSS output location with the `inject` option:
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
import { tws, twsx } from "tailwind-to-style";
|
|
256
|
+
|
|
257
|
+
// Auto-inject into document head (default)
|
|
258
|
+
const styles1 = tws("bg-blue-500 text-white p-4");
|
|
259
|
+
|
|
260
|
+
// Skip injection - returns CSS only
|
|
261
|
+
const styles2 = tws("bg-red-500 text-black p-2", { inject: false });
|
|
262
|
+
|
|
263
|
+
// Custom injection target
|
|
264
|
+
const targetElement = document.getElementById("custom-styles");
|
|
265
|
+
const styles3 = tws("bg-green-500 text-yellow p-3", { inject: targetElement });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
#### Performance Monitoring
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
import { tws } from "tailwind-to-style";
|
|
272
|
+
|
|
273
|
+
// Enable performance logging
|
|
274
|
+
const start = performance.now();
|
|
275
|
+
const styles = tws("complex-classes here...");
|
|
276
|
+
const end = performance.now();
|
|
277
|
+
console.log(`Generation time: ${end - start}ms`);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Advanced `@css` Directive
|
|
281
|
+
|
|
282
|
+
There are several ways to use the `@css` feature:
|
|
283
|
+
|
|
284
|
+
1. **As a nested object inside selectors**:
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
const styles = twsx({
|
|
288
|
+
".button": [
|
|
289
|
+
"bg-blue-500 text-white rounded-md",
|
|
290
|
+
{
|
|
291
|
+
"@css": {
|
|
292
|
+
transition: "all 0.3s ease-in-out",
|
|
293
|
+
"will-change": "transform, opacity",
|
|
294
|
+
},
|
|
295
|
+
"&:hover": "bg-blue-600",
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Output**:
|
|
302
|
+
|
|
303
|
+
```css
|
|
304
|
+
.button {
|
|
305
|
+
background-color: #3b82f6;
|
|
306
|
+
color: white;
|
|
307
|
+
border-radius: 0.375rem;
|
|
308
|
+
transition: all 0.3s ease-in-out;
|
|
309
|
+
will-change: transform, opacity;
|
|
310
|
+
}
|
|
311
|
+
.button:hover {
|
|
312
|
+
background-color: #2563eb;
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
2. **As a direct property in the selector**:
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
const styles = twsx({
|
|
320
|
+
".button @css transition": "all 0.3s ease-in-out",
|
|
321
|
+
".button": "bg-blue-500 text-white rounded-md",
|
|
322
|
+
".button:hover": "bg-blue-600",
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
This syntax is especially useful when you need to add just a single CSS property that isn't available in Tailwind.
|
|
327
|
+
|
|
328
|
+
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.
|
|
329
|
+
|
|
330
|
+
#### Advanced `@css` Examples:
|
|
331
|
+
|
|
332
|
+
You can combine `@css` with state variants:
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
const styles = twsx({
|
|
336
|
+
".modal": [
|
|
337
|
+
"bg-white rounded-lg shadow-xl",
|
|
338
|
+
{
|
|
339
|
+
"@css": {
|
|
340
|
+
transform: "translateX(0px)",
|
|
341
|
+
transition: "all 0.3s ease-out",
|
|
342
|
+
"will-change": "transform, opacity",
|
|
343
|
+
},
|
|
344
|
+
"&.hidden": [
|
|
345
|
+
"opacity-0",
|
|
346
|
+
{
|
|
347
|
+
"@css": {
|
|
348
|
+
transform: "translateX(-100px)",
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
],
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Output**:
|
|
358
|
+
|
|
359
|
+
```css
|
|
360
|
+
.modal {
|
|
361
|
+
background-color: white;
|
|
362
|
+
border-radius: 0.5rem;
|
|
363
|
+
box-shadow:
|
|
364
|
+
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
|
365
|
+
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
366
|
+
transform: translateX(0px);
|
|
367
|
+
transition: all 0.3s ease-out;
|
|
368
|
+
will-change: transform, opacity;
|
|
369
|
+
}
|
|
370
|
+
.modal.hidden {
|
|
371
|
+
opacity: 0;
|
|
372
|
+
transform: translateX(-100px);
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
For responsive styles, you can use standard Tailwind responsive utilities within your classes:
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
const styles = twsx({
|
|
380
|
+
".responsive-box": "w-full md:w-1/2 lg:w-1/3 p-4 bg-blue-500",
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
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.
|
|
385
|
+
|
|
386
|
+
### Inject Option (Browser Only)
|
|
387
|
+
|
|
388
|
+
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.
|
|
389
|
+
|
|
390
|
+
You can control this behavior with the `inject` option:
|
|
391
|
+
|
|
392
|
+
```js
|
|
393
|
+
// Auto-inject (default)
|
|
394
|
+
twsx({ ... }) // CSS is injected automatically
|
|
395
|
+
|
|
396
|
+
// Disable auto-inject
|
|
397
|
+
twsx({ ... }, { inject: false }) // CSS is NOT injected, just returned as string
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
- **inject: true** (default): CSS is injected into the page (browser only).
|
|
401
|
+
- **inject: false**: CSS is only returned as a string, not injected. Useful for SSR, testing, or custom handling.
|
|
402
|
+
|
|
403
|
+
> Note: This option only affects browser usage. In Node.js or SSR, no injection occurs.
|
|
404
|
+
|
|
405
|
+
## Performance Monitoring & Debugging (v2.7.0+)
|
|
406
|
+
|
|
407
|
+
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.
|
|
408
|
+
|
|
409
|
+
### Performance Utils
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
import { performanceUtils } from "tailwind-to-style";
|
|
413
|
+
|
|
414
|
+
// Enable performance logging (logs operations > 5ms as warnings)
|
|
415
|
+
performanceUtils.enablePerformanceLogging(true);
|
|
416
|
+
|
|
417
|
+
// Get cache and injection statistics
|
|
418
|
+
const stats = performanceUtils.getStats();
|
|
419
|
+
console.log(stats);
|
|
420
|
+
// Output:
|
|
421
|
+
// {
|
|
422
|
+
// cacheStats: {
|
|
423
|
+
// cssResolution: 45,
|
|
424
|
+
// configOptions: 2,
|
|
425
|
+
// parseSelector: 23,
|
|
426
|
+
// encodeBracket: 12,
|
|
427
|
+
// decodeBracket: 8
|
|
428
|
+
// },
|
|
429
|
+
// injectionStats: {
|
|
430
|
+
// uniqueStylesheets: 15
|
|
431
|
+
// }
|
|
432
|
+
// }
|
|
433
|
+
|
|
434
|
+
// Clear all caches (useful for memory management)
|
|
435
|
+
performanceUtils.clearCaches();
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Performance Metrics
|
|
439
|
+
|
|
440
|
+
The library automatically tracks performance for key operations:
|
|
441
|
+
|
|
442
|
+
- **tws:total** - Total execution time for `tws()`
|
|
443
|
+
- **tws:parse** - Time spent parsing classes
|
|
444
|
+
- **tws:process** - Time spent processing classes
|
|
445
|
+
- **twsx:total** - Total execution time for `twsx()`
|
|
446
|
+
- **twsx:flatten** - Time spent flattening objects
|
|
447
|
+
- **twsx:generate** - Time spent generating CSS
|
|
448
|
+
- **css:inject** - Time spent injecting CSS to DOM
|
|
449
|
+
|
|
450
|
+
### Debounced Functions
|
|
451
|
+
|
|
452
|
+
For high-frequency usage, use the debounced versions:
|
|
453
|
+
|
|
454
|
+
```javascript
|
|
455
|
+
import { debouncedTws, debouncedTwsx } from "tailwind-to-style";
|
|
456
|
+
|
|
457
|
+
// Debounced versions (50ms for tws, 100ms for twsx)
|
|
458
|
+
const styles = debouncedTws("bg-red-500 p-4");
|
|
459
|
+
const complexStyles = debouncedTwsx({ ".card": "bg-white p-6" });
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Example: Performance Monitoring
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
import { tws, twsx, performanceUtils } from "tailwind-to-style";
|
|
466
|
+
|
|
467
|
+
// Enable monitoring
|
|
468
|
+
performanceUtils.enablePerformanceLogging(true);
|
|
469
|
+
|
|
470
|
+
// Your code that uses tws/twsx
|
|
471
|
+
const styles = tws("bg-gradient-to-r from-purple-400 to-pink-500 p-8");
|
|
472
|
+
const complexStyles = twsx({
|
|
473
|
+
".hero": [
|
|
474
|
+
"bg-gradient-to-br from-indigo-900 to-purple-900 min-h-screen",
|
|
475
|
+
{
|
|
476
|
+
h1: "text-6xl font-bold text-white md:text-4xl",
|
|
477
|
+
"@css": {
|
|
478
|
+
transition: "font-size 0.3s ease-in-out",
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Check performance stats
|
|
485
|
+
console.log(performanceUtils.getStats());
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
This will automatically log warnings for operations taking longer than 5ms and provide insights into cache usage and performance bottlenecks.
|
|
489
|
+
|
|
490
|
+
# Build-Time Plugins: Vite & Webpack
|
|
491
|
+
|
|
492
|
+
### Automated Modular CSS Generation
|
|
493
|
+
|
|
494
|
+
1. Create JS files with `twsx.` prefix in your project (e.g., `twsx.card.js`, `twsx.button.js`) anywhere in your `src/` folder.
|
|
495
|
+
2. Use the Vite/Webpack plugin from the `plugins/` folder to automatically generate CSS on every build/rebuild.
|
|
496
|
+
3. Each JS file will generate its own CSS file in the specified output directory (default: `src/styles/`).
|
|
497
|
+
4. Import the generated CSS files directly in your components or bundle them as needed.
|
|
498
|
+
|
|
499
|
+
#### Vite Plugin Usage Example
|
|
500
|
+
|
|
501
|
+
Add the plugin to your `vite.config.js`:
|
|
502
|
+
```js
|
|
503
|
+
import twsxPlugin from 'tailwind-to-style/plugins/vite-twsx';
|
|
504
|
+
|
|
505
|
+
export default {
|
|
506
|
+
plugins: [
|
|
507
|
+
twsxPlugin({
|
|
508
|
+
inputDir: 'src',
|
|
509
|
+
outputDir: 'src/styles',
|
|
510
|
+
preserveStructure: false // Set to true to generate CSS next to JS files
|
|
511
|
+
})
|
|
512
|
+
]
|
|
513
|
+
};
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**Configuration Options:**
|
|
517
|
+
- `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
|
|
518
|
+
- `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
|
|
519
|
+
- `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
|
|
520
|
+
|
|
521
|
+
**Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
|
|
522
|
+
**Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
|
|
523
|
+
|
|
524
|
+
Import in your components:
|
|
525
|
+
```js
|
|
526
|
+
// Default mode
|
|
527
|
+
import './styles/twsx.card.css';
|
|
528
|
+
import './styles/twsx.button.css';
|
|
529
|
+
|
|
530
|
+
// Preserve structure mode
|
|
531
|
+
import './twsx.card.css'; // If in same directory
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
#### Webpack Plugin Usage Example
|
|
535
|
+
|
|
536
|
+
Add the plugin to your `webpack.config.js`:
|
|
537
|
+
```js
|
|
538
|
+
import TwsxPlugin from 'tailwind-to-style/plugins/webpack-twsx';
|
|
539
|
+
|
|
540
|
+
module.exports = {
|
|
541
|
+
plugins: [
|
|
542
|
+
new TwsxPlugin({
|
|
543
|
+
inputDir: 'src',
|
|
544
|
+
outputDir: 'src/styles',
|
|
545
|
+
preserveStructure: false // Set to true to generate CSS next to JS files
|
|
546
|
+
})
|
|
547
|
+
]
|
|
548
|
+
};
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Configuration Options:**
|
|
552
|
+
- `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
|
|
553
|
+
- `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
|
|
554
|
+
- `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
|
|
555
|
+
|
|
556
|
+
**Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
|
|
557
|
+
**Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
|
|
558
|
+
|
|
559
|
+
Import in your components:
|
|
560
|
+
```js
|
|
561
|
+
// Default mode
|
|
562
|
+
import './styles/twsx.card.css';
|
|
563
|
+
import './styles/twsx.button.css';
|
|
564
|
+
|
|
565
|
+
// Preserve structure mode
|
|
566
|
+
import './twsx.card.css'; // If in same directory
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Build-Time CSS Generation via Script
|
|
570
|
+
|
|
571
|
+
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.
|
|
572
|
+
|
|
573
|
+
### Script: tailwind-to-style/lib/twsx-cli.js (Legacy)
|
|
574
|
+
|
|
575
|
+
> **💡 Recommended:** Use `npx twsx-cli` instead of calling the script directly.
|
|
576
|
+
|
|
577
|
+
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.
|
|
578
|
+
|
|
579
|
+
#### How to Use
|
|
580
|
+
|
|
581
|
+
1. Create JS files with `twsx.` prefix containing style objects anywhere in your `src/` folder (e.g., `src/components/twsx.card.js`).
|
|
582
|
+
|
|
583
|
+
2. **One-time Build:**
|
|
584
|
+
```bash
|
|
585
|
+
node tailwind-to-style/lib/twsx-cli.js
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
3. **Watch Mode (Auto-rebuild on file changes):**
|
|
589
|
+
```bash
|
|
590
|
+
node tailwind-to-style/lib/twsx-cli.js --watch
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
4. **Preserve Structure Mode (Generate CSS next to JS files):**
|
|
594
|
+
```bash
|
|
595
|
+
# One-time build with preserve structure
|
|
596
|
+
node tailwind-to-style/lib/twsx-cli.js --preserve-structure
|
|
597
|
+
|
|
598
|
+
# Watch mode with preserve structure
|
|
599
|
+
node tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
You can configure input and output directories using environment variables:
|
|
603
|
+
```bash
|
|
604
|
+
TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/twsx-cli.js --watch
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Or use environment variables for preserve structure:
|
|
608
|
+
```bash
|
|
609
|
+
TWSX_PRESERVE_STRUCTURE=true node tailwind-to-style/lib/twsx-cli.js --watch
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
5. **Output locations:**
|
|
613
|
+
|
|
614
|
+
**Default mode:** CSS files will be in the output directory (default: `src/styles/`):
|
|
615
|
+
```
|
|
616
|
+
src/styles/twsx.card.css
|
|
617
|
+
src/styles/twsx.button.css
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
**Preserve structure mode:** CSS files will be generated next to their JS counterparts:
|
|
621
|
+
```
|
|
622
|
+
src/components/Button/twsx.button.js → src/components/Button/twsx.button.css
|
|
623
|
+
src/components/Card/twsx.card.js → src/components/Card/twsx.card.css
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
5. Import the generated CSS files in your components:
|
|
627
|
+
|
|
628
|
+
**Default mode:**
|
|
629
|
+
```js
|
|
630
|
+
import './styles/twsx.card.css';
|
|
631
|
+
import './styles/twsx.button.css';
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**Preserve structure mode:**
|
|
635
|
+
```js
|
|
636
|
+
// In src/components/Button/Button.jsx
|
|
637
|
+
import './twsx.button.css';
|
|
638
|
+
|
|
639
|
+
// In src/components/Card/Card.jsx
|
|
640
|
+
import './twsx.card.css';
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
#### Usage in Different Projects
|
|
644
|
+
|
|
645
|
+
**React/Next.js/Vue/Any Project:**
|
|
646
|
+
|
|
647
|
+
1. Install the package:
|
|
648
|
+
```bash
|
|
649
|
+
npm install tailwind-to-style
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
2. Add to your `package.json`:
|
|
653
|
+
```json
|
|
654
|
+
{
|
|
655
|
+
"scripts": {
|
|
656
|
+
"twsx:build": "node node_modules/tailwind-to-style/lib/twsx-cli.js",
|
|
657
|
+
"twsx:watch": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch",
|
|
658
|
+
"twsx:preserve": "node node_modules/tailwind-to-style/lib/twsx-cli.js --preserve-structure",
|
|
659
|
+
"twsx:dev": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure",
|
|
660
|
+
"dev": "npm run twsx:watch & next dev"
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
3. For development with auto-rebuild:
|
|
666
|
+
```bash
|
|
667
|
+
npm run twsx:watch
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
4. For production build:
|
|
671
|
+
```bash
|
|
672
|
+
npm run twsx:build
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**VS Code Integration:**
|
|
676
|
+
Add to your workspace settings (`.vscode/settings.json`):
|
|
677
|
+
```json
|
|
678
|
+
{
|
|
679
|
+
"emeraldwalk.runonsave": {
|
|
680
|
+
"commands": [
|
|
681
|
+
{
|
|
682
|
+
"match": "twsx\\..*\\.js$",
|
|
683
|
+
"cmd": "npm run twsx:build"
|
|
684
|
+
}
|
|
685
|
+
]
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
#### Automatic Integration
|
|
691
|
+
|
|
692
|
+
You can add this script to the build section in your `package.json`:
|
|
693
|
+
|
|
694
|
+
```json
|
|
695
|
+
{
|
|
696
|
+
"scripts": {
|
|
697
|
+
"build-css": "node tailwind-to-style/lib/twsx-cli.js"
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
Then run:
|
|
703
|
+
|
|
704
|
+
```bash
|
|
705
|
+
npm run build-css
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
This script is suitable for CI/CD workflows, pre-build steps, or manually generating CSS without a bundler plugin.
|
|
709
|
+
|
|
710
|
+
## License
|
|
711
|
+
|
|
712
|
+
## Contributing
|
|
713
|
+
|
|
714
|
+
Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
|
|
715
|
+
|
|
716
|
+
## License
|
|
717
|
+
|
|
718
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
Feel free to contribute or raise issues on the [GitHub repository](https://github.com/Bigetion/tailwind-to-style).
|