cls-extended 1.1.1 → 1.1.3
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 +349 -66
- package/dist/adapters/vite.d.ts +2 -1
- package/dist/adapters/vite.d.ts.map +1 -0
- package/dist/adapters/vite.js +2 -1
- package/dist/adapters/vite.js.map +1 -0
- package/dist/adapters/webpack.d.ts +2 -1
- package/dist/adapters/webpack.d.ts.map +1 -0
- package/dist/adapters/webpack.js +2 -1
- package/dist/adapters/webpack.js.map +1 -0
- package/dist/api.d.ts +2 -1
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -1
- package/dist/api.js.map +1 -0
- package/dist/core/options.d.ts +2 -1
- package/dist/core/options.d.ts.map +1 -0
- package/dist/core/options.js +2 -1
- package/dist/core/options.js.map +1 -0
- package/dist/core/parser.d.ts +2 -1
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +2 -1
- package/dist/core/parser.js.map +1 -0
- package/dist/core/transform.d.ts +2 -1
- package/dist/core/transform.d.ts.map +1 -0
- package/dist/core/transform.js +2 -1
- package/dist/core/transform.js.map +1 -0
- package/dist/unplugin-factory.d.ts +2 -1
- package/dist/unplugin-factory.d.ts.map +1 -0
- package/dist/unplugin-factory.js +2 -1
- package/dist/unplugin-factory.js.map +1 -0
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -1,112 +1,146 @@
|
|
|
1
|
-
#
|
|
1
|
+
# cls-extended
|
|
2
2
|
|
|
3
|
-
[![npm version]
|
|
4
|
-
[![npm downloads]
|
|
3
|
+
[](https://www.npmjs.com/package/cls-extended)
|
|
4
|
+
[](https://www.npmjs.com/package/cls-extended)
|
|
5
5
|
|
|
6
6
|
Zero-runtime Tailwind CSS responsive class transformer. Write cleaner responsive syntax that compiles to standard Tailwind classes at build time.
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- ⚡ **Zero Runtime Overhead** -
|
|
11
|
-
- 🎨 **Better DX** -
|
|
10
|
+
- ⚡ **Zero Runtime Overhead** - Build-time transformations for Vite/Webpack (0KB runtime). Next.js 16+ with Turbopack uses tiny runtime fallback (~0.5KB)
|
|
11
|
+
- 🎨 **Better DX** - Reduces code verbosity by ~40% for responsive designs
|
|
12
12
|
- 🔧 **Universal** - Works with Vite, Webpack, Rollup, esbuild, Rspack, Rolldown, and Farm
|
|
13
|
-
- 📦 **Tiny Bundle** - ~8KB
|
|
14
|
-
- 🔒 **Type Safe** - Full TypeScript support
|
|
13
|
+
- 📦 **Tiny Bundle** - ~8KB package
|
|
14
|
+
- 🔒 **Type Safe** - Full TypeScript support with intelligent autocomplete
|
|
15
|
+
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
|
-
npm
|
|
20
|
+
npm install -D cls-extended
|
|
21
|
+
# or
|
|
22
|
+
pnpm add -D cls-extended
|
|
23
|
+
# or
|
|
24
|
+
yarn add -D cls-extended
|
|
20
25
|
```
|
|
21
26
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
### Setup Plugin
|
|
27
|
+
## Setup
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
<summary>Vite</summary><br>
|
|
29
|
+
### Vite
|
|
28
30
|
|
|
29
31
|
```ts
|
|
30
32
|
// vite.config.ts
|
|
31
|
-
import
|
|
33
|
+
import { defineConfig } from "vite";
|
|
34
|
+
import clsExtended from "cls-extended/adapters/vite";
|
|
32
35
|
|
|
33
36
|
export default defineConfig({
|
|
34
37
|
plugins: [clsExtended()],
|
|
35
|
-
})
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Next.js (Webpack) - Before Next.js 16
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
// next.config.mjs
|
|
45
|
+
import clsExtended from "cls-extended/adapters/webpack";
|
|
46
|
+
|
|
47
|
+
export default {
|
|
48
|
+
webpack: (config) => {
|
|
49
|
+
config.plugins = config.plugins || [];
|
|
50
|
+
config.plugins.push(clsExtended());
|
|
51
|
+
return config;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Next.js (Webpack) - After Next.js 16
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
// next.config.mjs
|
|
60
|
+
import type { NextConfig } from "next";
|
|
61
|
+
|
|
62
|
+
const nextConfig: NextConfig = {
|
|
63
|
+
// Note: cls-extended plugin integration for Next.js 16+ with Turbopack is not yet supported.
|
|
64
|
+
// For now, use the runtime cls() function directly.
|
|
65
|
+
// leave the config as it is!
|
|
66
|
+
turbopack: {},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default nextConfig;
|
|
36
70
|
```
|
|
37
71
|
|
|
38
|
-
</details>
|
|
39
72
|
|
|
40
73
|
<details>
|
|
41
|
-
<summary>
|
|
74
|
+
<summary> <h3 style="display: inline;" > Check Other Adapters (rspack, rolldown, farm etc.) </h3> </summary>
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
### Webpack
|
|
42
78
|
|
|
43
79
|
```js
|
|
44
80
|
// webpack.config.js
|
|
45
|
-
import clsExtended from
|
|
81
|
+
import clsExtended from "cls-extended/adapters/webpack";
|
|
46
82
|
|
|
47
83
|
export default {
|
|
48
84
|
plugins: [clsExtended()],
|
|
49
|
-
}
|
|
85
|
+
};
|
|
50
86
|
```
|
|
51
87
|
|
|
52
|
-
</details>
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
<summary>Rollup</summary><br>
|
|
89
|
+
### Rollup
|
|
56
90
|
|
|
57
91
|
```ts
|
|
58
92
|
// rollup.config.js
|
|
59
|
-
import clsExtended from
|
|
93
|
+
import clsExtended from "cls-extended/adapters/rollup";
|
|
60
94
|
|
|
61
95
|
export default {
|
|
62
96
|
plugins: [clsExtended()],
|
|
63
|
-
}
|
|
97
|
+
};
|
|
64
98
|
```
|
|
65
99
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<details>
|
|
69
|
-
<summary>esbuild</summary><br>
|
|
100
|
+
### esbuild
|
|
70
101
|
|
|
71
102
|
```ts
|
|
72
|
-
import { build } from
|
|
73
|
-
import clsExtended from
|
|
103
|
+
import { build } from "esbuild";
|
|
104
|
+
import clsExtended from "cls-extended/adapters/esbuild";
|
|
74
105
|
|
|
75
106
|
build({
|
|
76
107
|
plugins: [clsExtended()],
|
|
77
|
-
})
|
|
108
|
+
});
|
|
78
109
|
```
|
|
79
110
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<details>
|
|
83
|
-
<summary>Rspack</summary><br>
|
|
111
|
+
### Rspack
|
|
84
112
|
|
|
85
113
|
```ts
|
|
86
114
|
// rspack.config.js
|
|
87
|
-
import clsExtended from
|
|
115
|
+
import clsExtended from "cls-extended/adapters/rspack";
|
|
88
116
|
|
|
89
117
|
export default {
|
|
90
118
|
plugins: [clsExtended()],
|
|
91
|
-
}
|
|
119
|
+
};
|
|
92
120
|
```
|
|
93
121
|
|
|
122
|
+
|
|
94
123
|
</details>
|
|
95
124
|
|
|
96
|
-
|
|
125
|
+
|
|
126
|
+
## Usage
|
|
127
|
+
|
|
128
|
+
### Basic Usage
|
|
97
129
|
|
|
98
130
|
```tsx
|
|
99
|
-
import { cls } from
|
|
131
|
+
import { cls } from "cls-extended";
|
|
100
132
|
|
|
101
133
|
function Component() {
|
|
102
134
|
return (
|
|
103
|
-
<div
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
135
|
+
<div
|
|
136
|
+
className={cls("text-xl font-bold", {
|
|
137
|
+
md: "text-2xl",
|
|
138
|
+
lg: "text-3xl",
|
|
139
|
+
})}
|
|
140
|
+
>
|
|
107
141
|
Responsive Text
|
|
108
142
|
</div>
|
|
109
|
-
)
|
|
143
|
+
);
|
|
110
144
|
}
|
|
111
145
|
```
|
|
112
146
|
|
|
@@ -118,46 +152,295 @@ function Component() {
|
|
|
118
152
|
</div>
|
|
119
153
|
```
|
|
120
154
|
|
|
121
|
-
|
|
155
|
+
### Multiple Responsive Classes
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
cls("p-4 bg-white", {
|
|
159
|
+
md: "p-6 bg-gray-50",
|
|
160
|
+
lg: "p-8 shadow-lg",
|
|
161
|
+
xl: "max-w-7xl",
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Compiles to:
|
|
165
|
+
// "p-4 bg-white md:p-6 md:bg-gray-50 lg:p-8 lg:shadow-lg xl:max-w-7xl"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Complex Layouts
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
function Card() {
|
|
172
|
+
return (
|
|
173
|
+
<div
|
|
174
|
+
className={cls("container mx-auto px-4", {
|
|
175
|
+
sm: "px-6",
|
|
176
|
+
md: "px-8 max-w-4xl",
|
|
177
|
+
lg: "max-w-6xl",
|
|
178
|
+
xl: "max-w-7xl px-12",
|
|
179
|
+
})}
|
|
180
|
+
>
|
|
181
|
+
<h1
|
|
182
|
+
className={cls("text-2xl font-bold text-gray-900", {
|
|
183
|
+
md: "text-3xl",
|
|
184
|
+
lg: "text-4xl",
|
|
185
|
+
xl: "text-5xl",
|
|
186
|
+
})}
|
|
187
|
+
>
|
|
188
|
+
Heading
|
|
189
|
+
</h1>
|
|
190
|
+
<p
|
|
191
|
+
className={cls("text-base text-gray-600", {
|
|
192
|
+
md: "text-lg",
|
|
193
|
+
lg: "text-xl",
|
|
194
|
+
})}
|
|
195
|
+
>
|
|
196
|
+
Description
|
|
197
|
+
</p>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Conditional Classes
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
function Button({ variant, size }) {
|
|
207
|
+
return (
|
|
208
|
+
<button
|
|
209
|
+
className={cls(
|
|
210
|
+
"rounded font-medium",
|
|
211
|
+
variant === "primary" ? "bg-blue-500 text-white" : "bg-gray-200",
|
|
212
|
+
{
|
|
213
|
+
md: size === "large" ? "px-6 py-3 text-lg" : "px-4 py-2",
|
|
214
|
+
lg: "px-8 py-4 text-xl",
|
|
215
|
+
}
|
|
216
|
+
)}
|
|
217
|
+
>
|
|
218
|
+
Click me
|
|
219
|
+
</button>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Grid Layouts
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
function Grid() {
|
|
228
|
+
return (
|
|
229
|
+
<div
|
|
230
|
+
className={cls("grid grid-cols-1 gap-4", {
|
|
231
|
+
sm: "grid-cols-2 gap-6",
|
|
232
|
+
md: "grid-cols-3",
|
|
233
|
+
lg: "grid-cols-4 gap-8",
|
|
234
|
+
xl: "grid-cols-6",
|
|
235
|
+
})}
|
|
236
|
+
>
|
|
237
|
+
{/* Grid items */}
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## API Reference
|
|
122
244
|
|
|
123
245
|
### `cls(baseClasses, responsiveClasses?)`
|
|
124
246
|
|
|
125
247
|
Transform responsive Tailwind classes at build time.
|
|
126
248
|
|
|
127
249
|
**Parameters:**
|
|
128
|
-
|
|
250
|
+
|
|
251
|
+
- `baseClasses` (string) - Base Tailwind classes applied at all breakpoints
|
|
129
252
|
- `responsiveClasses` (object, optional) - Responsive breakpoint classes
|
|
130
253
|
|
|
131
254
|
**Supported Breakpoints:**
|
|
132
|
-
- `sm` - 640px
|
|
133
|
-
- `md` - 768px
|
|
134
|
-
- `lg` - 1024px
|
|
135
|
-
- `xl` - 1280px
|
|
136
|
-
- `2xl` - 1536px
|
|
137
255
|
|
|
138
|
-
|
|
256
|
+
| Breakpoint | Min Width | Description |
|
|
257
|
+
| ---------- | --------- | -------------------- |
|
|
258
|
+
| `sm` | 640px | Small devices |
|
|
259
|
+
| `md` | 768px | Medium devices |
|
|
260
|
+
| `lg` | 1024px | Large devices |
|
|
261
|
+
| `xl` | 1280px | Extra large devices |
|
|
262
|
+
| `2xl` | 1536px | 2X extra large |
|
|
263
|
+
|
|
264
|
+
**Returns:**
|
|
265
|
+
|
|
266
|
+
- At build time: Static string with all classes
|
|
267
|
+
- At runtime (fallback): Same string generated dynamically
|
|
268
|
+
|
|
269
|
+
**Examples:**
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
// Single breakpoint
|
|
273
|
+
cls("p-4", { md: "p-6" });
|
|
274
|
+
// → "p-4 md:p-6"
|
|
275
|
+
|
|
276
|
+
// Multiple breakpoints
|
|
277
|
+
cls("text-base", { md: "text-lg", lg: "text-xl" });
|
|
278
|
+
// → "text-base md:text-lg lg:text-xl"
|
|
279
|
+
|
|
280
|
+
// Multiple classes per breakpoint
|
|
281
|
+
cls("p-4 bg-white", { md: "p-6 shadow-lg" });
|
|
282
|
+
// → "p-4 bg-white md:p-6 md:shadow-lg"
|
|
283
|
+
|
|
284
|
+
// Only base classes
|
|
285
|
+
cls("container mx-auto");
|
|
286
|
+
// → "container mx-auto"
|
|
287
|
+
|
|
288
|
+
// Only responsive classes
|
|
289
|
+
cls("", { md: "hidden", lg: "block" });
|
|
290
|
+
// → "md:hidden lg:block"
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Configuration
|
|
294
|
+
|
|
295
|
+
### Plugin Options
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
clsExtended({
|
|
299
|
+
// Files to include (default: JS/TS/JSX/TSX files)
|
|
300
|
+
include: [/\.[jt]sx?$/],
|
|
301
|
+
|
|
302
|
+
// Files to exclude (default: node_modules)
|
|
303
|
+
exclude: [/node_modules/],
|
|
304
|
+
|
|
305
|
+
// Custom Tailwind breakpoints (optional)
|
|
306
|
+
breakpoints: {
|
|
307
|
+
sm: "640px",
|
|
308
|
+
md: "768px",
|
|
309
|
+
lg: "1024px",
|
|
310
|
+
xl: "1280px",
|
|
311
|
+
"2xl": "1536px",
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Custom Breakpoints
|
|
317
|
+
|
|
318
|
+
If you're using custom Tailwind breakpoints, configure them in the plugin:
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
// tailwind.config.js
|
|
322
|
+
export default {
|
|
323
|
+
theme: {
|
|
324
|
+
screens: {
|
|
325
|
+
tablet: "640px",
|
|
326
|
+
laptop: "1024px",
|
|
327
|
+
desktop: "1280px",
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
```
|
|
139
332
|
|
|
140
333
|
```ts
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
334
|
+
// vite.config.ts
|
|
335
|
+
clsExtended({
|
|
336
|
+
breakpoints: {
|
|
337
|
+
tablet: "640px",
|
|
338
|
+
laptop: "1024px",
|
|
339
|
+
desktop: "1280px",
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
// Usage
|
|
346
|
+
cls("p-4", { tablet: "p-6", laptop: "p-8" });
|
|
347
|
+
// → "p-4 tablet:p-6 laptop:p-8"
|
|
146
348
|
```
|
|
147
349
|
|
|
148
350
|
## How It Works
|
|
149
351
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
352
|
+
The plugin performs AST-based transformations during the build process:
|
|
353
|
+
|
|
354
|
+
1. **Parse**: Scans source files for `cls()` function calls
|
|
355
|
+
2. **Transform**: Uses Babel parser to analyze the AST
|
|
356
|
+
3. **Generate**: Converts object syntax to standard Tailwind classes
|
|
357
|
+
4. **Replace**: Replaces `cls()` calls with static strings
|
|
358
|
+
5. **Source Maps**: Maintains accurate debugging information
|
|
359
|
+
|
|
360
|
+
### Build-Time Transformation
|
|
361
|
+
|
|
362
|
+
**Input (what you write):**
|
|
363
|
+
|
|
364
|
+
```tsx
|
|
365
|
+
cls("text-xl font-bold", { md: "text-2xl", lg: "text-3xl" });
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Output (what gets compiled):**
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
"text-xl font-bold md:text-2xl lg:text-3xl";
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Zero Runtime Cost
|
|
375
|
+
|
|
376
|
+
- ✅ No `cls()` function in production bundle
|
|
377
|
+
- ✅ No runtime parsing or string manipulation
|
|
378
|
+
- ✅ No additional JavaScript overhead
|
|
379
|
+
- ✅ Just plain, static class strings
|
|
380
|
+
|
|
381
|
+
### Compatibility
|
|
382
|
+
|
|
383
|
+
- ✅ Works with Tailwind JIT mode
|
|
384
|
+
- ✅ Compatible with Tailwind's purge/content configuration
|
|
385
|
+
- ✅ Supports all Tailwind utility classes
|
|
386
|
+
- ✅ Maintains source maps for debugging
|
|
387
|
+
|
|
388
|
+
## TypeScript Support
|
|
389
|
+
|
|
390
|
+
Full TypeScript support with intelligent autocomplete:
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
import { cls } from "cls-extended";
|
|
394
|
+
|
|
395
|
+
// Type-safe breakpoints
|
|
396
|
+
const classes = cls("p-4", {
|
|
397
|
+
md: "p-6", // ✅ Valid breakpoint
|
|
398
|
+
lg: "p-8", // ✅ Valid breakpoint
|
|
399
|
+
// @ts-expect-error - Invalid breakpoint
|
|
400
|
+
invalid: "p-10",
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## Performance
|
|
405
|
+
|
|
406
|
+
### Package Size
|
|
407
|
+
|
|
408
|
+
[](https://bundlephobia.com/package/cls-extended)
|
|
409
|
+
[](https://bundlephobia.com/package/cls-extended)
|
|
410
|
+
[](https://bundlephobia.com/package/cls-extended)
|
|
411
|
+
|
|
412
|
+
> **Runtime Impact:** 0 KB for Vite/Webpack (build-time transformation) · ~0.5 KB for Next.js 16+ Turbopack (runtime fallback)
|
|
413
|
+
|
|
414
|
+
### Build Performance
|
|
415
|
+
|
|
416
|
+
- **File transformation**: <1ms per file
|
|
417
|
+
- **AST parsing**: ~0.3ms per file
|
|
418
|
+
- **Source map generation**: ~0.1ms per file
|
|
419
|
+
- **Memory usage**: <10MB for typical projects
|
|
420
|
+
|
|
421
|
+
## Examples
|
|
422
|
+
|
|
423
|
+
Check out the working examples:
|
|
424
|
+
|
|
425
|
+
- [Vite + React](../../examples/vite-react) - Basic Vite setup
|
|
426
|
+
- [Next.js](../../examples/nextjs) - Next.js integration
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
## Contributing
|
|
432
|
+
|
|
433
|
+
Contributions are welcome! See the [Root README](../../README.md) for development setup and contribution guidelines.
|
|
153
434
|
|
|
154
435
|
## License
|
|
155
436
|
|
|
156
|
-
[MIT](./LICENSE) License © 2025 [Yeasin](https://github.com/yeasin2002)
|
|
437
|
+
[MIT](./LICENSE) License © 2025-PRESENT [Yeasin](https://github.com/yeasin2002)
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
**Links:**
|
|
157
442
|
|
|
158
|
-
|
|
443
|
+
- [npm Package](https://www.npmjs.com/package/cls-extended)
|
|
444
|
+
- [GitHub Repository](https://github.com/yeasin2002/cls-extended)
|
|
445
|
+
- [Report Issues](https://github.com/yeasin2002/cls-extended/issues)
|
|
159
446
|
|
|
160
|
-
[npm-version-src]: https://img.shields.io/npm/v/@cls-extended/core.svg
|
|
161
|
-
[npm-version-href]: https://npmjs.com/package/@cls-extended/core
|
|
162
|
-
[npm-downloads-src]: https://img.shields.io/npm/dm/@cls-extended/core
|
|
163
|
-
[npm-downloads-href]: https://www.npmcharts.com/compare/@cls-extended/core?interval=30
|
package/dist/adapters/vite.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ import { UnpluginInstance } from "unplugin";
|
|
|
4
4
|
//#region src/adapters/vite.d.ts
|
|
5
5
|
declare const vitePlugin: UnpluginInstance<Options | undefined, false>["vite"];
|
|
6
6
|
//#endregion
|
|
7
|
-
export { vitePlugin as default };
|
|
7
|
+
export { vitePlugin as default };
|
|
8
|
+
//# sourceMappingURL=vite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.d.ts","names":[],"sources":["../../src/adapters/vite.ts"],"mappings":";;;;cAIM,UAAA,EAAY,gBAAA,CAAiB,OAAA"}
|
package/dist/adapters/vite.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","names":[],"sources":["../../src/adapters/vite.ts"],"sourcesContent":["import type { UnpluginInstance } from \"unplugin\";\nimport type { Options } from \"../core/options\";\nimport unplugin from \"../unplugin-factory\";\n\nconst vitePlugin: UnpluginInstance<Options | undefined, false>[\"vite\"] =\n unplugin.vite;\n\nexport default vitePlugin;\n"],"mappings":";;;AAIA,MAAM,aACJ,SAAS"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webpack.d.ts","names":[],"sources":["../../src/adapters/webpack.ts"],"mappings":";;;cAA2C,QAAA,SAED,QAAA,CAAS,OAAA"}
|
package/dist/adapters/webpack.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webpack.js","names":[],"sources":["../../src/adapters/webpack.ts"],"sourcesContent":["import unplugin from \"../unplugin-factory\";\n\nexport default unplugin.webpack as typeof unplugin.webpack;\n"],"mappings":";;;AAEA,sBAAe,SAAS"}
|
package/dist/api.d.ts
CHANGED
|
@@ -10,4 +10,5 @@ type ResponsiveClasses = Partial<Record<ResponsiveBreakpoint, string>>;
|
|
|
10
10
|
*/
|
|
11
11
|
declare function cls(baseClasses: string, responsiveClasses?: ResponsiveClasses): string;
|
|
12
12
|
//#endregion
|
|
13
|
-
export { ResponsiveBreakpoint, ResponsiveClasses, cls };
|
|
13
|
+
export { ResponsiveBreakpoint, ResponsiveClasses, cls };
|
|
14
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","names":[],"sources":["../src/api.ts"],"mappings":";KAAY,oBAAA;AAAA,KACA,iBAAA,GAAoB,OAAA,CAAQ,MAAA,CAAO,oBAAA;;;;;AAA/C;;;iBASgB,GAAA,CACd,WAAA,UACA,iBAAA,GAAoB,iBAAA"}
|
package/dist/api.js
CHANGED
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../src/api.ts"],"sourcesContent":["export type ResponsiveBreakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\";\nexport type ResponsiveClasses = Partial<Record<ResponsiveBreakpoint, string>>;\n\n/**\n * Transform responsive Tailwind classes at build time\n *\n * @example\n * tw('text-xl font-bold', { md: 'text-2xl', lg: 'text-3xl' })\n * // Compiles to: \"text-xl font-bold md:text-2xl lg:text-3xl\"\n */\nexport function cls(\n baseClasses: string,\n responsiveClasses?: ResponsiveClasses,\n): string {\n // This function is replaced at build time by the plugin\n // Runtime fallback for development without the plugin\n if (!responsiveClasses) return baseClasses;\n\n const parts = [baseClasses];\n for (const [breakpoint, classes] of Object.entries(responsiveClasses)) {\n const prefixed = classes\n .split(/\\s+/)\n .filter(Boolean)\n .map((cls) => `${breakpoint}:${cls}`)\n .join(\" \");\n parts.push(prefixed);\n }\n return parts.join(\" \");\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,IACd,aACA,mBACQ;AAGR,KAAI,CAAC,kBAAmB,QAAO;CAE/B,MAAM,QAAQ,CAAC,YAAY;AAC3B,MAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,kBAAkB,EAAE;EACrE,MAAM,WAAW,QACd,MAAM,MAAM,CACZ,OAAO,QAAQ,CACf,KAAK,QAAQ,GAAG,WAAW,GAAG,MAAM,CACpC,KAAK,IAAI;AACZ,QAAM,KAAK,SAAS;;AAEtB,QAAO,MAAM,KAAK,IAAI"}
|
package/dist/core/options.d.ts
CHANGED
|
@@ -31,4 +31,5 @@ interface Options {
|
|
|
31
31
|
type OptionsResolved = Required<Options>;
|
|
32
32
|
declare function resolveOptions(options?: Options): OptionsResolved;
|
|
33
33
|
//#endregion
|
|
34
|
-
export { Options, OptionsResolved, resolveOptions };
|
|
34
|
+
export { Options, OptionsResolved, resolveOptions };
|
|
35
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","names":[],"sources":["../../src/core/options.ts"],"mappings":";;;UAEiB,OAAA;;AAAjB;;;EAKE,OAAA,GAAU,aAAA;EAMA;;;;EAAV,OAAA,GAAU,aAAA;EANA;;;;EAYV,SAAA;EAMc;;;;EAAd,WAAA,GAAc,MAAA;EASW;;;;EAHzB,cAAA;AAAA;AAAA,KAGU,eAAA,GAAkB,QAAA,CAAS,OAAA;AAAA,iBAEvB,cAAA,CAAe,OAAA,GAAS,OAAA,GAAe,eAAA"}
|
package/dist/core/options.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","names":[],"sources":["../../src/core/options.ts"],"sourcesContent":["import type { FilterPattern } from 'unplugin'\n\nexport interface Options {\n /**\n * Files to include in processing\n * @default [/\\.[jt]sx?$/]\n */\n include?: FilterPattern;\n\n /**\n * Files to exclude from processing\n * @default [/node_modules/]\n */\n exclude?: FilterPattern;\n\n /**\n * Enable source map generation\n * @default true\n */\n sourcemap?: boolean;\n\n /**\n * Custom Tailwind breakpoints\n * @default { sm: '640px', md: '768px', lg: '1024px', xl: '1280px', '2xl': '1536px' }\n */\n breakpoints?: Record<string, string>;\n\n /**\n * Enable additional variant support (hover, focus, dark, etc.)\n * @default false\n */\n enableVariants?: boolean;\n}\n\nexport type OptionsResolved = Required<Options>;\n\nexport function resolveOptions(options: Options = {}): OptionsResolved {\n return {\n include: options.include ?? [/\\.[jt]sx?$/],\n exclude: options.exclude ?? [/node_modules/],\n sourcemap: options.sourcemap ?? true,\n breakpoints: options.breakpoints ?? {\n sm: \"640px\",\n md: \"768px\",\n lg: \"1024px\",\n xl: \"1280px\",\n \"2xl\": \"1536px\",\n },\n enableVariants: options.enableVariants ?? false,\n };\n}\n"],"mappings":";AAoCA,SAAgB,eAAe,UAAmB,EAAE,EAAmB;AACrE,QAAO;EACL,SAAS,QAAQ,WAAW,CAAC,aAAa;EAC1C,SAAS,QAAQ,WAAW,CAAC,eAAe;EAC5C,WAAW,QAAQ,aAAa;EAChC,aAAa,QAAQ,eAAe;GAClC,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,OAAO;GACR;EACD,gBAAgB,QAAQ,kBAAkB;EAC3C"}
|
package/dist/core/parser.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","names":[],"sources":["../../src/core/parser.ts"],"mappings":";UAGiB,iBAAA;EACf,WAAA;EACA,iBAAA,EAAmB,MAAA;EACnB,KAAA;EACA,GAAA;AAAA;AAAA,iBAGc,YAAA,CAAa,IAAA,WAAe,iBAAA"}
|
package/dist/core/parser.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","names":[],"sources":["../../src/core/parser.ts"],"sourcesContent":["import { parse } from \"@babel/parser\";\nimport type * as t from \"@babel/types\";\n\nexport interface ClsCallExpression {\n baseClasses: string;\n responsiveClasses: Record<string, string>;\n start: number;\n end: number;\n}\n\nexport function findClsCalls(code: string): ClsCallExpression[] {\n let ast: t.File;\n try {\n ast = parse(code, {\n sourceType: \"module\",\n plugins: [\"jsx\", \"typescript\"],\n });\n } catch {\n return [];\n }\n\n const clsCalls: ClsCallExpression[] = [];\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function traverse(node: any) {\n if (!node || typeof node !== \"object\") return;\n\n // Check if it's a CallExpression\n if (node.type === \"CallExpression\") {\n const callee = node.callee;\n\n // Check if it's tw() or tw.something()\n const isTwCall =\n (callee.type === \"Identifier\" && callee.name === \"tw\") ||\n (callee.type === \"MemberExpression\" &&\n callee.object.type === \"Identifier\" &&\n callee.object.name === \"tw\");\n\n if (isTwCall) {\n const args = node.arguments;\n\n // Must have at least 1 argument (base classes)\n if (args.length === 0) return;\n\n // First argument: base classes (string literal)\n const baseArg = args[0];\n if (baseArg.type !== \"StringLiteral\") return;\n\n const baseClasses = baseArg.value;\n\n // Second argument: responsive classes (object expression)\n const responsiveClasses: Record<string, string> = {};\n\n if (args.length > 1) {\n const responsiveArg = args[1];\n\n if (responsiveArg.type === \"ObjectExpression\") {\n for (const prop of responsiveArg.properties) {\n if (\n prop.type === \"ObjectProperty\" &&\n prop.value.type === \"StringLiteral\"\n ) {\n let key: string | undefined;\n if (prop.key.type === \"Identifier\") {\n key = prop.key.name;\n } else if (prop.key.type === \"StringLiteral\") {\n key = prop.key.value;\n }\n if (key) {\n responsiveClasses[key] = prop.value.value;\n }\n }\n }\n }\n }\n\n clsCalls.push({\n baseClasses,\n responsiveClasses,\n start: node.start!,\n end: node.end!,\n });\n }\n }\n\n // Traverse all properties\n for (const key in node) {\n if (key === \"loc\" || key === \"range\" || key === \"tokens\") continue;\n const value = node[key];\n if (Array.isArray(value)) {\n for (const item of value) {\n traverse(item);\n }\n } else if (value && typeof value === \"object\") {\n traverse(value);\n }\n }\n }\n\n traverse(ast);\n return clsCalls;\n}\n"],"mappings":";;;AAUA,SAAgB,aAAa,MAAmC;CAC9D,IAAI;AACJ,KAAI;AACF,QAAM,MAAM,MAAM;GAChB,YAAY;GACZ,SAAS,CAAC,OAAO,aAAa;GAC/B,CAAC;SACI;AACN,SAAO,EAAE;;CAGX,MAAM,WAAgC,EAAE;CAGxC,SAAS,SAAS,MAAW;AAC3B,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AAGvC,MAAI,KAAK,SAAS,kBAAkB;GAClC,MAAM,SAAS,KAAK;AASpB,OALG,OAAO,SAAS,gBAAgB,OAAO,SAAS,QAChD,OAAO,SAAS,sBACf,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,MAEb;IACZ,MAAM,OAAO,KAAK;AAGlB,QAAI,KAAK,WAAW,EAAG;IAGvB,MAAM,UAAU,KAAK;AACrB,QAAI,QAAQ,SAAS,gBAAiB;IAEtC,MAAM,cAAc,QAAQ;IAG5B,MAAM,oBAA4C,EAAE;AAEpD,QAAI,KAAK,SAAS,GAAG;KACnB,MAAM,gBAAgB,KAAK;AAE3B,SAAI,cAAc,SAAS,oBACzB;WAAK,MAAM,QAAQ,cAAc,WAC/B,KACE,KAAK,SAAS,oBACd,KAAK,MAAM,SAAS,iBACpB;OACA,IAAI;AACJ,WAAI,KAAK,IAAI,SAAS,aACpB,OAAM,KAAK,IAAI;gBACN,KAAK,IAAI,SAAS,gBAC3B,OAAM,KAAK,IAAI;AAEjB,WAAI,IACF,mBAAkB,OAAO,KAAK,MAAM;;;;AAO9C,aAAS,KAAK;KACZ;KACA;KACA,OAAO,KAAK;KACZ,KAAK,KAAK;KACX,CAAC;;;AAKN,OAAK,MAAM,OAAO,MAAM;AACtB,OAAI,QAAQ,SAAS,QAAQ,WAAW,QAAQ,SAAU;GAC1D,MAAM,QAAQ,KAAK;AACnB,OAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,QAAQ,MACjB,UAAS,KAAK;YAEP,SAAS,OAAO,UAAU,SACnC,UAAS,MAAM;;;AAKrB,UAAS,IAAI;AACb,QAAO"}
|
package/dist/core/transform.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ interface TransformResult {
|
|
|
7
7
|
}
|
|
8
8
|
declare function transformClsCalls(code: string, _id: string, options: OptionsResolved): TransformResult | null;
|
|
9
9
|
//#endregion
|
|
10
|
-
export { TransformResult, transformClsCalls };
|
|
10
|
+
export { TransformResult, transformClsCalls };
|
|
11
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","names":[],"sources":["../../src/core/transform.ts"],"mappings":";;;UAIiB,eAAA;EACf,IAAA;EAEA,GAAA;AAAA;AAAA,iBAGc,iBAAA,CACd,IAAA,UACA,GAAA,UACA,OAAA,EAAS,eAAA,GACR,eAAA"}
|
package/dist/core/transform.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","names":[],"sources":["../../src/core/transform.ts"],"sourcesContent":["import MagicString from \"magic-string\";\nimport type { OptionsResolved } from \"./options\";\nimport { findClsCalls, type ClsCallExpression } from \"./parser\";\n\nexport interface TransformResult {\n code: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n map: any;\n}\n\nexport function transformClsCalls(\n code: string,\n _id: string,\n options: OptionsResolved,\n): TransformResult | null {\n // Find all tw() calls\n const twCalls = findClsCalls(code);\n\n if (twCalls.length === 0) {\n return null;\n }\n\n const s = new MagicString(code);\n\n // Process each tw() call\n for (const call of twCalls) {\n const transformedString = generateClassString(call, options);\n\n // Replace the entire tw() call with a static string\n s.overwrite(call.start, call.end, `\"${transformedString}\"`);\n }\n\n return {\n code: s.toString(),\n map: options.sourcemap ? s.generateMap({ hires: true }) : null,\n };\n}\n\nfunction generateClassString(\n call: ClsCallExpression,\n options: OptionsResolved,\n): string {\n const { baseClasses, responsiveClasses } = call;\n const parts: string[] = [baseClasses];\n\n // Process responsive classes\n for (const [breakpoint, classes] of Object.entries(responsiveClasses)) {\n // Validate breakpoint\n if (!options.breakpoints[breakpoint] && !options.enableVariants) {\n console.warn(`Unknown breakpoint: ${breakpoint}`);\n continue;\n }\n\n // Split classes and prefix each one\n const prefixedClasses = classes\n .split(/\\s+/)\n .filter(Boolean)\n .map((cls) => `${breakpoint}:${cls}`)\n .join(\" \");\n\n parts.push(prefixedClasses);\n }\n\n return parts.filter(Boolean).join(\" \");\n}\n"],"mappings":";;;;AAUA,SAAgB,kBACd,MACA,KACA,SACwB;CAExB,MAAM,UAAU,aAAa,KAAK;AAElC,KAAI,QAAQ,WAAW,EACrB,QAAO;CAGT,MAAM,IAAI,IAAI,YAAY,KAAK;AAG/B,MAAK,MAAM,QAAQ,SAAS;EAC1B,MAAM,oBAAoB,oBAAoB,MAAM,QAAQ;AAG5D,IAAE,UAAU,KAAK,OAAO,KAAK,KAAK,IAAI,kBAAkB,GAAG;;AAG7D,QAAO;EACL,MAAM,EAAE,UAAU;EAClB,KAAK,QAAQ,YAAY,EAAE,YAAY,EAAE,OAAO,MAAM,CAAC,GAAG;EAC3D;;AAGH,SAAS,oBACP,MACA,SACQ;CACR,MAAM,EAAE,aAAa,sBAAsB;CAC3C,MAAM,QAAkB,CAAC,YAAY;AAGrC,MAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,kBAAkB,EAAE;AAErE,MAAI,CAAC,QAAQ,YAAY,eAAe,CAAC,QAAQ,gBAAgB;AAC/D,WAAQ,KAAK,uBAAuB,aAAa;AACjD;;EAIF,MAAM,kBAAkB,QACrB,MAAM,MAAM,CACZ,OAAO,QAAQ,CACf,KAAK,QAAQ,GAAG,WAAW,GAAG,MAAM,CACpC,KAAK,IAAI;AAEZ,QAAM,KAAK,gBAAgB;;AAG7B,QAAO,MAAM,OAAO,QAAQ,CAAC,KAAK,IAAI"}
|
|
@@ -4,4 +4,5 @@ import { UnpluginInstance } from "unplugin";
|
|
|
4
4
|
//#region src/unplugin-factory.d.ts
|
|
5
5
|
declare const unplugin: UnpluginInstance<Options | undefined, false>;
|
|
6
6
|
//#endregion
|
|
7
|
-
export { type Options, unplugin as default };
|
|
7
|
+
export { type Options, unplugin as default };
|
|
8
|
+
//# sourceMappingURL=unplugin-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unplugin-factory.d.ts","names":[],"sources":["../src/unplugin-factory.ts"],"mappings":";;;;cAIM,QAAA,EAAU,gBAAA,CAAiB,OAAA"}
|
package/dist/unplugin-factory.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unplugin-factory.js","names":[],"sources":["../src/unplugin-factory.ts"],"sourcesContent":["import { createUnplugin, type UnpluginInstance } from \"unplugin\";\nimport { resolveOptions, type Options } from \"./core/options\";\nimport { transformClsCalls } from \"./core/transform\";\n\nconst unplugin: UnpluginInstance<Options | undefined, false> = createUnplugin(\n (rawOptions = {}) => {\n const options = resolveOptions(rawOptions);\n\n const name = \"cls-extended\";\n return {\n name,\n\n transform: {\n filter: {\n id: { include: options.include, exclude: options.exclude },\n },\n handler(code, id) {\n // Only process files that might contain tw()\n if (!code.includes(\"tw(\")) {\n return null;\n }\n\n // Perform transformation\n return transformClsCalls(code, id, options);\n },\n },\n };\n },\n);\n\nexport default unplugin;\nexport type { Options } from \"./core/options\";\n"],"mappings":";;;;;AAIA,MAAM,WAAyD,gBAC5D,aAAa,EAAE,KAAK;CACnB,MAAM,UAAU,eAAe,WAAW;AAG1C,QAAO;EACL,MAFW;EAIX,WAAW;GACT,QAAQ,EACN,IAAI;IAAE,SAAS,QAAQ;IAAS,SAAS,QAAQ;IAAS,EAC3D;GACD,QAAQ,MAAM,IAAI;AAEhB,QAAI,CAAC,KAAK,SAAS,MAAM,CACvB,QAAO;AAIT,WAAO,kBAAkB,MAAM,IAAI,QAAQ;;GAE9C;EACF;EAEJ"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cls-extended",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.3",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
7
7
|
"./adapters/vite": "./dist/adapters/vite.js",
|
|
@@ -51,23 +51,25 @@
|
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@babel/types": "^7.29.0",
|
|
54
|
-
"@eslint/js": "
|
|
54
|
+
"@eslint/js": "catalog:",
|
|
55
55
|
"@release-it/conventional-changelog": "^8.0.2",
|
|
56
|
+
"@repo/eslint-config": "workspace:*",
|
|
57
|
+
"@repo/typescript-config": "workspace:*",
|
|
56
58
|
"@sxzz/eslint-config": "^7.6.0",
|
|
57
59
|
"@sxzz/prettier-config": "^2.3.1",
|
|
58
60
|
"@sxzz/test-utils": "^0.5.15",
|
|
59
|
-
"@types/node": "
|
|
61
|
+
"@types/node": "catalog:",
|
|
60
62
|
"auto-changelog": "^2.5.0",
|
|
61
63
|
"bumpp": "^10.4.0",
|
|
62
|
-
"eslint": "
|
|
63
|
-
"globals": "
|
|
64
|
+
"eslint": "catalog:",
|
|
65
|
+
"globals": "catalog:",
|
|
64
66
|
"jiti": "^2.6.1",
|
|
65
67
|
"prettier": "^3.8.1",
|
|
66
68
|
"release-it": "^17.10.0",
|
|
67
69
|
"tsdown": "^0.20.1",
|
|
68
70
|
"tsdown-preset-sxzz": "^0.3.1",
|
|
69
|
-
"typescript": "
|
|
70
|
-
"typescript-eslint": "
|
|
71
|
+
"typescript": "catalog:",
|
|
72
|
+
"typescript-eslint": "catalog:",
|
|
71
73
|
"vitest": "^4.0.18"
|
|
72
74
|
},
|
|
73
75
|
"keywords": [
|