jasmincss 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +524 -0
  2. package/bin/jasmin.js +45 -0
  3. package/dist/index.d.ts +62 -0
  4. package/dist/index.js +14568 -0
  5. package/dist/index.mjs +14524 -0
  6. package/dist/jasmin.css +63308 -0
  7. package/dist/jasmin.min.css +1 -0
  8. package/dist/plugins/nextjs.js +14777 -0
  9. package/dist/plugins/nextjs.mjs +14747 -0
  10. package/dist/plugins/vite.js +14889 -0
  11. package/dist/plugins/vite.mjs +14860 -0
  12. package/package.json +101 -0
  13. package/src/cli/add.js +83 -0
  14. package/src/cli/init.js +210 -0
  15. package/src/cli/run.js +142 -0
  16. package/src/components/accordion.js +309 -0
  17. package/src/components/alerts.js +357 -0
  18. package/src/components/avatars.js +331 -0
  19. package/src/components/badges.js +353 -0
  20. package/src/components/buttons.js +412 -0
  21. package/src/components/cards.js +342 -0
  22. package/src/components/carousel.js +495 -0
  23. package/src/components/chips.js +440 -0
  24. package/src/components/command-palette.js +434 -0
  25. package/src/components/datepicker.js +517 -0
  26. package/src/components/dropdown.js +411 -0
  27. package/src/components/forms.js +516 -0
  28. package/src/components/index.js +81 -0
  29. package/src/components/modals.js +349 -0
  30. package/src/components/navigation.js +463 -0
  31. package/src/components/offcanvas.js +390 -0
  32. package/src/components/popover.js +427 -0
  33. package/src/components/progress.js +396 -0
  34. package/src/components/rating.js +394 -0
  35. package/src/components/skeleton.js +408 -0
  36. package/src/components/spinner.js +453 -0
  37. package/src/components/stepper.js +389 -0
  38. package/src/components/tables.js +304 -0
  39. package/src/components/timeline.js +452 -0
  40. package/src/components/timepicker.js +529 -0
  41. package/src/components/tooltips.js +345 -0
  42. package/src/components/upload.js +490 -0
  43. package/src/config/defaults.js +263 -0
  44. package/src/config/loader.js +109 -0
  45. package/src/core/base.js +241 -0
  46. package/src/core/compiler.js +135 -0
  47. package/src/core/utilities/accessibility.js +290 -0
  48. package/src/core/utilities/animations.js +205 -0
  49. package/src/core/utilities/background.js +109 -0
  50. package/src/core/utilities/colors.js +234 -0
  51. package/src/core/utilities/columns.js +161 -0
  52. package/src/core/utilities/effects.js +261 -0
  53. package/src/core/utilities/filters.js +135 -0
  54. package/src/core/utilities/icons.js +806 -0
  55. package/src/core/utilities/index.js +239 -0
  56. package/src/core/utilities/layout.js +321 -0
  57. package/src/core/utilities/scroll.js +205 -0
  58. package/src/core/utilities/spacing.js +120 -0
  59. package/src/core/utilities/svg.js +191 -0
  60. package/src/core/utilities/transforms.js +116 -0
  61. package/src/core/utilities/typography.js +188 -0
  62. package/src/index.js +7 -0
  63. package/src/js/components/accordion.js +154 -0
  64. package/src/js/components/alert.js +198 -0
  65. package/src/js/components/carousel.js +226 -0
  66. package/src/js/components/dropdown.js +166 -0
  67. package/src/js/components/modal.js +169 -0
  68. package/src/js/components/offcanvas.js +175 -0
  69. package/src/js/components/popover.js +221 -0
  70. package/src/js/components/tabs.js +163 -0
  71. package/src/js/components/tooltip.js +200 -0
  72. package/src/js/index.js +79 -0
  73. package/src/js/types/config.d.ts +228 -0
  74. package/src/js/types/index.d.ts +439 -0
  75. package/src/plugins/nextjs.js +100 -0
  76. package/src/plugins/vite.js +133 -0
