@promptui-lib/codegen 0.1.4 → 0.1.5

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.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Intelligent Component Detector
3
+ * Detects component types from Figma nodes using multiple strategies:
4
+ * 1. Fuzzy name matching (multilingual)
5
+ * 2. Visual property heuristics
6
+ * 3. Structure-based detection
7
+ */
8
+ import type { IFigmaNode } from '@promptui-lib/core';
9
+ /**
10
+ * Detected component type with confidence score
11
+ */
12
+ export interface IDetectionResult {
13
+ componentType: string;
14
+ confidence: number;
15
+ strategy: 'name' | 'visual' | 'structure' | 'hybrid';
16
+ details?: string;
17
+ }
18
+ /**
19
+ * Main detection function - combines all strategies
20
+ */
21
+ export declare function detectComponentType(node: IFigmaNode): IDetectionResult;
22
+ /**
23
+ * Detect all components in a tree
24
+ */
25
+ export declare function detectComponentsInTree(node: IFigmaNode, results?: Map<string, IDetectionResult>): Map<string, IDetectionResult>;
26
+ /**
27
+ * Get component type with fallback to raw CSS generation
28
+ */
29
+ export declare function getComponentTypeOrRaw(node: IFigmaNode): {
30
+ type: 'component' | 'raw';
31
+ componentType?: string;
32
+ confidence?: number;
33
+ };
34
+ //# sourceMappingURL=component-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-detector.d.ts","sourceRoot":"","sources":["../../src/detection/component-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmgBD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,gBAAgB,CAkEtE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAa,GACjD,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAW/B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG;IACvD,IAAI,EAAE,WAAW,GAAG,KAAK,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAaA"}
@@ -0,0 +1,564 @@
1
+ /**
2
+ * Intelligent Component Detector
3
+ * Detects component types from Figma nodes using multiple strategies:
4
+ * 1. Fuzzy name matching (multilingual)
5
+ * 2. Visual property heuristics
6
+ * 3. Structure-based detection
7
+ */
8
+ /**
9
+ * Name patterns for fuzzy matching (multilingual)
10
+ */
11
+ const NAME_PATTERNS = {
12
+ button: [
13
+ /button/i, /btn/i, /botão/i, /botao/i, /cta/i, /submit/i, /enviar/i,
14
+ /action/i, /ação/i, /acao/i, /confirmar/i, /cancelar/i, /salvar/i, /save/i,
15
+ /click/i, /tap/i, /press/i,
16
+ ],
17
+ input: [
18
+ /input/i, /text.?field/i, /entrada/i, /campo/i, /field/i,
19
+ /email/i, /password/i, /senha/i, /search/i, /busca/i, /pesquisa/i,
20
+ /nome/i, /name/i, /telefone/i, /phone/i, /cpf/i, /cnpj/i,
21
+ ],
22
+ card: [
23
+ /card/i, /cartão/i, /cartao/i, /tile/i, /item/i, /panel/i, /painel/i,
24
+ /box/i, /container/i, /wrapper/i, /bloco/i, /block/i,
25
+ ],
26
+ avatar: [
27
+ /avatar/i, /profile.?pic/i, /user.?image/i, /foto/i, /photo/i,
28
+ /imagem.?perfil/i, /user.?icon/i,
29
+ ],
30
+ checkbox: [
31
+ /checkbox/i, /check.?box/i, /caixa.?seleção/i, /selecionar/i,
32
+ /marcar/i, /tick/i,
33
+ ],
34
+ radio: [
35
+ /radio/i, /radio.?button/i, /opção/i, /opcao/i, /option/i,
36
+ ],
37
+ switch: [
38
+ /switch/i, /toggle/i, /alternar/i, /on.?off/i, /liga.?desliga/i,
39
+ ],
40
+ select: [
41
+ /select/i, /dropdown/i, /combo/i, /seleção/i, /selecao/i,
42
+ /escolher/i, /picker/i, /lista/i, /list/i,
43
+ ],
44
+ modal: [
45
+ /modal/i, /dialog/i, /popup/i, /overlay/i, /alert/i, /alerta/i,
46
+ /confirm/i, /toast/i, /notification/i, /notificação/i,
47
+ ],
48
+ tabs: [
49
+ /tab/i, /tabs/i, /aba/i, /abas/i, /navigation/i, /nav/i,
50
+ ],
51
+ table: [
52
+ /table/i, /tabela/i, /grid/i, /data.?grid/i, /lista/i, /list/i,
53
+ /rows/i, /linhas/i,
54
+ ],
55
+ icon: [
56
+ /icon/i, /ícone/i, /icone/i, /symbol/i, /símbolo/i, /simbolo/i,
57
+ /glyph/i, /svg/i,
58
+ ],
59
+ image: [
60
+ /image/i, /imagem/i, /img/i, /photo/i, /foto/i, /picture/i,
61
+ /banner/i, /thumb/i, /thumbnail/i,
62
+ ],
63
+ text: [
64
+ /text/i, /texto/i, /label/i, /título/i, /titulo/i, /title/i,
65
+ /heading/i, /paragraph/i, /parágrafo/i, /paragrafo/i,
66
+ /description/i, /descrição/i, /descricao/i,
67
+ ],
68
+ badge: [
69
+ /badge/i, /tag/i, /chip/i, /etiqueta/i, /label/i, /status/i,
70
+ /indicator/i, /indicador/i,
71
+ ],
72
+ progress: [
73
+ /progress/i, /progresso/i, /loading/i, /carregando/i, /spinner/i,
74
+ /loader/i, /bar/i, /barra/i,
75
+ ],
76
+ divider: [
77
+ /divider/i, /divisor/i, /separator/i, /separador/i, /line/i, /linha/i,
78
+ /hr/i,
79
+ ],
80
+ header: [
81
+ /header/i, /cabeçalho/i, /cabecalho/i, /topbar/i, /top.?bar/i,
82
+ /navbar/i, /nav.?bar/i, /app.?bar/i,
83
+ ],
84
+ footer: [
85
+ /footer/i, /rodapé/i, /rodape/i, /bottom/i, /fundo/i,
86
+ ],
87
+ sidebar: [
88
+ /sidebar/i, /side.?bar/i, /menu.?lateral/i, /drawer/i, /nav/i,
89
+ /navigation/i, /navegação/i, /navegacao/i,
90
+ ],
91
+ form: [
92
+ /form/i, /formulário/i, /formulario/i, /cadastro/i, /registro/i,
93
+ /register/i, /login/i, /signin/i, /sign.?in/i, /signup/i, /sign.?up/i,
94
+ ],
95
+ breadcrumb: [
96
+ /breadcrumb/i, /migalha/i, /caminho/i, /path/i, /trail/i,
97
+ ],
98
+ pagination: [
99
+ /pagination/i, /paginação/i, /paginacao/i, /page/i, /páginas/i, /paginas/i,
100
+ ],
101
+ tooltip: [
102
+ /tooltip/i, /dica/i, /hint/i, /popover/i, /info/i,
103
+ ],
104
+ accordion: [
105
+ /accordion/i, /collapse/i, /expandir/i, /expand/i, /acordeão/i, /acordeao/i,
106
+ ],
107
+ carousel: [
108
+ /carousel/i, /slider/i, /slideshow/i, /galeria/i, /gallery/i,
109
+ /swiper/i, /scroll/i,
110
+ ],
111
+ rating: [
112
+ /rating/i, /avaliação/i, /avaliacao/i, /stars/i, /estrelas/i,
113
+ /review/i, /score/i,
114
+ ],
115
+ stepper: [
116
+ /stepper/i, /steps/i, /wizard/i, /etapas/i, /passos/i,
117
+ ],
118
+ menu: [
119
+ /menu/i, /dropdown.?menu/i, /context.?menu/i, /options/i, /opções/i, /opcoes/i,
120
+ ],
121
+ datepicker: [
122
+ /date/i, /data/i, /calendar/i, /calendário/i, /calendario/i,
123
+ /picker/i,
124
+ ],
125
+ timepicker: [
126
+ /time/i, /hora/i, /horário/i, /horario/i, /clock/i, /relógio/i, /relogio/i,
127
+ ],
128
+ upload: [
129
+ /upload/i, /file/i, /arquivo/i, /anexo/i, /attachment/i,
130
+ /drop.?zone/i, /drag/i, /arrastar/i,
131
+ ],
132
+ };
133
+ const VISUAL_HEURISTICS = {
134
+ button: {
135
+ minWidth: 60,
136
+ maxWidth: 400,
137
+ minHeight: 28,
138
+ maxHeight: 80,
139
+ hasCornerRadius: true,
140
+ minCornerRadius: 2,
141
+ hasFill: true,
142
+ hasText: true,
143
+ childrenCount: { min: 0, max: 3 },
144
+ },
145
+ input: {
146
+ minWidth: 100,
147
+ maxWidth: 600,
148
+ minHeight: 28,
149
+ maxHeight: 80,
150
+ hasCornerRadius: true,
151
+ hasStroke: true,
152
+ childrenCount: { min: 0, max: 4 },
153
+ },
154
+ card: {
155
+ minWidth: 150,
156
+ minHeight: 100,
157
+ hasCornerRadius: true,
158
+ hasFill: true,
159
+ hasDropShadow: true,
160
+ childrenCount: { min: 1, max: 20 },
161
+ },
162
+ avatar: {
163
+ aspectRatio: { min: 0.8, max: 1.2 },
164
+ minWidth: 24,
165
+ maxWidth: 200,
166
+ minCornerRadius: 12, // Usually circular
167
+ hasFill: true,
168
+ },
169
+ checkbox: {
170
+ minWidth: 14,
171
+ maxWidth: 32,
172
+ minHeight: 14,
173
+ maxHeight: 32,
174
+ aspectRatio: { min: 0.8, max: 1.2 },
175
+ hasStroke: true,
176
+ },
177
+ switch: {
178
+ minWidth: 36,
179
+ maxWidth: 80,
180
+ minHeight: 16,
181
+ maxHeight: 40,
182
+ aspectRatio: { min: 1.5, max: 3 },
183
+ hasCornerRadius: true,
184
+ minCornerRadius: 8,
185
+ hasFill: true,
186
+ },
187
+ icon: {
188
+ minWidth: 12,
189
+ maxWidth: 64,
190
+ minHeight: 12,
191
+ maxHeight: 64,
192
+ aspectRatio: { min: 0.5, max: 2 },
193
+ childrenCount: { min: 0, max: 5 },
194
+ },
195
+ badge: {
196
+ minWidth: 16,
197
+ maxWidth: 120,
198
+ minHeight: 16,
199
+ maxHeight: 40,
200
+ hasCornerRadius: true,
201
+ minCornerRadius: 4,
202
+ hasFill: true,
203
+ hasText: true,
204
+ childrenCount: { min: 0, max: 2 },
205
+ },
206
+ divider: {
207
+ minWidth: 50,
208
+ minHeight: 1,
209
+ maxHeight: 4,
210
+ },
211
+ modal: {
212
+ minWidth: 280,
213
+ minHeight: 150,
214
+ hasCornerRadius: true,
215
+ hasFill: true,
216
+ hasDropShadow: true,
217
+ childrenCount: { min: 1, max: 30 },
218
+ },
219
+ progress: {
220
+ minWidth: 80,
221
+ minHeight: 4,
222
+ maxHeight: 24,
223
+ hasCornerRadius: true,
224
+ hasFill: true,
225
+ },
226
+ };
227
+ /**
228
+ * Check if node has a fill
229
+ */
230
+ function hasFill(node) {
231
+ if (!node.fills || node.fills.length === 0)
232
+ return false;
233
+ return node.fills.some((fill) => fill.type === 'SOLID' || fill.type === 'IMAGE');
234
+ }
235
+ /**
236
+ * Check if node has a stroke
237
+ */
238
+ function hasStroke(node) {
239
+ return !!(node.strokes && node.strokes.length > 0 && node.strokeWeight && node.strokeWeight > 0);
240
+ }
241
+ /**
242
+ * Check if node has drop shadow
243
+ */
244
+ function hasDropShadow(node) {
245
+ if (!node.effects)
246
+ return false;
247
+ return node.effects.some((effect) => effect.type === 'DROP_SHADOW' && effect.visible);
248
+ }
249
+ /**
250
+ * Check if node has text content (direct or in children)
251
+ */
252
+ function hasText(node) {
253
+ if (node.type === 'TEXT' && node.characters)
254
+ return true;
255
+ if (node.children) {
256
+ return node.children.some(child => hasText(child));
257
+ }
258
+ return false;
259
+ }
260
+ /**
261
+ * Count direct children
262
+ */
263
+ function countChildren(node) {
264
+ return node.children?.length || 0;
265
+ }
266
+ /**
267
+ * Get node dimensions
268
+ */
269
+ function getDimensions(node) {
270
+ if (!node.absoluteBoundingBox)
271
+ return null;
272
+ return {
273
+ width: node.absoluteBoundingBox.width,
274
+ height: node.absoluteBoundingBox.height,
275
+ };
276
+ }
277
+ /**
278
+ * Strategy 1: Fuzzy name matching
279
+ */
280
+ function detectByName(name) {
281
+ const normalizedName = name.toLowerCase().trim();
282
+ for (const [componentType, patterns] of Object.entries(NAME_PATTERNS)) {
283
+ for (const pattern of patterns) {
284
+ if (pattern.test(normalizedName)) {
285
+ // Calculate confidence based on match specificity
286
+ const matchStr = normalizedName.match(pattern)?.[0] || '';
287
+ const confidence = matchStr.length / normalizedName.length;
288
+ return {
289
+ componentType,
290
+ confidence: Math.min(0.9, 0.5 + confidence * 0.4), // 0.5-0.9 range
291
+ strategy: 'name',
292
+ details: `Matched pattern: ${pattern.source}`,
293
+ };
294
+ }
295
+ }
296
+ }
297
+ return null;
298
+ }
299
+ /**
300
+ * Strategy 2: Visual property heuristics
301
+ */
302
+ function detectByVisual(node) {
303
+ const dimensions = getDimensions(node);
304
+ if (!dimensions)
305
+ return null;
306
+ const { width, height } = dimensions;
307
+ const aspectRatio = width / height;
308
+ const cornerRadius = node.cornerRadius || 0;
309
+ const childCount = countChildren(node);
310
+ const scores = [];
311
+ for (const [componentType, heuristics] of Object.entries(VISUAL_HEURISTICS)) {
312
+ let score = 0;
313
+ let checks = 0;
314
+ // Width check
315
+ if (heuristics.minWidth !== undefined) {
316
+ checks++;
317
+ if (width >= heuristics.minWidth)
318
+ score++;
319
+ }
320
+ if (heuristics.maxWidth !== undefined) {
321
+ checks++;
322
+ if (width <= heuristics.maxWidth)
323
+ score++;
324
+ }
325
+ // Height check
326
+ if (heuristics.minHeight !== undefined) {
327
+ checks++;
328
+ if (height >= heuristics.minHeight)
329
+ score++;
330
+ }
331
+ if (heuristics.maxHeight !== undefined) {
332
+ checks++;
333
+ if (height <= heuristics.maxHeight)
334
+ score++;
335
+ }
336
+ // Aspect ratio check
337
+ if (heuristics.aspectRatio) {
338
+ checks++;
339
+ if (aspectRatio >= heuristics.aspectRatio.min && aspectRatio <= heuristics.aspectRatio.max) {
340
+ score++;
341
+ }
342
+ }
343
+ // Corner radius checks
344
+ if (heuristics.hasCornerRadius !== undefined) {
345
+ checks++;
346
+ if ((cornerRadius > 0) === heuristics.hasCornerRadius)
347
+ score++;
348
+ }
349
+ if (heuristics.minCornerRadius !== undefined) {
350
+ checks++;
351
+ if (cornerRadius >= heuristics.minCornerRadius)
352
+ score++;
353
+ }
354
+ if (heuristics.maxCornerRadius !== undefined) {
355
+ checks++;
356
+ if (cornerRadius <= heuristics.maxCornerRadius)
357
+ score++;
358
+ }
359
+ // Fill check
360
+ if (heuristics.hasFill !== undefined) {
361
+ checks++;
362
+ if (hasFill(node) === heuristics.hasFill)
363
+ score++;
364
+ }
365
+ // Stroke check
366
+ if (heuristics.hasStroke !== undefined) {
367
+ checks++;
368
+ if (hasStroke(node) === heuristics.hasStroke)
369
+ score++;
370
+ }
371
+ // Drop shadow check
372
+ if (heuristics.hasDropShadow !== undefined) {
373
+ checks++;
374
+ if (hasDropShadow(node) === heuristics.hasDropShadow)
375
+ score++;
376
+ }
377
+ // Text check
378
+ if (heuristics.hasText !== undefined) {
379
+ checks++;
380
+ if (hasText(node) === heuristics.hasText)
381
+ score++;
382
+ }
383
+ // Children count check
384
+ if (heuristics.childrenCount) {
385
+ checks++;
386
+ if (childCount >= heuristics.childrenCount.min && childCount <= heuristics.childrenCount.max) {
387
+ score++;
388
+ }
389
+ }
390
+ // Layout mode check
391
+ if (heuristics.layoutMode !== undefined) {
392
+ checks++;
393
+ if (node.layoutMode === heuristics.layoutMode)
394
+ score++;
395
+ }
396
+ if (checks > 0) {
397
+ scores.push({ type: componentType, score: score / checks });
398
+ }
399
+ }
400
+ // Get best match
401
+ scores.sort((a, b) => b.score - a.score);
402
+ if (scores.length > 0 && scores[0].score >= 0.5) {
403
+ return {
404
+ componentType: scores[0].type,
405
+ confidence: scores[0].score * 0.8, // Max 0.8 for visual-only
406
+ strategy: 'visual',
407
+ details: `Visual score: ${(scores[0].score * 100).toFixed(0)}%`,
408
+ };
409
+ }
410
+ return null;
411
+ }
412
+ /**
413
+ * Strategy 3: Structure-based detection
414
+ */
415
+ function detectByStructure(node) {
416
+ const childCount = countChildren(node);
417
+ const hasLayout = node.layoutMode && node.layoutMode !== 'NONE';
418
+ // Form detection: multiple input-like children
419
+ if (childCount >= 2 && hasLayout && node.layoutMode === 'VERTICAL') {
420
+ const inputLikeChildren = node.children?.filter(child => {
421
+ const childDim = getDimensions(child);
422
+ return childDim && childDim.width > 100 && childDim.height >= 28 && childDim.height <= 60;
423
+ }) || [];
424
+ if (inputLikeChildren.length >= 2) {
425
+ return {
426
+ componentType: 'form',
427
+ confidence: 0.6,
428
+ strategy: 'structure',
429
+ details: `${inputLikeChildren.length} input-like children in vertical layout`,
430
+ };
431
+ }
432
+ }
433
+ // Table detection: grid-like structure
434
+ if (childCount >= 3 && node.layoutMode === 'VERTICAL') {
435
+ const firstChild = node.children?.[0];
436
+ if (firstChild?.layoutMode === 'HORIZONTAL' && firstChild.children?.length) {
437
+ const cellCount = firstChild.children.length;
438
+ const rowsWithSameCells = node.children?.filter(child => child.layoutMode === 'HORIZONTAL' && child.children?.length === cellCount).length || 0;
439
+ if (rowsWithSameCells >= 2) {
440
+ return {
441
+ componentType: 'table',
442
+ confidence: 0.7,
443
+ strategy: 'structure',
444
+ details: `Grid-like structure with ${rowsWithSameCells} rows of ${cellCount} cells`,
445
+ };
446
+ }
447
+ }
448
+ }
449
+ // Tabs detection: horizontal layout with similar-sized children
450
+ if (childCount >= 2 && node.layoutMode === 'HORIZONTAL') {
451
+ const childWidths = node.children?.map(child => getDimensions(child)?.width || 0) || [];
452
+ const avgWidth = childWidths.reduce((a, b) => a + b, 0) / childWidths.length;
453
+ const similarWidths = childWidths.every(w => Math.abs(w - avgWidth) < avgWidth * 0.3);
454
+ if (similarWidths && avgWidth > 50) {
455
+ return {
456
+ componentType: 'tabs',
457
+ confidence: 0.5,
458
+ strategy: 'structure',
459
+ details: `${childCount} similarly-sized horizontal items`,
460
+ };
461
+ }
462
+ }
463
+ // Navigation/menu detection: vertical list with many items
464
+ if (childCount >= 4 && node.layoutMode === 'VERTICAL') {
465
+ const textChildren = node.children?.filter(child => hasText(child)).length || 0;
466
+ if (textChildren >= 3) {
467
+ return {
468
+ componentType: 'menu',
469
+ confidence: 0.5,
470
+ strategy: 'structure',
471
+ details: `Vertical list with ${textChildren} text items`,
472
+ };
473
+ }
474
+ }
475
+ return null;
476
+ }
477
+ /**
478
+ * Main detection function - combines all strategies
479
+ */
480
+ export function detectComponentType(node) {
481
+ // Try all strategies
482
+ const nameResult = detectByName(node.name);
483
+ const visualResult = detectByVisual(node);
484
+ const structureResult = detectByStructure(node);
485
+ // Combine results
486
+ const results = [nameResult, visualResult, structureResult].filter(Boolean);
487
+ if (results.length === 0) {
488
+ // Fallback: use node type
489
+ if (node.type === 'TEXT') {
490
+ return {
491
+ componentType: 'text',
492
+ confidence: 0.8,
493
+ strategy: 'visual',
494
+ details: 'Figma TEXT node',
495
+ };
496
+ }
497
+ // Default to container/div
498
+ return {
499
+ componentType: 'container',
500
+ confidence: 0.3,
501
+ strategy: 'visual',
502
+ details: 'No specific component detected',
503
+ };
504
+ }
505
+ // If multiple strategies agree, boost confidence
506
+ const typeVotes = {};
507
+ for (const result of results) {
508
+ if (!typeVotes[result.componentType]) {
509
+ typeVotes[result.componentType] = { count: 0, totalConfidence: 0, results: [] };
510
+ }
511
+ typeVotes[result.componentType].count++;
512
+ typeVotes[result.componentType].totalConfidence += result.confidence;
513
+ typeVotes[result.componentType].results.push(result);
514
+ }
515
+ // Find best type
516
+ let bestType = '';
517
+ let bestScore = 0;
518
+ for (const [type, data] of Object.entries(typeVotes)) {
519
+ // Score = average confidence * (1 + 0.2 * agreement bonus)
520
+ const avgConfidence = data.totalConfidence / data.count;
521
+ const agreementBonus = (data.count - 1) * 0.2;
522
+ const score = avgConfidence * (1 + agreementBonus);
523
+ if (score > bestScore) {
524
+ bestScore = score;
525
+ bestType = type;
526
+ }
527
+ }
528
+ const bestData = typeVotes[bestType];
529
+ const strategies = bestData.results.map(r => r.strategy).join('+');
530
+ return {
531
+ componentType: bestType,
532
+ confidence: Math.min(0.95, bestScore),
533
+ strategy: bestData.count > 1 ? 'hybrid' : bestData.results[0].strategy,
534
+ details: `${strategies}: ${bestData.results.map(r => r.details).join('; ')}`,
535
+ };
536
+ }
537
+ /**
538
+ * Detect all components in a tree
539
+ */
540
+ export function detectComponentsInTree(node, results = new Map()) {
541
+ const detection = detectComponentType(node);
542
+ results.set(node.id, detection);
543
+ if (node.children) {
544
+ for (const child of node.children) {
545
+ detectComponentsInTree(child, results);
546
+ }
547
+ }
548
+ return results;
549
+ }
550
+ /**
551
+ * Get component type with fallback to raw CSS generation
552
+ */
553
+ export function getComponentTypeOrRaw(node) {
554
+ const result = detectComponentType(node);
555
+ // If confidence is too low, suggest raw CSS generation
556
+ if (result.confidence < 0.4) {
557
+ return { type: 'raw' };
558
+ }
559
+ return {
560
+ type: 'component',
561
+ componentType: result.componentType,
562
+ confidence: result.confidence,
563
+ };
564
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Component Detection Module
3
+ * Intelligent detection of UI components from Figma nodes
4
+ */
5
+ export { detectComponentType, detectComponentsInTree, getComponentTypeOrRaw, type IDetectionResult, } from './component-detector.js';
6
+ export { generateRawCSS, cssToInlineStyle, cssToReactStyle, cssToBlock, cssToTailwind, } from './raw-css-generator.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,aAAa,GACd,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Component Detection Module
3
+ * Intelligent detection of UI components from Figma nodes
4
+ */
5
+ export { detectComponentType, detectComponentsInTree, getComponentTypeOrRaw, } from './component-detector.js';
6
+ export { generateRawCSS, cssToInlineStyle, cssToReactStyle, cssToBlock, cssToTailwind, } from './raw-css-generator.js';
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Raw CSS Generator
3
+ * Generates pixel-perfect CSS from Figma node properties
4
+ * Used when no specific component type is detected
5
+ */
6
+ import type { IFigmaNode } from '@promptui-lib/core';
7
+ /**
8
+ * Generate all CSS properties from Figma node
9
+ */
10
+ export declare function generateRawCSS(node: IFigmaNode): Record<string, string>;
11
+ /**
12
+ * Convert CSS object to inline style string
13
+ */
14
+ export declare function cssToInlineStyle(css: Record<string, string>): string;
15
+ /**
16
+ * Convert CSS object to React style object string
17
+ */
18
+ export declare function cssToReactStyle(css: Record<string, string>): string;
19
+ /**
20
+ * Convert CSS object to SCSS/CSS block
21
+ */
22
+ export declare function cssToBlock(css: Record<string, string>, selector: string, indent?: number): string;
23
+ /**
24
+ * Generate Tailwind classes from CSS (approximation)
25
+ */
26
+ export declare function cssToTailwind(css: Record<string, string>): string[];
27
+ //# sourceMappingURL=raw-css-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-css-generator.d.ts","sourceRoot":"","sources":["../../src/detection/raw-css-generator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAyC,MAAM,oBAAoB,CAAC;AA4M5F;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0GvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAQpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAGnE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,CAQpG;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CA0InE"}