@webmate-studio/builder 0.2.63 → 0.2.65

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webmate-studio/builder",
3
- "version": "0.2.63",
3
+ "version": "0.2.65",
4
4
  "type": "module",
5
5
  "description": "Webmate Studio Component Builder",
6
6
  "keywords": [
@@ -0,0 +1,1166 @@
1
+ /**
2
+ * Default Design Tokens für Website-Design
3
+ * Tailwind v4 kompatibel - verwendet Base-Values wo möglich
4
+ * Diese Tokens werden verwendet wenn keine custom Tokens in der DB existieren
5
+ */
6
+
7
+ export const defaultDesignTokens = {
8
+ colors: {
9
+ // Primary Colors
10
+ primary: '#0f172a',
11
+ primaryDark: '#020617',
12
+ primaryLight: '#334155',
13
+
14
+ // Secondary Colors
15
+ secondary: '#6366f1',
16
+ secondaryDark: '#4f46e5',
17
+ secondaryLight: '#818cf8',
18
+
19
+ // Neutral Colors
20
+ white: '#ffffff',
21
+ black: '#000000',
22
+
23
+ // Semantic Colors
24
+ success: '#10b981',
25
+ successDark: '#059669',
26
+ warning: '#f59e0b',
27
+ warningDark: '#d97706',
28
+ error: '#ef4444',
29
+ errorDark: '#dc2626',
30
+ info: '#3b82f6',
31
+ infoDark: '#2563eb',
32
+
33
+ // Background Colors (Semantic)
34
+ bgBase: '#ffffff',
35
+ bgElevated: '#f9fafb',
36
+ bgLifted: '#ffffff',
37
+ bgAccentBase: '#8b5cf6',
38
+ bgAccentElevated: '#a78bfa',
39
+ bgAccentLifted: '#ddd6fe',
40
+
41
+ // Text Colors (Semantic)
42
+ textBase: '#111827',
43
+ textSubtle: '#374151',
44
+ textMuted: '#6b7280',
45
+ textAccentBase: '#7c3aed',
46
+ textAccentSubtle: '#8b5cf6',
47
+ textAccentMuted: '#a78bfa',
48
+
49
+ // Border Colors (Semantic)
50
+ borderBase: '#d1d5db', // slate-300 - Standard Border
51
+ borderSubtle: '#e5e7eb', // slate-200 - Dezenter Border
52
+ borderMuted: '#f3f4f6' // slate-100 - Sehr dezenter Border
53
+ },
54
+
55
+ typography: {
56
+ fontFamily: {
57
+ heading: 'Inter, system-ui, -apple-system, sans-serif',
58
+ body: 'Inter, system-ui, -apple-system, sans-serif',
59
+ mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
60
+ accent: 'Inter, system-ui, -apple-system, sans-serif'
61
+ },
62
+ // Font References (IDs from Font table, null = use fontFamily string)
63
+ fontHeadingId: null,
64
+ fontBodyId: null,
65
+ fontMonoId: null,
66
+ fontAccentId: null,
67
+ // Base font size - Tailwind berechnet Skala automatisch
68
+ fontSizeBase: '1rem', // 16px base
69
+ // Base line height
70
+ lineHeightBase: '1.5',
71
+ // Base letter spacing
72
+ letterSpacingBase: '0em'
73
+ },
74
+
75
+ // Text Styles - Predefined typography combinations
76
+ textStyles: {
77
+ display: {
78
+ fontFamily: 'heading',
79
+ fontSize: {
80
+ base: '2.5rem', // 40px - Mobile
81
+ md: '3.5rem', // 56px - Tablet
82
+ lg: '4.5rem' // 72px - Desktop
83
+ },
84
+ fontWeight: 800,
85
+ lineHeight: '1.1',
86
+ letterSpacing: '-0.02em',
87
+ textTransform: 'none',
88
+ textColor: 'textBase'
89
+ },
90
+ heading1: {
91
+ fontFamily: 'heading',
92
+ fontSize: {
93
+ base: '2rem', // 32px - Mobile
94
+ md: '2.5rem', // 40px - Tablet
95
+ lg: '3rem' // 48px - Desktop
96
+ },
97
+ fontWeight: 700,
98
+ lineHeight: '1.2',
99
+ letterSpacing: '-0.015em',
100
+ textTransform: 'none',
101
+ textColor: 'textBase'
102
+ },
103
+ heading2: {
104
+ fontFamily: 'heading',
105
+ fontSize: {
106
+ base: '1.5rem', // 24px - Mobile
107
+ md: '1.875rem', // 30px - Tablet
108
+ lg: '2.25rem' // 36px - Desktop
109
+ },
110
+ fontWeight: 600,
111
+ lineHeight: '1.3',
112
+ letterSpacing: '-0.01em',
113
+ textTransform: 'none',
114
+ textColor: 'textBase'
115
+ },
116
+ heading3: {
117
+ fontFamily: 'heading',
118
+ fontSize: {
119
+ base: '1.25rem', // 20px - Mobile
120
+ lg: '1.5rem' // 24px - Desktop
121
+ },
122
+ fontWeight: 600,
123
+ lineHeight: '1.4',
124
+ letterSpacing: '0em',
125
+ textTransform: 'none',
126
+ textColor: 'textBase'
127
+ },
128
+ overlineDisplay: {
129
+ fontFamily: 'body',
130
+ fontSize: '1rem', // 16px
131
+ fontWeight: 600,
132
+ lineHeight: '1.5',
133
+ letterSpacing: '0.1em',
134
+ textTransform: 'uppercase',
135
+ textColor: 'textAccentBase'
136
+ },
137
+ overlineHeading1: {
138
+ fontFamily: 'body',
139
+ fontSize: '0.875rem', // 14px
140
+ fontWeight: 600,
141
+ lineHeight: '1.5',
142
+ letterSpacing: '0.1em',
143
+ textTransform: 'uppercase',
144
+ textColor: 'textAccentBase'
145
+ },
146
+ overlineHeading2: {
147
+ fontFamily: 'body',
148
+ fontSize: '0.75rem', // 12px
149
+ fontWeight: 600,
150
+ lineHeight: '1.5',
151
+ letterSpacing: '0.1em',
152
+ textTransform: 'uppercase',
153
+ textColor: 'textAccentSubtle'
154
+ },
155
+ overlineHeading3: {
156
+ fontFamily: 'body',
157
+ fontSize: '0.75rem', // 12px
158
+ fontWeight: 500,
159
+ lineHeight: '1.5',
160
+ letterSpacing: '0.08em',
161
+ textTransform: 'uppercase',
162
+ textColor: 'textAccentSubtle'
163
+ },
164
+ lead: {
165
+ fontFamily: 'body',
166
+ fontSize: '1.25rem', // 20px
167
+ fontWeight: 400,
168
+ lineHeight: '1.6',
169
+ letterSpacing: '0em',
170
+ textTransform: 'none',
171
+ textColor: 'textSubtle'
172
+ },
173
+ body: {
174
+ fontFamily: 'body',
175
+ fontSize: '1rem', // 16px
176
+ fontWeight: 400,
177
+ lineHeight: '1.6',
178
+ letterSpacing: '0em',
179
+ textTransform: 'none',
180
+ textColor: 'textSubtle'
181
+ },
182
+ bodySmall: {
183
+ fontFamily: 'body',
184
+ fontSize: '0.875rem', // 14px
185
+ fontWeight: 400,
186
+ lineHeight: '1.5',
187
+ letterSpacing: '0em',
188
+ textTransform: 'none',
189
+ textColor: 'textSubtle'
190
+ },
191
+ caption: {
192
+ fontFamily: 'body',
193
+ fontSize: '0.75rem', // 12px
194
+ fontWeight: 400,
195
+ lineHeight: '1.4',
196
+ letterSpacing: '0em',
197
+ textTransform: 'none',
198
+ textColor: 'textMuted'
199
+ },
200
+ label: {
201
+ fontFamily: 'body',
202
+ fontSize: '0.875rem', // 14px
203
+ fontWeight: 500,
204
+ lineHeight: '1.4',
205
+ letterSpacing: '0.01em',
206
+ textTransform: 'none',
207
+ textColor: 'textBase'
208
+ }
209
+ },
210
+
211
+ // Base spacing unit - Tailwind berechnet p-1, p-2, p-4 etc. automatisch
212
+ spacing: '0.25rem', // 4px base unit (Tailwind default)
213
+
214
+ // Base border width
215
+ borderWidth: '1px',
216
+
217
+ // Base border radius
218
+ borderRadius: '0.25rem', // 4px
219
+
220
+ // Container max widths (bleiben als Objekt, da spezifische Breakpoints)
221
+ container: {
222
+ sm: '640px',
223
+ md: '768px',
224
+ lg: '1024px',
225
+ xl: '1280px',
226
+ '2xl': '1536px'
227
+ },
228
+
229
+ // Breakpoints (bleiben als Objekt, da spezifische Werte)
230
+ breakpoints: {
231
+ sm: '640px',
232
+ md: '768px',
233
+ lg: '1024px',
234
+ xl: '1280px',
235
+ '2xl': '1536px'
236
+ },
237
+
238
+ // Buttons - Shared sizes and individual variants
239
+ buttons: {
240
+ sizes: {
241
+ small: {
242
+ paddingX: 12, // px
243
+ paddingY: 8, // px
244
+ fontSize: 14, // px
245
+ lineHeight: 20, // px
246
+ minHeight: 36, // px
247
+ borderRadius: 6, // px
248
+ borderWidth: 1, // px
249
+ gap: 8, // px (icon spacing)
250
+ iconSize: 16 // px (icon size)
251
+ },
252
+ medium: {
253
+ paddingX: 16, // px
254
+ paddingY: 10, // px
255
+ fontSize: 16, // px
256
+ lineHeight: 24, // px
257
+ minHeight: 44, // px
258
+ borderRadius: 8, // px
259
+ borderWidth: 1, // px
260
+ gap: 8, // px (icon spacing)
261
+ iconSize: 20 // px (icon size)
262
+ },
263
+ large: {
264
+ paddingX: 24, // px
265
+ paddingY: 12, // px
266
+ fontSize: 18, // px
267
+ lineHeight: 28, // px
268
+ minHeight: 52, // px
269
+ borderRadius: 8, // px
270
+ borderWidth: 2, // px
271
+ gap: 10, // px (icon spacing)
272
+ iconSize: 24 // px (icon size)
273
+ }
274
+ },
275
+ primary: {
276
+ bgColor: 'primary',
277
+ bgColorHover: 'primaryDark',
278
+ bgGradient: null, // null or { from: 'primary', to: 'primaryDark', direction: 'to-br' }
279
+ bgGradientHover: null,
280
+ textColor: 'white',
281
+ textColorHover: null, // null = same as textColor
282
+ borderColor: 'primary',
283
+ borderColorHover: 'primaryDark',
284
+ shadow: 'sm', // none, sm, md, lg, xl, 2xl
285
+ shadowHover: 'md',
286
+ shadowColor: null, // null = default shadow, or color token
287
+ backdropBlur: null, // null or px value (4, 8, 12, 16, 24)
288
+ backdropBlurHover: null,
289
+ opacity: 100, // 0-100
290
+ opacityHover: 100 // 0-100
291
+ },
292
+ secondary: {
293
+ bgColor: 'secondary',
294
+ bgColorHover: 'secondaryDark',
295
+ bgGradient: null,
296
+ bgGradientHover: null,
297
+ textColor: 'white',
298
+ textColorHover: null,
299
+ borderColor: 'secondary',
300
+ borderColorHover: 'secondaryDark',
301
+ shadow: 'sm',
302
+ shadowHover: 'md',
303
+ shadowColor: null,
304
+ backdropBlur: null,
305
+ backdropBlurHover: null,
306
+ opacity: 100,
307
+ opacityHover: 100
308
+ },
309
+ ghost: {
310
+ bgColor: 'transparent',
311
+ bgColorHover: 'bgElevated',
312
+ bgGradient: null,
313
+ bgGradientHover: null,
314
+ textColor: 'textBase',
315
+ textColorHover: null,
316
+ borderColor: 'transparent',
317
+ borderColorHover: 'transparent',
318
+ shadow: 'none',
319
+ shadowHover: 'none',
320
+ shadowColor: null,
321
+ backdropBlur: null,
322
+ backdropBlurHover: null,
323
+ opacity: 100,
324
+ opacityHover: 100
325
+ },
326
+ accent: {
327
+ bgColor: 'bgAccentBase',
328
+ bgColorHover: 'bgAccentElevated',
329
+ bgGradient: null,
330
+ bgGradientHover: null,
331
+ textColor: 'white',
332
+ textColorHover: null,
333
+ borderColor: 'bgAccentBase',
334
+ borderColorHover: 'bgAccentElevated',
335
+ shadow: 'md',
336
+ shadowHover: 'lg',
337
+ shadowColor: null,
338
+ backdropBlur: null,
339
+ backdropBlurHover: null,
340
+ opacity: 100,
341
+ opacityHover: 100
342
+ },
343
+ inverted: {
344
+ bgColor: 'white',
345
+ bgColorHover: 'bgElevated',
346
+ bgGradient: null,
347
+ bgGradientHover: null,
348
+ textColor: 'textBase',
349
+ textColorHover: null,
350
+ borderColor: 'white',
351
+ borderColorHover: 'bgElevated',
352
+ shadow: 'sm',
353
+ shadowHover: 'md',
354
+ shadowColor: null,
355
+ backdropBlur: null,
356
+ backdropBlurHover: null,
357
+ opacity: 100,
358
+ opacityHover: 100
359
+ }
360
+ }
361
+ };
362
+
363
+ /**
364
+ * Generate Tailwind v4 @theme CSS from Design Tokens
365
+ */
366
+ export function generateTailwindV4Theme(tokens) {
367
+ const lines = [];
368
+
369
+ // Colors - Map to Tailwind v4 CSS variables
370
+ if (tokens.colors) {
371
+ // Primary colors
372
+ if (tokens.colors.primary) lines.push(` --color-primary: ${tokens.colors.primary};`);
373
+ if (tokens.colors.primaryDark) lines.push(` --color-primary-dark: ${tokens.colors.primaryDark};`);
374
+ if (tokens.colors.primaryLight) lines.push(` --color-primary-light: ${tokens.colors.primaryLight};`);
375
+
376
+ // Secondary colors
377
+ if (tokens.colors.secondary) lines.push(` --color-secondary: ${tokens.colors.secondary};`);
378
+ if (tokens.colors.secondaryDark) lines.push(` --color-secondary-dark: ${tokens.colors.secondaryDark};`);
379
+ if (tokens.colors.secondaryLight) lines.push(` --color-secondary-light: ${tokens.colors.secondaryLight};`);
380
+
381
+ // Semantic colors
382
+ if (tokens.colors.success) lines.push(` --color-success: ${tokens.colors.success};`);
383
+ if (tokens.colors.successDark) lines.push(` --color-success-dark: ${tokens.colors.successDark};`);
384
+ if (tokens.colors.warning) lines.push(` --color-warning: ${tokens.colors.warning};`);
385
+ if (tokens.colors.warningDark) lines.push(` --color-warning-dark: ${tokens.colors.warningDark};`);
386
+ if (tokens.colors.error) lines.push(` --color-error: ${tokens.colors.error};`);
387
+ if (tokens.colors.errorDark) lines.push(` --color-error-dark: ${tokens.colors.errorDark};`);
388
+ if (tokens.colors.info) lines.push(` --color-info: ${tokens.colors.info};`);
389
+ if (tokens.colors.infoDark) lines.push(` --color-info-dark: ${tokens.colors.infoDark};`);
390
+
391
+ // Background colors (Semantic)
392
+ if (tokens.colors.bgBase) lines.push(` --color-bg-base: ${tokens.colors.bgBase};`);
393
+ if (tokens.colors.bgElevated) lines.push(` --color-bg-elevated: ${tokens.colors.bgElevated};`);
394
+ if (tokens.colors.bgLifted) lines.push(` --color-bg-lifted: ${tokens.colors.bgLifted};`);
395
+ if (tokens.colors.bgAccentBase) lines.push(` --color-bg-accent-base: ${tokens.colors.bgAccentBase};`);
396
+ if (tokens.colors.bgAccentElevated) lines.push(` --color-bg-accent-elevated: ${tokens.colors.bgAccentElevated};`);
397
+ if (tokens.colors.bgAccentLifted) lines.push(` --color-bg-accent-lifted: ${tokens.colors.bgAccentLifted};`);
398
+
399
+ // Text colors (Semantic)
400
+ if (tokens.colors.textBase) lines.push(` --color-text-base: ${tokens.colors.textBase};`);
401
+ if (tokens.colors.textSubtle) lines.push(` --color-text-subtle: ${tokens.colors.textSubtle};`);
402
+ if (tokens.colors.textMuted) lines.push(` --color-text-muted: ${tokens.colors.textMuted};`);
403
+ if (tokens.colors.textAccentBase) lines.push(` --color-text-accent-base: ${tokens.colors.textAccentBase};`);
404
+ if (tokens.colors.textAccentSubtle) lines.push(` --color-text-accent-subtle: ${tokens.colors.textAccentSubtle};`);
405
+ if (tokens.colors.textAccentMuted) lines.push(` --color-text-accent-muted: ${tokens.colors.textAccentMuted};`);
406
+
407
+ // Border colors (Semantic)
408
+ if (tokens.colors.borderBase) lines.push(` --color-border-base: ${tokens.colors.borderBase};`);
409
+ if (tokens.colors.borderSubtle) lines.push(` --color-border-subtle: ${tokens.colors.borderSubtle};`);
410
+ if (tokens.colors.borderMuted) lines.push(` --color-border-muted: ${tokens.colors.borderMuted};`);
411
+
412
+ // Basic colors
413
+ if (tokens.colors.white) lines.push(` --color-white: ${tokens.colors.white};`);
414
+ if (tokens.colors.black) lines.push(` --color-black: ${tokens.colors.black};`);
415
+ }
416
+
417
+ // Typography - Font families
418
+ if (tokens.typography?.fontFamily) {
419
+ if (tokens.typography.fontFamily.heading) {
420
+ lines.push(` --font-heading: ${tokens.typography.fontFamily.heading};`);
421
+ }
422
+ if (tokens.typography.fontFamily.body) {
423
+ lines.push(` --font-body: ${tokens.typography.fontFamily.body};`);
424
+ }
425
+ if (tokens.typography.fontFamily.mono) {
426
+ lines.push(` --font-mono: ${tokens.typography.fontFamily.mono};`);
427
+ }
428
+ }
429
+
430
+ // Typography - Base values
431
+ if (tokens.typography?.fontSizeBase) {
432
+ lines.push(` --font-size: ${tokens.typography.fontSizeBase};`);
433
+ }
434
+ if (tokens.typography?.lineHeightBase) {
435
+ lines.push(` --line-height: ${tokens.typography.lineHeightBase};`);
436
+ }
437
+ if (tokens.typography?.letterSpacingBase) {
438
+ lines.push(` --letter-spacing: ${tokens.typography.letterSpacingBase};`);
439
+ }
440
+
441
+ // Text Styles - Generate CSS variables for each style (with responsive support)
442
+ if (tokens.textStyles) {
443
+ for (const [styleName, style] of Object.entries(tokens.textStyles)) {
444
+ const kebabName = styleName.replace(/([A-Z])/g, '-$1').toLowerCase();
445
+
446
+ // Font family (not responsive)
447
+ if (style.fontFamily) {
448
+ lines.push(` --text-${kebabName}-font-family: var(--font-${style.fontFamily});`);
449
+ }
450
+
451
+ // Font weight (not responsive)
452
+ if (style.fontWeight) {
453
+ lines.push(` --text-${kebabName}-font-weight: ${style.fontWeight};`);
454
+ }
455
+
456
+ // Text transform (not responsive)
457
+ if (style.textTransform) {
458
+ lines.push(` --text-${kebabName}-text-transform: ${style.textTransform};`);
459
+ }
460
+
461
+ // Font size (can be responsive)
462
+ if (style.fontSize) {
463
+ if (typeof style.fontSize === 'object') {
464
+ // Responsive: base value
465
+ if (style.fontSize.base) {
466
+ lines.push(` --text-${kebabName}-font-size: ${style.fontSize.base};`);
467
+ }
468
+ } else {
469
+ // Simple value
470
+ lines.push(` --text-${kebabName}-font-size: ${style.fontSize};`);
471
+ }
472
+ }
473
+
474
+ // Line height (can be responsive)
475
+ if (style.lineHeight) {
476
+ if (typeof style.lineHeight === 'object') {
477
+ if (style.lineHeight.base) {
478
+ lines.push(` --text-${kebabName}-line-height: ${style.lineHeight.base};`);
479
+ }
480
+ } else {
481
+ lines.push(` --text-${kebabName}-line-height: ${style.lineHeight};`);
482
+ }
483
+ }
484
+
485
+ // Letter spacing (can be responsive)
486
+ if (style.letterSpacing) {
487
+ if (typeof style.letterSpacing === 'object') {
488
+ if (style.letterSpacing.base) {
489
+ lines.push(` --text-${kebabName}-letter-spacing: ${style.letterSpacing.base};`);
490
+ }
491
+ } else {
492
+ lines.push(` --text-${kebabName}-letter-spacing: ${style.letterSpacing};`);
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ // Spacing base
499
+ if (tokens.spacing) {
500
+ lines.push(` --spacing: ${tokens.spacing};`);
501
+ }
502
+
503
+ // Border width base
504
+ if (tokens.borderWidth) {
505
+ lines.push(` --border-width: ${tokens.borderWidth};`);
506
+ }
507
+
508
+ // Border radius base
509
+ if (tokens.borderRadius) {
510
+ lines.push(` --radius: ${tokens.borderRadius};`);
511
+ }
512
+
513
+ // Container widths (specific breakpoints)
514
+ if (tokens.container) {
515
+ for (const [key, value] of Object.entries(tokens.container)) {
516
+ lines.push(` --container-${key}: ${value};`);
517
+ }
518
+ }
519
+
520
+ // Breakpoints
521
+ if (tokens.breakpoints) {
522
+ for (const [key, value] of Object.entries(tokens.breakpoints)) {
523
+ lines.push(` --breakpoint-${key}: ${value};`);
524
+ }
525
+ }
526
+
527
+ // Buttons - Sizes
528
+ if (tokens.buttons?.sizes) {
529
+ for (const [sizeName, sizeProps] of Object.entries(tokens.buttons.sizes)) {
530
+ const prefix = `button-${sizeName}`;
531
+ if (sizeProps.paddingX) lines.push(` --${prefix}-padding-x: ${sizeProps.paddingX};`);
532
+ if (sizeProps.paddingY) lines.push(` --${prefix}-padding-y: ${sizeProps.paddingY};`);
533
+ if (sizeProps.fontSize) lines.push(` --${prefix}-font-size: ${sizeProps.fontSize};`);
534
+ if (sizeProps.lineHeight) lines.push(` --${prefix}-line-height: ${sizeProps.lineHeight};`);
535
+ if (sizeProps.borderRadius) lines.push(` --${prefix}-border-radius: ${sizeProps.borderRadius};`);
536
+ if (sizeProps.gap) lines.push(` --${prefix}-gap: ${sizeProps.gap};`);
537
+ if (sizeProps.iconSize) lines.push(` --${prefix}-icon-size: ${sizeProps.iconSize};`);
538
+ }
539
+ }
540
+
541
+ // Buttons - Variants
542
+ if (tokens.buttons) {
543
+ const variants = Object.keys(tokens.buttons).filter(key => key !== 'sizes');
544
+ for (const variantName of variants) {
545
+ const variant = tokens.buttons[variantName];
546
+ const prefix = `button-${variantName}`;
547
+
548
+ if (variant.bgColor) {
549
+ const colorVar = tokens.colors[variant.bgColor] || variant.bgColor;
550
+ lines.push(` --${prefix}-bg: ${colorVar};`);
551
+ }
552
+ if (variant.bgColorHover) {
553
+ const colorVar = tokens.colors[variant.bgColorHover] || variant.bgColorHover;
554
+ lines.push(` --${prefix}-bg-hover: ${colorVar};`);
555
+ }
556
+ if (variant.textColor) {
557
+ const colorVar = tokens.colors[variant.textColor] || variant.textColor;
558
+ lines.push(` --${prefix}-text: ${colorVar};`);
559
+ }
560
+ if (variant.borderColor) {
561
+ const colorVar = tokens.colors[variant.borderColor] || variant.borderColor;
562
+ lines.push(` --${prefix}-border: ${colorVar};`);
563
+ }
564
+ if (variant.borderColorHover) {
565
+ const colorVar = tokens.colors[variant.borderColorHover] || variant.borderColorHover;
566
+ lines.push(` --${prefix}-border-hover: ${colorVar};`);
567
+ }
568
+ }
569
+ }
570
+
571
+ const themeVars = lines.join('\n');
572
+
573
+ // Global styles (MUST be outside @theme block)
574
+ let globalStyles = `
575
+ /* Global baseline font */
576
+ body {
577
+ font-family: var(--font-body);
578
+ }`;
579
+
580
+ // Generate utility classes for text styles
581
+ if (tokens.textStyles) {
582
+ globalStyles += '\n\n/* Text Style Utilities */';
583
+ for (const [styleName, style] of Object.entries(tokens.textStyles)) {
584
+ const kebabName = styleName.replace(/([A-Z])/g, '-$1').toLowerCase();
585
+ const className = `text-${kebabName}`;
586
+
587
+ globalStyles += `\n.${className} {`;
588
+ if (style.fontFamily) {
589
+ globalStyles += `\n font-family: var(--text-${kebabName}-font-family);`;
590
+ }
591
+ if (style.fontWeight) {
592
+ globalStyles += `\n font-weight: var(--text-${kebabName}-font-weight);`;
593
+ }
594
+ if (style.fontSize) {
595
+ globalStyles += `\n font-size: var(--text-${kebabName}-font-size);`;
596
+ }
597
+ if (style.lineHeight) {
598
+ globalStyles += `\n line-height: var(--text-${kebabName}-line-height);`;
599
+ }
600
+ if (style.letterSpacing) {
601
+ globalStyles += `\n letter-spacing: var(--text-${kebabName}-letter-spacing);`;
602
+ }
603
+ if (style.textTransform) {
604
+ globalStyles += `\n text-transform: var(--text-${kebabName}-text-transform);`;
605
+ }
606
+ globalStyles += `\n}`;
607
+ }
608
+ }
609
+
610
+ // Generate utility classes for buttons
611
+ if (tokens.buttons) {
612
+ globalStyles += '\n\n/* Button Utilities */';
613
+
614
+ // Base button class
615
+ globalStyles += `\n.btn {
616
+ display: inline-flex;
617
+ align-items: center;
618
+ justify-content: center;
619
+ font-weight: 500;
620
+ border-width: 1px;
621
+ border-style: solid;
622
+ transition: all 0.15s ease-in-out;
623
+ cursor: pointer;
624
+ text-decoration: none;
625
+ }`;
626
+
627
+ // Size classes
628
+ if (tokens.buttons.sizes) {
629
+ for (const sizeName of Object.keys(tokens.buttons.sizes)) {
630
+ globalStyles += `\n.btn-${sizeName} {
631
+ padding: var(--button-${sizeName}-padding-y) var(--button-${sizeName}-padding-x);
632
+ font-size: var(--button-${sizeName}-font-size);
633
+ line-height: var(--button-${sizeName}-line-height);
634
+ border-radius: var(--button-${sizeName}-border-radius);
635
+ gap: var(--button-${sizeName}-gap);
636
+ }`;
637
+ }
638
+ }
639
+
640
+ // Variant classes
641
+ const variants = Object.keys(tokens.buttons).filter(key => key !== 'sizes');
642
+ for (const variantName of variants) {
643
+ globalStyles += `\n.btn-${variantName} {
644
+ background-color: var(--button-${variantName}-bg);
645
+ color: var(--button-${variantName}-text);
646
+ border-color: var(--button-${variantName}-border);
647
+ }
648
+ .btn-${variantName}:hover {
649
+ background-color: var(--button-${variantName}-bg-hover);
650
+ border-color: var(--button-${variantName}-border-hover);
651
+ }`;
652
+ }
653
+ }
654
+
655
+ // Add responsive media queries for textStyles (OUTSIDE @theme block!)
656
+ if (tokens.textStyles) {
657
+ const breakpointKeys = ['sm', 'md', 'lg', 'xl', '2xl'];
658
+ const breakpointValues = {
659
+ sm: '640px',
660
+ md: '768px',
661
+ lg: '1024px',
662
+ xl: '1280px',
663
+ '2xl': '1536px'
664
+ };
665
+
666
+ for (const bp of breakpointKeys) {
667
+ const mediaQueryLines = [];
668
+
669
+ for (const [styleName, style] of Object.entries(tokens.textStyles)) {
670
+ const kebabName = styleName.replace(/([A-Z])/g, '-$1').toLowerCase();
671
+
672
+ // Font size
673
+ if (style.fontSize && typeof style.fontSize === 'object' && style.fontSize[bp]) {
674
+ mediaQueryLines.push(` --text-${kebabName}-font-size: ${style.fontSize[bp]};`);
675
+ }
676
+
677
+ // Line height
678
+ if (style.lineHeight && typeof style.lineHeight === 'object' && style.lineHeight[bp]) {
679
+ mediaQueryLines.push(` --text-${kebabName}-line-height: ${style.lineHeight[bp]};`);
680
+ }
681
+
682
+ // Letter spacing
683
+ if (style.letterSpacing && typeof style.letterSpacing === 'object' && style.letterSpacing[bp]) {
684
+ mediaQueryLines.push(` --text-${kebabName}-letter-spacing: ${style.letterSpacing[bp]};`);
685
+ }
686
+ }
687
+
688
+ if (mediaQueryLines.length > 0) {
689
+ globalStyles += `\n\n@media (min-width: ${breakpointValues[bp]}) {\n :root {\n`;
690
+ globalStyles += mediaQueryLines.join('\n');
691
+ globalStyles += '\n }\n}';
692
+ }
693
+ }
694
+ }
695
+
696
+ return { themeVars, globalStyles };
697
+ }
698
+
699
+ /**
700
+ * Generate Tailwind Config from Design Tokens (for Tailwind v3 - legacy)
701
+ */
702
+ export function generateTailwindConfig(tokens) {
703
+ return {
704
+ theme: {
705
+ extend: {
706
+ colors: {
707
+ // Brand colors
708
+ primary: {
709
+ DEFAULT: tokens.colors?.primary || '#ea580c',
710
+ dark: tokens.colors?.primaryDark || '#c2410c',
711
+ light: tokens.colors?.primaryLight || '#fb923c'
712
+ },
713
+ secondary: {
714
+ DEFAULT: tokens.colors?.secondary || '#6366f1',
715
+ dark: tokens.colors?.secondaryDark || '#4f46e5',
716
+ light: tokens.colors?.secondaryLight || '#818cf8'
717
+ },
718
+ // Semantic colors
719
+ success: {
720
+ DEFAULT: tokens.colors?.success || '#10b981',
721
+ dark: tokens.colors?.successDark || '#059669'
722
+ },
723
+ warning: {
724
+ DEFAULT: tokens.colors?.warning || '#f59e0b',
725
+ dark: tokens.colors?.warningDark || '#d97706'
726
+ },
727
+ error: {
728
+ DEFAULT: tokens.colors?.error || '#ef4444',
729
+ dark: tokens.colors?.errorDark || '#dc2626'
730
+ },
731
+ info: {
732
+ DEFAULT: tokens.colors?.info || '#3b82f6',
733
+ dark: tokens.colors?.infoDark || '#2563eb'
734
+ }
735
+ },
736
+ fontFamily: {
737
+ heading: tokens.typography?.fontFamily?.heading?.split(',') || ['Inter', 'system-ui', 'sans-serif'],
738
+ body: tokens.typography?.fontFamily?.body?.split(',') || ['Inter', 'system-ui', 'sans-serif'],
739
+ mono: tokens.typography?.fontFamily?.mono?.split(',') || ['ui-monospace', 'monospace']
740
+ },
741
+ fontSize: tokens.typography?.fontSize || {},
742
+ fontWeight: tokens.typography?.fontWeight || {},
743
+ lineHeight: tokens.typography?.lineHeight || {},
744
+ letterSpacing: tokens.typography?.letterSpacing || {},
745
+ spacing: tokens.spacing || {},
746
+ borderRadius: tokens.borderRadius || {},
747
+ boxShadow: tokens.boxShadow || {},
748
+ maxWidth: tokens.container || {}
749
+ }
750
+ },
751
+ safelist: [
752
+ // Brand colors
753
+ 'bg-primary', 'bg-primary-dark', 'bg-primary-light',
754
+ 'bg-secondary', 'bg-secondary-dark', 'bg-secondary-light',
755
+ 'text-primary', 'text-primary-dark', 'text-primary-light',
756
+ 'text-secondary', 'text-secondary-dark', 'text-secondary-light',
757
+ 'border-primary', 'border-secondary',
758
+ // Semantic colors
759
+ 'bg-success', 'bg-warning', 'bg-error', 'bg-info',
760
+ 'text-success', 'text-warning', 'text-error', 'text-info',
761
+ // Background tokens
762
+ 'bg-base', 'bg-elevated', 'bg-lifted',
763
+ 'bg-accent-base', 'bg-accent-elevated', 'bg-accent-lifted',
764
+ // Text tokens
765
+ 'text-base', 'text-subtle', 'text-muted',
766
+ 'text-accent-base', 'text-accent-subtle', 'text-accent-muted',
767
+ // Text styles
768
+ 'text-display', 'text-heading-1', 'text-heading-2', 'text-heading-3',
769
+ 'text-overline-display', 'text-overline-heading-1', 'text-overline-heading-2', 'text-overline-heading-3',
770
+ 'text-lead', 'text-body', 'text-body-small',
771
+ 'text-caption', 'text-label'
772
+ ]
773
+ };
774
+ }
775
+
776
+ /**
777
+ * Generate CSS Variables from Design Tokens
778
+ */
779
+ export function generateCSSFromTokens(tokens) {
780
+ const lines = [':root {'];
781
+
782
+ // Colors
783
+ for (const [key, value] of Object.entries(tokens.colors || {})) {
784
+ const cssVarName = `--color-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
785
+ lines.push(` ${cssVarName}: ${value};`);
786
+ }
787
+
788
+ // Typography - Font Families
789
+ for (const [key, value] of Object.entries(tokens.typography?.fontFamily || {})) {
790
+ lines.push(` --font-${key}: ${value};`);
791
+ }
792
+
793
+ // Typography - Font Sizes
794
+ for (const [key, value] of Object.entries(tokens.typography?.fontSize || {})) {
795
+ lines.push(` --text-${key}: ${value};`);
796
+ }
797
+
798
+ // Typography - Font Weights
799
+ for (const [key, value] of Object.entries(tokens.typography?.fontWeight || {})) {
800
+ lines.push(` --font-${key}: ${value};`);
801
+ }
802
+
803
+ // Typography - Line Heights
804
+ for (const [key, value] of Object.entries(tokens.typography?.lineHeight || {})) {
805
+ lines.push(` --leading-${key}: ${value};`);
806
+ }
807
+
808
+ // Typography - Letter Spacing
809
+ for (const [key, value] of Object.entries(tokens.typography?.letterSpacing || {})) {
810
+ lines.push(` --tracking-${key}: ${value};`);
811
+ }
812
+
813
+ // Spacing
814
+ if (typeof tokens.spacing === 'object' && tokens.spacing !== null) {
815
+ // Object format: { '0': '0', '1': '0.25rem', '2': '0.5rem', ... }
816
+ for (const [key, value] of Object.entries(tokens.spacing)) {
817
+ lines.push(` --spacing-${key.replace('.', '-')}: ${value};`);
818
+ }
819
+ } else if (typeof tokens.spacing === 'string') {
820
+ // String format (base unit): '0.25rem' - Tailwind v4 will auto-generate scale
821
+ // Output base spacing variable for Tailwind v4
822
+ lines.push(` --spacing: ${tokens.spacing};`);
823
+ }
824
+
825
+ // Container
826
+ for (const [key, value] of Object.entries(tokens.container || {})) {
827
+ lines.push(` --container-${key}: ${value};`);
828
+ }
829
+
830
+ // Border Width
831
+ if (typeof tokens.borderWidth === 'object' && tokens.borderWidth !== null) {
832
+ for (const [key, value] of Object.entries(tokens.borderWidth)) {
833
+ const varName = key === 'DEFAULT' ? '--border-width' : `--border-width-${key}`;
834
+ lines.push(` ${varName}: ${value};`);
835
+ }
836
+ } else if (typeof tokens.borderWidth === 'string') {
837
+ lines.push(` --border-width: ${tokens.borderWidth};`);
838
+ }
839
+
840
+ // Border Radius
841
+ if (typeof tokens.borderRadius === 'object' && tokens.borderRadius !== null) {
842
+ for (const [key, value] of Object.entries(tokens.borderRadius)) {
843
+ const varName = key === 'DEFAULT' ? '--radius' : `--radius-${key}`;
844
+ lines.push(` ${varName}: ${value};`);
845
+ }
846
+ } else if (typeof tokens.borderRadius === 'string') {
847
+ lines.push(` --radius: ${tokens.borderRadius};`);
848
+ }
849
+
850
+ // Box Shadow
851
+ for (const [key, value] of Object.entries(tokens.boxShadow || {})) {
852
+ const varName = key === 'DEFAULT' ? '--shadow' : `--shadow-${key}`;
853
+ lines.push(` ${varName}: ${value};`);
854
+ }
855
+
856
+ lines.push('}');
857
+
858
+ // Add global body font-family as baseline
859
+ lines.push('');
860
+ lines.push('/* Global baseline font */');
861
+ lines.push('body {');
862
+ lines.push(' font-family: var(--font-body);');
863
+ lines.push('}');
864
+
865
+ // Generate utility classes for text styles
866
+ if (tokens.textStyles) {
867
+ lines.push('');
868
+ lines.push('/* Text Style Utilities */');
869
+ for (const [styleName, style] of Object.entries(tokens.textStyles)) {
870
+ const kebabName = styleName.replace(/([A-Z])/g, '-$1').toLowerCase();
871
+ const className = `text-${kebabName}`;
872
+
873
+ lines.push(`.${className} {`);
874
+ if (style.fontFamily) {
875
+ const fontVar = `--font-${style.fontFamily}`;
876
+ lines.push(` font-family: var(${fontVar});`);
877
+ }
878
+ if (style.fontWeight) {
879
+ lines.push(` font-weight: ${style.fontWeight};`);
880
+ }
881
+ if (style.fontSize) {
882
+ const fontSize = typeof style.fontSize === 'object' ? style.fontSize.base : style.fontSize;
883
+ lines.push(` font-size: ${fontSize};`);
884
+ }
885
+ if (style.lineHeight) {
886
+ const lineHeight = typeof style.lineHeight === 'object' ? style.lineHeight.base : style.lineHeight;
887
+ lines.push(` line-height: ${lineHeight};`);
888
+ }
889
+ if (style.letterSpacing) {
890
+ const letterSpacing = typeof style.letterSpacing === 'object' ? style.letterSpacing.base : style.letterSpacing;
891
+ lines.push(` letter-spacing: ${letterSpacing};`);
892
+ }
893
+ if (style.textTransform) {
894
+ lines.push(` text-transform: ${style.textTransform};`);
895
+ }
896
+ if (style.textColor) {
897
+ const colorVar = `--color-${style.textColor.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
898
+ lines.push(` color: var(${colorVar});`);
899
+ }
900
+ lines.push('}');
901
+ }
902
+
903
+ // Add responsive media queries for textStyles
904
+ const breakpointKeys = ['md', 'lg', 'xl', '2xl'];
905
+ const breakpointValues = {
906
+ md: '768px',
907
+ lg: '1024px',
908
+ xl: '1280px',
909
+ '2xl': '1536px'
910
+ };
911
+
912
+ for (const bp of breakpointKeys) {
913
+ const mediaQueryLines = [];
914
+
915
+ for (const [styleName, style] of Object.entries(tokens.textStyles)) {
916
+ const kebabName = styleName.replace(/([A-Z])/g, '-$1').toLowerCase();
917
+ const className = `text-${kebabName}`;
918
+ const hasResponsive = (
919
+ (style.fontSize && typeof style.fontSize === 'object' && style.fontSize[bp]) ||
920
+ (style.lineHeight && typeof style.lineHeight === 'object' && style.lineHeight[bp]) ||
921
+ (style.letterSpacing && typeof style.letterSpacing === 'object' && style.letterSpacing[bp])
922
+ );
923
+
924
+ if (hasResponsive) {
925
+ mediaQueryLines.push(` .${className} {`);
926
+ if (style.fontSize && typeof style.fontSize === 'object' && style.fontSize[bp]) {
927
+ mediaQueryLines.push(` font-size: ${style.fontSize[bp]};`);
928
+ }
929
+ if (style.lineHeight && typeof style.lineHeight === 'object' && style.lineHeight[bp]) {
930
+ mediaQueryLines.push(` line-height: ${style.lineHeight[bp]};`);
931
+ }
932
+ if (style.letterSpacing && typeof style.letterSpacing === 'object' && style.letterSpacing[bp]) {
933
+ mediaQueryLines.push(` letter-spacing: ${style.letterSpacing[bp]};`);
934
+ }
935
+ mediaQueryLines.push(` }`);
936
+ }
937
+ }
938
+
939
+ if (mediaQueryLines.length > 0) {
940
+ lines.push('');
941
+ lines.push(`@media (min-width: ${breakpointValues[bp]}) {`);
942
+ lines.push(...mediaQueryLines);
943
+ lines.push('}');
944
+ }
945
+ }
946
+ }
947
+
948
+ // Generate button utility classes
949
+ if (tokens.buttons) {
950
+ lines.push('');
951
+ lines.push('/* Button Utilities */');
952
+
953
+ // Helper to convert hex to rgba with opacity
954
+ const hexToRgba = (hex, alpha) => {
955
+ if (!hex || hex === 'transparent') return 'transparent';
956
+ hex = hex.replace('#', '');
957
+ const r = parseInt(hex.substring(0, 2), 16);
958
+ const g = parseInt(hex.substring(2, 4), 16);
959
+ const b = parseInt(hex.substring(4, 6), 16);
960
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
961
+ };
962
+
963
+ // Shadow presets
964
+ const shadowPresets = {
965
+ none: 'none',
966
+ sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
967
+ md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
968
+ lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
969
+ xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
970
+ '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)'
971
+ };
972
+
973
+ // Gradient direction mapping
974
+ const directionMap = {
975
+ 'to-t': 'to top',
976
+ 'to-tr': 'to top right',
977
+ 'to-r': 'to right',
978
+ 'to-br': 'to bottom right',
979
+ 'to-b': 'to bottom',
980
+ 'to-bl': 'to bottom left',
981
+ 'to-l': 'to left',
982
+ 'to-tl': 'to top left'
983
+ };
984
+
985
+ // Base button class
986
+ lines.push('.btn {');
987
+ lines.push(' display: inline-flex;');
988
+ lines.push(' align-items: center;');
989
+ lines.push(' justify-content: center;');
990
+ lines.push(' font-weight: 500;');
991
+ lines.push(' border-style: solid;');
992
+ lines.push(' transition: all 0.15s ease-in-out;');
993
+ lines.push(' cursor: pointer;');
994
+ lines.push(' text-decoration: none;');
995
+ lines.push('}');
996
+
997
+ // Size classes with direct values
998
+ if (tokens.buttons.sizes) {
999
+ for (const [sizeName, size] of Object.entries(tokens.buttons.sizes)) {
1000
+ lines.push(`.btn-${sizeName} {`);
1001
+ lines.push(` padding: ${size.paddingY}px ${size.paddingX}px;`);
1002
+ lines.push(` font-size: ${size.fontSize}px;`);
1003
+ // Calculate unitless line-height (lineHeight in px / fontSize in px)
1004
+ const lineHeightRatio = size.lineHeight / size.fontSize;
1005
+ lines.push(` line-height: ${lineHeightRatio};`);
1006
+ lines.push(` min-height: ${size.minHeight}px;`);
1007
+ lines.push(` border-radius: ${size.borderRadius}px;`);
1008
+ lines.push(` border-width: ${size.borderWidth}px;`);
1009
+ lines.push(` gap: ${size.gap}px;`);
1010
+ lines.push('}');
1011
+
1012
+ // Icon size
1013
+ lines.push(`.btn-${sizeName} iconify-icon {`);
1014
+ lines.push(` font-size: ${size.iconSize}px;`);
1015
+ lines.push('}');
1016
+ }
1017
+ }
1018
+
1019
+ // Variant classes with gradients, opacity, shadows
1020
+ const variants = Object.keys(tokens.buttons).filter(key => key !== 'sizes');
1021
+ for (const variantName of variants) {
1022
+ const variant = tokens.buttons[variantName];
1023
+
1024
+ const bgColor = tokens.colors[variant.bgColor] || variant.bgColor;
1025
+ const textColor = tokens.colors[variant.textColor] || variant.textColor;
1026
+ const borderColor = tokens.colors[variant.borderColor] || variant.borderColor;
1027
+ const opacity = (variant.opacity || 100) / 100;
1028
+
1029
+ lines.push(`.btn-${variantName} {`);
1030
+
1031
+ // Background with opacity and gradient support
1032
+ if (variant.bgGradient) {
1033
+ const fromColor = tokens.colors[variant.bgGradient.from] || variant.bgGradient.from;
1034
+ const toColor = tokens.colors[variant.bgGradient.to] || variant.bgGradient.to;
1035
+ const direction = directionMap[variant.bgGradient.direction] || 'to bottom right';
1036
+ const fromRgba = hexToRgba(fromColor, opacity);
1037
+ const toRgba = hexToRgba(toColor, opacity);
1038
+ lines.push(` background: linear-gradient(${direction}, ${fromRgba}, ${toRgba});`);
1039
+ } else {
1040
+ lines.push(` background-color: ${hexToRgba(bgColor, opacity)};`);
1041
+ }
1042
+
1043
+ lines.push(` color: ${textColor};`);
1044
+ lines.push(` border-color: ${borderColor};`);
1045
+
1046
+ // Shadow
1047
+ if (variant.shadow && variant.shadow !== 'none') {
1048
+ lines.push(` box-shadow: ${shadowPresets[variant.shadow]};`);
1049
+ }
1050
+
1051
+ // Backdrop blur
1052
+ if (variant.backdropBlur) {
1053
+ lines.push(` backdrop-filter: blur(${variant.backdropBlur}px);`);
1054
+ lines.push(` -webkit-backdrop-filter: blur(${variant.backdropBlur}px);`);
1055
+ }
1056
+
1057
+ lines.push('}');
1058
+
1059
+ // Hover state
1060
+ const bgColorHover = variant.bgColorHover ? (tokens.colors[variant.bgColorHover] || variant.bgColorHover) : bgColor;
1061
+ const textColorHover = variant.textColorHover ? (tokens.colors[variant.textColorHover] || variant.textColorHover) : textColor;
1062
+ const borderColorHover = variant.borderColorHover ? (tokens.colors[variant.borderColorHover] || variant.borderColorHover) : borderColor;
1063
+ const opacityHover = (variant.opacityHover !== undefined ? variant.opacityHover : (variant.opacity || 100)) / 100;
1064
+
1065
+ lines.push(`.btn-${variantName}:hover {`);
1066
+
1067
+ // Hover background with opacity and gradient support
1068
+ if (variant.bgGradientHover) {
1069
+ const fromColor = tokens.colors[variant.bgGradientHover.from] || variant.bgGradientHover.from;
1070
+ const toColor = tokens.colors[variant.bgGradientHover.to] || variant.bgGradientHover.to;
1071
+ const direction = directionMap[variant.bgGradientHover.direction] || 'to bottom right';
1072
+ const fromRgba = hexToRgba(fromColor, opacityHover);
1073
+ const toRgba = hexToRgba(toColor, opacityHover);
1074
+ lines.push(` background: linear-gradient(${direction}, ${fromRgba}, ${toRgba});`);
1075
+ } else if (variant.bgGradient && !variant.bgColorHover) {
1076
+ // Keep gradient on hover if no hover color specified
1077
+ const fromColor = tokens.colors[variant.bgGradient.from] || variant.bgGradient.from;
1078
+ const toColor = tokens.colors[variant.bgGradient.to] || variant.bgGradient.to;
1079
+ const direction = directionMap[variant.bgGradient.direction] || 'to bottom right';
1080
+ const fromRgba = hexToRgba(fromColor, opacityHover);
1081
+ const toRgba = hexToRgba(toColor, opacityHover);
1082
+ lines.push(` background: linear-gradient(${direction}, ${fromRgba}, ${toRgba});`);
1083
+ } else {
1084
+ lines.push(` background-color: ${hexToRgba(bgColorHover, opacityHover)};`);
1085
+ }
1086
+
1087
+ if (variant.textColorHover) {
1088
+ lines.push(` color: ${textColorHover};`);
1089
+ }
1090
+ lines.push(` border-color: ${borderColorHover};`);
1091
+
1092
+ // Hover shadow
1093
+ if (variant.shadowHover && variant.shadowHover !== 'none') {
1094
+ lines.push(` box-shadow: ${shadowPresets[variant.shadowHover]};`);
1095
+ }
1096
+
1097
+ // Hover backdrop blur
1098
+ if (variant.backdropBlurHover !== undefined && variant.backdropBlurHover !== null) {
1099
+ if (variant.backdropBlurHover === 0) {
1100
+ lines.push(` backdrop-filter: none;`);
1101
+ lines.push(` -webkit-backdrop-filter: none;`);
1102
+ } else {
1103
+ lines.push(` backdrop-filter: blur(${variant.backdropBlurHover}px);`);
1104
+ lines.push(` -webkit-backdrop-filter: blur(${variant.backdropBlurHover}px);`);
1105
+ }
1106
+ }
1107
+
1108
+ lines.push('}');
1109
+ }
1110
+ }
1111
+
1112
+ // Generate utility classes for semantic colors
1113
+ if (tokens.colors) {
1114
+ lines.push('');
1115
+ lines.push('/* Semantic Color Utilities */');
1116
+
1117
+ // Background colors
1118
+ const bgColors = [
1119
+ 'bgBase', 'bgElevated', 'bgLifted',
1120
+ 'bgAccentBase', 'bgAccentElevated', 'bgAccentLifted'
1121
+ ];
1122
+ for (const colorKey of bgColors) {
1123
+ if (tokens.colors[colorKey]) {
1124
+ const kebabName = colorKey.replace(/([A-Z])/g, '-$1').toLowerCase().replace('bg-', '');
1125
+ const className = `bg-${kebabName}`;
1126
+ const colorVar = `--color-${colorKey.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
1127
+ lines.push(`.${className} {`);
1128
+ lines.push(` background-color: var(${colorVar});`);
1129
+ lines.push('}');
1130
+ }
1131
+ }
1132
+
1133
+ // Text colors
1134
+ const textColors = [
1135
+ 'textBase', 'textSubtle', 'textMuted',
1136
+ 'textAccentBase', 'textAccentSubtle', 'textAccentMuted'
1137
+ ];
1138
+ for (const colorKey of textColors) {
1139
+ if (tokens.colors[colorKey]) {
1140
+ const kebabName = colorKey.replace(/([A-Z])/g, '-$1').toLowerCase().replace('text-', '');
1141
+ const className = `text-${kebabName}`;
1142
+ const colorVar = `--color-${colorKey.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
1143
+ lines.push(`.${className} {`);
1144
+ lines.push(` color: var(${colorVar});`);
1145
+ lines.push('}');
1146
+ }
1147
+ }
1148
+
1149
+ // Border colors
1150
+ const borderColors = [
1151
+ 'borderBase', 'borderSubtle', 'borderMuted'
1152
+ ];
1153
+ for (const colorKey of borderColors) {
1154
+ if (tokens.colors[colorKey]) {
1155
+ const kebabName = colorKey.replace(/([A-Z])/g, '-$1').toLowerCase().replace('border-', '');
1156
+ const className = `border-${kebabName}`;
1157
+ const colorVar = `--color-${colorKey.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
1158
+ lines.push(`.${className} {`);
1159
+ lines.push(` border-color: var(${colorVar});`);
1160
+ lines.push('}');
1161
+ }
1162
+ }
1163
+ }
1164
+
1165
+ return lines.join('\n');
1166
+ }
package/src/index.js CHANGED
@@ -5,6 +5,7 @@ import { bundleIsland, bundleComponentIslands } from './bundler.js';
5
5
  import { deduplicateCSS } from './css-deduplicator.js';
6
6
  import { markdownToHtml, processMarkdownProps } from './markdown.js';
7
7
  import TemplateProcessor, { templateProcessor } from './template-processor.js';
8
+ import { defaultDesignTokens, generateTailwindV4Theme, generateTailwindConfig, generateCSSFromTokens } from './design-tokens.js';
8
9
  import { readFileSync } from 'fs';
9
10
  import { fileURLToPath } from 'url';
10
11
  import { dirname, join } from 'path';
@@ -17,4 +18,4 @@ function getMotionRuntime() {
17
18
  return readFileSync(join(__dirname, '../dist/motion-runtime.min.js'), 'utf-8');
18
19
  }
19
20
 
20
- export { build, generateComponentCSS, generateTailwindCSS, extractTailwindClasses, cleanComponentHTML, bundleIsland, bundleComponentIslands, deduplicateCSS, markdownToHtml, processMarkdownProps, getMotionRuntime, TemplateProcessor, templateProcessor };
21
+ export { build, generateComponentCSS, generateTailwindCSS, extractTailwindClasses, cleanComponentHTML, bundleIsland, bundleComponentIslands, deduplicateCSS, markdownToHtml, processMarkdownProps, getMotionRuntime, TemplateProcessor, templateProcessor, defaultDesignTokens, generateTailwindV4Theme, generateTailwindConfig, generateCSSFromTokens };