@@ -0,0 +1,516 @@
1
+ export function generateFormStyles(config) {
2
+ return `/* Form Controls */
3
+ .form-control {
4
+ display: block;
5
+ width: 100%;
6
+ padding: 0.625rem 0.875rem;
7
+ font-size: 0.875rem;
8
+ line-height: 1.5;
9
+ color: var(--j-text);
10
+ background-color: var(--j-bg);
11
+ border: 1px solid var(--j-border);
12
+ border-radius: var(--j-radius-default, 0.5rem);
13
+ transition: border-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
14
+ appearance: none;
15
+ }
16
+
17
+ .form-control::placeholder {
18
+ color: var(--j-text-muted);
19
+ }
20
+
21
+ .form-control:focus {
22
+ border-color: var(--j-primary);
23
+ outline: none;
24
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-primary) 20%, transparent);
25
+ }
26
+
27
+ .form-control:disabled {
28
+ background-color: var(--j-bg-muted);
29
+ opacity: 0.6;
30
+ cursor: not-allowed;
31
+ }
32
+
33
+ .form-control[readonly] {
34
+ background-color: var(--j-bg-subtle);
35
+ }
36
+
37
+ /* Form Control Sizes */
38
+ .form-control-sm {
39
+ padding: 0.375rem 0.75rem;
40
+ font-size: 0.8125rem;
41
+ }
42
+
43
+ .form-control-lg {
44
+ padding: 0.875rem 1rem;
45
+ font-size: 1rem;
46
+ }
47
+
48
+ /* Textarea */
49
+ textarea.form-control {
50
+ min-height: 80px;
51
+ resize: vertical;
52
+ }
53
+
54
+ /* Select - Same height as text inputs */
55
+ select.form-control {
56
+ height: calc(2.5rem + 2px); /* Match text input height exactly */
57
+ padding-right: 2.5rem;
58
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
59
+ background-position: right 0.5rem center;
60
+ background-repeat: no-repeat;
61
+ background-size: 1.5em 1.5em;
62
+ }
63
+
64
+ select.form-control-sm {
65
+ height: calc(2rem + 2px);
66
+ }
67
+
68
+ select.form-control-lg {
69
+ height: calc(3rem + 2px);
70
+ }
71
+
72
+ /* File Input */
73
+ input[type="file"].form-control {
74
+ padding: 0.375rem;
75
+ }
76
+
77
+ input[type="file"].form-control::file-selector-button {
78
+ padding: 0.375rem 0.75rem;
79
+ margin-right: 0.75rem;
80
+ background-color: var(--j-bg-subtle);
81
+ border: 1px solid var(--j-border);
82
+ border-radius: var(--j-radius-sm, 0.25rem);
83
+ cursor: pointer;
84
+ transition: background-color 150ms ease-in-out;
85
+ }
86
+
87
+ input[type="file"].form-control::file-selector-button:hover {
88
+ background-color: var(--j-bg-muted);
89
+ }
90
+
91
+ /* Color Input */
92
+ input[type="color"].form-control {
93
+ padding: 0.25rem;
94
+ height: 2.5rem;
95
+ cursor: pointer;
96
+ }
97
+
98
+ /* Range Input */
99
+ input[type="range"].form-control {
100
+ padding: 0;
101
+ border: none;
102
+ background: transparent;
103
+ height: 1.5rem;
104
+ }
105
+
106
+ input[type="range"].form-control::-webkit-slider-track {
107
+ width: 100%;
108
+ height: 0.5rem;
109
+ background: var(--j-bg-muted);
110
+ border-radius: var(--j-radius-full, 9999px);
111
+ }
112
+
113
+ input[type="range"].form-control::-webkit-slider-thumb {
114
+ -webkit-appearance: none;
115
+ width: 1.25rem;
116
+ height: 1.25rem;
117
+ margin-top: -0.375rem;
118
+ background: var(--j-primary);
119
+ border-radius: 50%;
120
+ cursor: pointer;
121
+ transition: transform 100ms ease-in-out;
122
+ }
123
+
124
+ input[type="range"].form-control::-webkit-slider-thumb:hover {
125
+ transform: scale(1.1);
126
+ }
127
+
128
+ /* Validation States */
129
+ .form-control.is-valid {
130
+ border-color: var(--j-success);
131
+ }
132
+
133
+ .form-control.is-valid:focus {
134
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-success) 20%, transparent);
135
+ }
136
+
137
+ .form-control.is-invalid {
138
+ border-color: var(--j-error);
139
+ }
140
+
141
+ .form-control.is-invalid:focus {
142
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-error) 20%, transparent);
143
+ }
144
+
145
+ /* Form Label */
146
+ .form-label {
147
+ display: block;
148
+ margin-bottom: 0.5rem;
149
+ font-size: 0.875rem;
150
+ font-weight: 500;
151
+ color: var(--j-text);
152
+ }
153
+
154
+ .form-label-required::after {
155
+ content: " *";
156
+ color: var(--j-error);
157
+ }
158
+
159
+ /* Form Text (Help Text) */
160
+ .form-text {
161
+ display: block;
162
+ margin-top: 0.375rem;
163
+ font-size: 0.8125rem;
164
+ color: var(--j-text-subtle);
165
+ }
166
+
167
+ .form-text-error {
168
+ color: var(--j-error);
169
+ }
170
+
171
+ .form-text-success {
172
+ color: var(--j-success);
173
+ }
174
+
175
+ /* Form Group */
176
+ .form-group {
177
+ margin-bottom: 1rem;
178
+ }
179
+
180
+ /* Checkbox & Radio */
181
+ .form-check {
182
+ display: flex;
183
+ align-items: center;
184
+ gap: 0.5rem;
185
+ padding-left: 0;
186
+ margin-bottom: 0.5rem;
187
+ }
188
+
189
+ .form-check-input {
190
+ width: 1.125rem;
191
+ height: 1.125rem;
192
+ margin: 0;
193
+ appearance: none;
194
+ background-color: var(--j-bg);
195
+ border: 2px solid var(--j-border);
196
+ cursor: pointer;
197
+ flex-shrink: 0;
198
+ transition: all 150ms ease-in-out;
199
+ }
200
+
201
+ .form-check-input[type="checkbox"] {
202
+ border-radius: var(--j-radius-sm, 0.25rem);
203
+ }
204
+
205
+ .form-check-input[type="radio"] {
206
+ border-radius: 50%;
207
+ }
208
+
209
+ .form-check-input:checked {
210
+ background-color: var(--j-primary);
211
+ border-color: var(--j-primary);
212
+ }
213
+
214
+ .form-check-input[type="checkbox"]:checked {
215
+ background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
216
+ background-repeat: no-repeat;
217
+ background-position: center;
218
+ background-size: 100%;
219
+ }
220
+
221
+ .form-check-input[type="radio"]:checked {
222
+ background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
223
+ background-repeat: no-repeat;
224
+ background-position: center;
225
+ }
226
+
227
+ .form-check-input:focus {
228
+ outline: none;
229
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-primary) 20%, transparent);
230
+ }
231
+
232
+ .form-check-input:disabled {
233
+ opacity: 0.5;
234
+ cursor: not-allowed;
235
+ }
236
+
237
+ .form-check-label {
238
+ font-size: 0.875rem;
239
+ color: var(--j-text);
240
+ cursor: pointer;
241
+ user-select: none;
242
+ }
243
+
244
+ /* Switch/Toggle */
245
+ .form-switch {
246
+ display: flex;
247
+ align-items: center;
248
+ gap: 0.5rem;
249
+ }
250
+
251
+ .form-switch-input {
252
+ width: 2.5rem;
253
+ height: 1.5rem;
254
+ appearance: none;
255
+ background-color: var(--j-bg-muted);
256
+ border-radius: var(--j-radius-full, 9999px);
257
+ cursor: pointer;
258
+ position: relative;
259
+ transition: background-color 200ms ease-in-out;
260
+ }
261
+
262
+ .form-switch-input::before {
263
+ content: "";
264
+ position: absolute;
265
+ top: 0.125rem;
266
+ left: 0.125rem;
267
+ width: 1.25rem;
268
+ height: 1.25rem;
269
+ background-color: white;
270
+ border-radius: 50%;
271
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
272
+ transition: transform 200ms ease-in-out;
273
+ }
274
+
275
+ .form-switch-input:checked {
276
+ background-color: var(--j-primary);
277
+ }
278
+
279
+ .form-switch-input:checked::before {
280
+ transform: translateX(1rem);
281
+ }
282
+
283
+ .form-switch-input:focus {
284
+ outline: none;
285
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-primary) 20%, transparent);
286
+ }
287
+
288
+ .form-switch-input:disabled {
289
+ opacity: 0.5;
290
+ cursor: not-allowed;
291
+ }
292
+
293
+ /* Switch Sizes */
294
+ .form-switch-sm .form-switch-input {
295
+ width: 2rem;
296
+ height: 1.125rem;
297
+ }
298
+
299
+ .form-switch-sm .form-switch-input::before {
300
+ width: 0.875rem;
301
+ height: 0.875rem;
302
+ }
303
+
304
+ .form-switch-sm .form-switch-input:checked::before {
305
+ transform: translateX(0.875rem);
306
+ }
307
+
308
+ .form-switch-lg .form-switch-input {
309
+ width: 3.5rem;
310
+ height: 2rem;
311
+ }
312
+
313
+ .form-switch-lg .form-switch-input::before {
314
+ width: 1.75rem;
315
+ height: 1.75rem;
316
+ }
317
+
318
+ .form-switch-lg .form-switch-input:checked::before {
319
+ transform: translateX(1.5rem);
320
+ }
321
+
322
+ /* Switch Colors */
323
+ .form-switch-secondary .form-switch-input:checked {
324
+ background-color: var(--j-secondary);
325
+ }
326
+
327
+ .form-switch-secondary .form-switch-input:focus {
328
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-secondary) 20%, transparent);
329
+ }
330
+
331
+ .form-switch-success .form-switch-input:checked {
332
+ background-color: var(--j-success);
333
+ }
334
+
335
+ .form-switch-success .form-switch-input:focus {
336
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-success) 20%, transparent);
337
+ }
338
+
339
+ .form-switch-warning .form-switch-input:checked {
340
+ background-color: var(--j-warning);
341
+ }
342
+
343
+ .form-switch-warning .form-switch-input:focus {
344
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-warning) 20%, transparent);
345
+ }
346
+
347
+ .form-switch-error .form-switch-input:checked {
348
+ background-color: var(--j-error);
349
+ }
350
+
351
+ .form-switch-error .form-switch-input:focus {
352
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-error) 20%, transparent);
353
+ }
354
+
355
+ .form-switch-info .form-switch-input:checked {
356
+ background-color: var(--j-info);
357
+ }
358
+
359
+ .form-switch-info .form-switch-input:focus {
360
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--j-info) 20%, transparent);
361
+ }
362
+
363
+ /* Switch with Label Inside */
364
+ .form-switch-labeled .form-switch-input {
365
+ width: 4rem;
366
+ }
367
+
368
+ .form-switch-labeled .form-switch-input::after {
369
+ content: "OFF";
370
+ position: absolute;
371
+ right: 0.5rem;
372
+ top: 50%;
373
+ transform: translateY(-50%);
374
+ font-size: 0.625rem;
375
+ font-weight: 600;
376
+ color: var(--j-text-muted);
377
+ }
378
+
379
+ .form-switch-labeled .form-switch-input:checked::after {
380
+ content: "ON";
381
+ left: 0.5rem;
382
+ right: auto;
383
+ color: white;
384
+ }
385
+
386
+ /* Switch with Icons */
387
+ .form-switch-icon .form-switch-input::before {
388
+ display: flex;
389
+ align-items: center;
390
+ justify-content: center;
391
+ font-size: 0.75rem;
392
+ }
393
+
394
+ /* Square Switch */
395
+ .form-switch-square .form-switch-input {
396
+ border-radius: var(--j-radius-default, 0.375rem);
397
+ }
398
+
399
+ .form-switch-square .form-switch-input::before {
400
+ border-radius: var(--j-radius-sm, 0.25rem);
401
+ }
402
+
403
+ /* Glow Switch */
404
+ .form-switch-glow .form-switch-input:checked {
405
+ box-shadow: 0 0 15px var(--j-primary);
406
+ }
407
+
408
+ /* Input Group */
409
+ .input-group {
410
+ display: flex;
411
+ width: 100%;
412
+ }
413
+
414
+ .input-group > .form-control {
415
+ flex: 1;
416
+ min-width: 0;
417
+ }
418
+
419
+ .input-group > .form-control:not(:first-child) {
420
+ border-top-left-radius: 0;
421
+ border-bottom-left-radius: 0;
422
+ }
423
+
424
+ .input-group > .form-control:not(:last-child) {
425
+ border-top-right-radius: 0;
426
+ border-bottom-right-radius: 0;
427
+ }
428
+
429
+ .input-group-text {
430
+ display: flex;
431
+ align-items: center;
432
+ padding: 0.625rem 0.875rem;
433
+ font-size: 0.875rem;
434
+ color: var(--j-text-subtle);
435
+ background-color: var(--j-bg-subtle);
436
+ border: 1px solid var(--j-border);
437
+ white-space: nowrap;
438
+ }
439
+
440
+ .input-group-text:first-child {
441
+ border-right: none;
442
+ border-radius: var(--j-radius-default, 0.5rem) 0 0 var(--j-radius-default, 0.5rem);
443
+ }
444
+
445
+ .input-group-text:last-child {
446
+ border-left: none;
447
+ border-radius: 0 var(--j-radius-default, 0.5rem) var(--j-radius-default, 0.5rem) 0;
448
+ }
449
+
450
+ .input-group > .btn:first-child {
451
+ border-top-right-radius: 0;
452
+ border-bottom-right-radius: 0;
453
+ }
454
+
455
+ .input-group > .btn:last-child {
456
+ border-top-left-radius: 0;
457
+ border-bottom-left-radius: 0;
458
+ }
459
+
460
+ /* Floating Label */
461
+ .form-floating {
462
+ position: relative;
463
+ }
464
+
465
+ .form-floating > .form-control {
466
+ padding-top: 1.625rem;
467
+ padding-bottom: 0.625rem;
468
+ }
469
+
470
+ .form-floating > .form-label {
471
+ position: absolute;
472
+ top: 0;
473
+ left: 0;
474
+ padding: 1rem 0.875rem;
475
+ pointer-events: none;
476
+ transform-origin: 0 0;
477
+ transition: opacity 150ms ease-in-out, transform 150ms ease-in-out;
478
+ color: var(--j-text-muted);
479
+ margin-bottom: 0;
480
+ }
481
+
482
+ .form-floating > .form-control:focus ~ .form-label,
483
+ .form-floating > .form-control:not(:placeholder-shown) ~ .form-label {
484
+ transform: scale(0.85) translateY(-0.5rem);
485
+ color: var(--j-primary);
486
+ }
487
+
488
+ /* Form Row/Grid */
489
+ .form-row {
490
+ display: grid;
491
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
492
+ gap: 1rem;
493
+ }
494
+
495
+ /* Fieldset */
496
+ fieldset {
497
+ border: 1px solid var(--j-border);
498
+ border-radius: var(--j-radius-default, 0.5rem);
499
+ padding: 1.5rem;
500
+ margin-bottom: 1.5rem;
501
+ }
502
+
503
+ legend {
504
+ font-size: 0.875rem;
505
+ font-weight: 600;
506
+ padding: 0 0.5rem;
507
+ color: var(--j-text);
508
+ }
509
+
510
+ /* Form Futuristic Glow */
511
+ .form-control-glow:focus {
512
+ border-color: var(--j-primary);
513
+ box-shadow: 0 0 15px color-mix(in srgb, var(--j-primary) 40%, transparent);
514
+ }
515
+ `;
516
+ }
@@ -0,0 +1,81 @@
1
+ import { generateButtonStyles } from './buttons.js';
2
+ import { generateCardStyles } from './cards.js';
3
+ import { generateFormStyles } from './forms.js';
4
+ import { generateNavigationStyles } from './navigation.js';
5
+ import { generateAlertStyles } from './alerts.js';
6
+ import { generateBadgeStyles } from './badges.js';
7
+ import { generateModalStyles } from './modals.js';
8
+ import { generateTableStyles } from './tables.js';
9
+ import { generateAvatarStyles } from './avatars.js';
10
+ import { generateTooltipStyles } from './tooltips.js';
11
+ import { generateProgressStyles } from './progress.js';
12
+ import { generateSkeletonStyles } from './skeleton.js';
13
+ import { generateDropdownStyles } from './dropdown.js';
14
+ import { generateAccordionStyles } from './accordion.js';
15
+ import { generateChipStyles } from './chips.js';
16
+ import { generateOffcanvasStyles } from './offcanvas.js';
17
+ import { generateCarouselStyles } from './carousel.js';
18
+ import { generateStepperStyles } from './stepper.js';
19
+ import { generateTimelineStyles } from './timeline.js';
20
+ import { generateRatingStyles } from './rating.js';
21
+ import { generateUploadStyles } from './upload.js';
22
+ import { generateSpinnerStyles } from './spinner.js';
23
+ import { generatePopoverStyles } from './popover.js';
24
+ import { generateCommandPaletteStyles } from './command-palette.js';
25
+ import { generateDatepickerStyles } from './datepicker.js';
26
+ import { generateTimepickerStyles } from './timepicker.js';
27
+
28
+ const componentGenerators = {
29
+ buttons: generateButtonStyles,
30
+ cards: generateCardStyles,
31
+ forms: generateFormStyles,
32
+ navigation: generateNavigationStyles,
33
+ alerts: generateAlertStyles,
34
+ badges: generateBadgeStyles,
35
+ modals: generateModalStyles,
36
+ tables: generateTableStyles,
37
+ avatars: generateAvatarStyles,
38
+ tooltips: generateTooltipStyles,
39
+ progress: generateProgressStyles,
40
+ skeleton: generateSkeletonStyles,
41
+ dropdown: generateDropdownStyles,
42
+ accordion: generateAccordionStyles,
43
+ chips: generateChipStyles,
44
+ offcanvas: generateOffcanvasStyles,
45
+ carousel: generateCarouselStyles,
46
+ stepper: generateStepperStyles,
47
+ timeline: generateTimelineStyles,
48
+ rating: generateRatingStyles,
49
+ upload: generateUploadStyles,
50
+ spinner: generateSpinnerStyles,
51
+ popover: generatePopoverStyles,
52
+ 'command-palette': generateCommandPaletteStyles,
53
+ datepicker: generateDatepickerStyles,
54
+ timepicker: generateTimepickerStyles
55
+ };
56
+
57
+ export const components = Object.keys(componentGenerators);
58
+
59
+ export function generateComponents(config, options = {}) {
60
+ const { selected = components, usedClasses, includeAll = true } = options;
61
+
62
+ const parts = [];
63
+ let totalCount = 0;
64
+
65
+ parts.push('/* ==================== COMPONENTS ==================== */');
66
+
67
+ for (const componentName of selected) {
68
+ const generator = componentGenerators[componentName];
69
+ if (!generator) continue;
70
+
71
+ const css = generator(config);
72
+ parts.push(`\n/* ${componentName} component */`);
73
+ parts.push(css);
74
+ totalCount++;
75
+ }
76
+
77
+ return {
78
+ css: parts.join('\n'),
79
+ count: totalCount
80
+ };
81
+ }