@promptui-lib/codegen 0.1.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.
- package/dist/frameworks/bootstrap.template.d.ts +10 -0
- package/dist/frameworks/bootstrap.template.d.ts.map +1 -0
- package/dist/frameworks/bootstrap.template.js +294 -0
- package/dist/frameworks/index.d.ts +19 -0
- package/dist/frameworks/index.d.ts.map +1 -0
- package/dist/frameworks/index.js +45 -0
- package/dist/frameworks/mui.template.d.ts +14 -0
- package/dist/frameworks/mui.template.d.ts.map +1 -0
- package/dist/frameworks/mui.template.js +304 -0
- package/dist/frameworks/tailwind.template.d.ts +14 -0
- package/dist/frameworks/tailwind.template.d.ts.map +1 -0
- package/dist/frameworks/tailwind.template.js +286 -0
- package/dist/generators/index.d.ts +3 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +2 -0
- package/dist/generators/scss-generator.d.ts +14 -0
- package/dist/generators/scss-generator.d.ts.map +1 -0
- package/dist/generators/scss-generator.js +116 -0
- package/dist/generators/tsx-generator.d.ts +14 -0
- package/dist/generators/tsx-generator.d.ts.map +1 -0
- package/dist/generators/tsx-generator.js +152 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/writers/file-writer.d.ts +35 -0
- package/dist/writers/file-writer.d.ts.map +1 -0
- package/dist/writers/file-writer.js +102 -0
- package/dist/writers/index.d.ts +3 -0
- package/dist/writers/index.d.ts.map +1 -0
- package/dist/writers/index.js +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Material UI Template
|
|
3
|
+
* Gera componentes React com MUI sx props
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Mapeamento de tokens SCSS → MUI theme
|
|
7
|
+
*/
|
|
8
|
+
const TOKEN_TO_MUI = {
|
|
9
|
+
// Colors
|
|
10
|
+
'$color-primary': 'primary.main',
|
|
11
|
+
'$color-secondary': 'secondary.main',
|
|
12
|
+
'$color-success': 'success.main',
|
|
13
|
+
'$color-error': 'error.main',
|
|
14
|
+
'$color-warning': 'warning.main',
|
|
15
|
+
'$color-text-primary': 'text.primary',
|
|
16
|
+
'$color-text-secondary': 'text.secondary',
|
|
17
|
+
'$color-bg-primary': 'background.paper',
|
|
18
|
+
'$color-bg-secondary': 'background.default',
|
|
19
|
+
// Spacing (MUI usa múltiplos de 8px)
|
|
20
|
+
'$spacing-xs': 0.5, // 4px
|
|
21
|
+
'$spacing-sm': 1, // 8px
|
|
22
|
+
'$spacing-md': 2, // 16px
|
|
23
|
+
'$spacing-lg': 3, // 24px
|
|
24
|
+
'$spacing-xl': 4, // 32px
|
|
25
|
+
'$spacing-2xl': 6, // 48px
|
|
26
|
+
// Border radius
|
|
27
|
+
'$radius-none': 0,
|
|
28
|
+
'$radius-small': 0.5,
|
|
29
|
+
'$radius-medium': 1,
|
|
30
|
+
'$radius-large': 1.5,
|
|
31
|
+
'$radius-xl': 2,
|
|
32
|
+
'$radius-full': '50%',
|
|
33
|
+
// Typography
|
|
34
|
+
'$font-size-xs': 'caption.fontSize',
|
|
35
|
+
'$font-size-sm': 'body2.fontSize',
|
|
36
|
+
'$font-size-md': 'body1.fontSize',
|
|
37
|
+
'$font-size-lg': 'h6.fontSize',
|
|
38
|
+
'$font-size-xl': 'h5.fontSize',
|
|
39
|
+
'$font-size-2xl': 'h4.fontSize',
|
|
40
|
+
'$font-size-h1': 'h1.fontSize',
|
|
41
|
+
'$font-size-h2': 'h2.fontSize',
|
|
42
|
+
// Shadows
|
|
43
|
+
'$shadow-sm': 1,
|
|
44
|
+
'$shadow-md': 2,
|
|
45
|
+
'$shadow-lg': 4,
|
|
46
|
+
'$shadow-modal': 8,
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Converte propriedade CSS para sx prop
|
|
50
|
+
*/
|
|
51
|
+
function cssToSx(property, value) {
|
|
52
|
+
// Mapeamento de propriedades CSS → sx
|
|
53
|
+
const propMap = {
|
|
54
|
+
'display': 'display',
|
|
55
|
+
'flex-direction': 'flexDirection',
|
|
56
|
+
'align-items': 'alignItems',
|
|
57
|
+
'justify-content': 'justifyContent',
|
|
58
|
+
'gap': 'gap',
|
|
59
|
+
'padding': 'p',
|
|
60
|
+
'padding-top': 'pt',
|
|
61
|
+
'padding-bottom': 'pb',
|
|
62
|
+
'padding-left': 'pl',
|
|
63
|
+
'padding-right': 'pr',
|
|
64
|
+
'margin': 'm',
|
|
65
|
+
'margin-top': 'mt',
|
|
66
|
+
'margin-bottom': 'mb',
|
|
67
|
+
'margin-left': 'ml',
|
|
68
|
+
'margin-right': 'mr',
|
|
69
|
+
'width': 'width',
|
|
70
|
+
'height': 'height',
|
|
71
|
+
'min-width': 'minWidth',
|
|
72
|
+
'max-width': 'maxWidth',
|
|
73
|
+
'min-height': 'minHeight',
|
|
74
|
+
'max-height': 'maxHeight',
|
|
75
|
+
'background-color': 'bgcolor',
|
|
76
|
+
'color': 'color',
|
|
77
|
+
'border-radius': 'borderRadius',
|
|
78
|
+
'border': 'border',
|
|
79
|
+
'border-color': 'borderColor',
|
|
80
|
+
'box-shadow': 'boxShadow',
|
|
81
|
+
'font-family': 'fontFamily',
|
|
82
|
+
'font-size': 'fontSize',
|
|
83
|
+
'font-weight': 'fontWeight',
|
|
84
|
+
'line-height': 'lineHeight',
|
|
85
|
+
'text-align': 'textAlign',
|
|
86
|
+
'overflow': 'overflow',
|
|
87
|
+
'position': 'position',
|
|
88
|
+
'top': 'top',
|
|
89
|
+
'bottom': 'bottom',
|
|
90
|
+
'left': 'left',
|
|
91
|
+
'right': 'right',
|
|
92
|
+
'z-index': 'zIndex',
|
|
93
|
+
'cursor': 'cursor',
|
|
94
|
+
'opacity': 'opacity',
|
|
95
|
+
};
|
|
96
|
+
const sxKey = propMap[property] ?? property;
|
|
97
|
+
// Converte valor de token para MUI
|
|
98
|
+
if (value.startsWith('$')) {
|
|
99
|
+
const muiValue = TOKEN_TO_MUI[value];
|
|
100
|
+
if (muiValue !== undefined) {
|
|
101
|
+
return { key: sxKey, value: muiValue };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Remove 'px' de valores numéricos para spacing
|
|
105
|
+
if (['p', 'pt', 'pb', 'pl', 'pr', 'm', 'mt', 'mb', 'ml', 'mr', 'gap'].includes(sxKey)) {
|
|
106
|
+
const numValue = parseInt(value);
|
|
107
|
+
if (!isNaN(numValue)) {
|
|
108
|
+
// Converte px para unidades MUI (múltiplos de 8)
|
|
109
|
+
return { key: sxKey, value: numValue / 8 };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { key: sxKey, value };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Converte array de estilos para objeto sx
|
|
116
|
+
*/
|
|
117
|
+
function stylesToSx(styles) {
|
|
118
|
+
const sx = {};
|
|
119
|
+
for (const style of styles) {
|
|
120
|
+
const { key, value } = cssToSx(style.property, style.token ?? style.value);
|
|
121
|
+
sx[key] = value;
|
|
122
|
+
}
|
|
123
|
+
return sx;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Formata objeto sx como string
|
|
127
|
+
*/
|
|
128
|
+
function formatSx(sx, indent = 2) {
|
|
129
|
+
const spaces = ' '.repeat(indent);
|
|
130
|
+
const entries = Object.entries(sx);
|
|
131
|
+
if (entries.length === 0)
|
|
132
|
+
return '{}';
|
|
133
|
+
const lines = entries.map(([key, value]) => {
|
|
134
|
+
if (typeof value === 'string') {
|
|
135
|
+
// Verifica se é referência ao theme
|
|
136
|
+
if (value.includes('.')) {
|
|
137
|
+
return `${spaces} ${key}: '${value}',`;
|
|
138
|
+
}
|
|
139
|
+
return `${spaces} ${key}: '${value}',`;
|
|
140
|
+
}
|
|
141
|
+
return `${spaces} ${key}: ${value},`;
|
|
142
|
+
});
|
|
143
|
+
return `{\n${lines.join('\n')}\n${spaces}}`;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Determina o componente MUI apropriado baseado no tipo
|
|
147
|
+
*/
|
|
148
|
+
function getMuiComponent(node, isRoot) {
|
|
149
|
+
// Button
|
|
150
|
+
if (node.tag === 'button') {
|
|
151
|
+
return 'Button';
|
|
152
|
+
}
|
|
153
|
+
// Text
|
|
154
|
+
if (node.tag === 'span' || node.tag === 'p' || node.tag === 'h1' || node.tag === 'h2' || node.tag === 'h3') {
|
|
155
|
+
return 'Typography';
|
|
156
|
+
}
|
|
157
|
+
// Container com flex
|
|
158
|
+
if (node.props && Object.keys(node.props).length > 0) {
|
|
159
|
+
return 'Stack';
|
|
160
|
+
}
|
|
161
|
+
// Default
|
|
162
|
+
return 'Box';
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Gera props adicionais do MUI baseado no contexto
|
|
166
|
+
*/
|
|
167
|
+
function getMuiProps(node, componentType) {
|
|
168
|
+
const props = [];
|
|
169
|
+
if (componentType === 'Button') {
|
|
170
|
+
props.push('variant="contained"');
|
|
171
|
+
}
|
|
172
|
+
if (componentType === 'Typography') {
|
|
173
|
+
// Determina variante baseado no contexto
|
|
174
|
+
const className = node.className ?? '';
|
|
175
|
+
if (className.includes('title') || className.includes('heading')) {
|
|
176
|
+
props.push('variant="h6"');
|
|
177
|
+
}
|
|
178
|
+
else if (className.includes('label')) {
|
|
179
|
+
props.push('variant="body2"');
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
props.push('variant="body1"');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (componentType === 'Stack') {
|
|
186
|
+
props.push('direction="row"');
|
|
187
|
+
props.push('spacing={1}');
|
|
188
|
+
}
|
|
189
|
+
return props;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Gera JSX com componentes MUI
|
|
193
|
+
*/
|
|
194
|
+
function generateMuiJSX(node, styles, indent = 2) {
|
|
195
|
+
const spaces = ' '.repeat(indent);
|
|
196
|
+
const isRoot = indent === 2;
|
|
197
|
+
const muiComponent = getMuiComponent(node, isRoot);
|
|
198
|
+
const muiProps = getMuiProps(node, muiComponent);
|
|
199
|
+
const nodeStyles = styles.get(`.${node.className}`) ?? [];
|
|
200
|
+
const sx = stylesToSx(nodeStyles);
|
|
201
|
+
// Props string
|
|
202
|
+
const propsArray = [];
|
|
203
|
+
if (isRoot) {
|
|
204
|
+
propsArray.push(`className={\`${node.className} \${className}\`.trim()}`);
|
|
205
|
+
}
|
|
206
|
+
propsArray.push(...muiProps);
|
|
207
|
+
if (Object.keys(sx).length > 0) {
|
|
208
|
+
propsArray.push(`sx={${formatSx(sx, indent)}}`);
|
|
209
|
+
}
|
|
210
|
+
const propsStr = propsArray.length > 0 ? ` ${propsArray.join(' ')}` : '';
|
|
211
|
+
// Children
|
|
212
|
+
if (node.selfClosing) {
|
|
213
|
+
return `${spaces}<${muiComponent}${propsStr} />`;
|
|
214
|
+
}
|
|
215
|
+
const childrenContent = [];
|
|
216
|
+
for (const child of node.children) {
|
|
217
|
+
if (typeof child === 'string' || (typeof child === 'object' && 'type' in child && child.type === 'text')) {
|
|
218
|
+
const text = typeof child === 'string' ? child : child.value;
|
|
219
|
+
childrenContent.push(`${spaces} {children ?? '${text}'}`);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
childrenContent.push(generateMuiJSX(child, styles, indent + 2));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (childrenContent.length === 0) {
|
|
226
|
+
return `${spaces}<${muiComponent}${propsStr} />`;
|
|
227
|
+
}
|
|
228
|
+
return [
|
|
229
|
+
`${spaces}<${muiComponent}${propsStr}>`,
|
|
230
|
+
...childrenContent,
|
|
231
|
+
`${spaces}</${muiComponent}>`,
|
|
232
|
+
].join('\n');
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Gera componente React com MUI
|
|
236
|
+
*/
|
|
237
|
+
export function generateMuiComponent(ast) {
|
|
238
|
+
// Cria mapa de estilos por selector
|
|
239
|
+
const stylesMap = new Map();
|
|
240
|
+
for (const block of ast.styles) {
|
|
241
|
+
stylesMap.set(block.selector, block.properties);
|
|
242
|
+
}
|
|
243
|
+
// Props interface
|
|
244
|
+
const propsInterface = `export interface I${ast.name}Props {
|
|
245
|
+
children?: ReactNode;
|
|
246
|
+
className?: string;
|
|
247
|
+
sx?: SxProps<Theme>;
|
|
248
|
+
}`;
|
|
249
|
+
// JSX
|
|
250
|
+
const jsx = generateMuiJSX(ast.jsx, stylesMap);
|
|
251
|
+
// Component
|
|
252
|
+
const component = `export const ${ast.name} = ({
|
|
253
|
+
children,
|
|
254
|
+
className = '',
|
|
255
|
+
sx: sxOverride,
|
|
256
|
+
}: I${ast.name}Props) => {
|
|
257
|
+
return (
|
|
258
|
+
${jsx}
|
|
259
|
+
);
|
|
260
|
+
};`;
|
|
261
|
+
// Imports
|
|
262
|
+
const imports = [
|
|
263
|
+
"import type { ReactNode } from 'react';",
|
|
264
|
+
"import { Box, Stack, Typography, Button } from '@mui/material';",
|
|
265
|
+
"import type { SxProps, Theme } from '@mui/material/styles';",
|
|
266
|
+
];
|
|
267
|
+
return [
|
|
268
|
+
'/**',
|
|
269
|
+
` * ${ast.name}`,
|
|
270
|
+
' * Generated by PromptUI (MUI)',
|
|
271
|
+
' */',
|
|
272
|
+
'',
|
|
273
|
+
...imports,
|
|
274
|
+
'',
|
|
275
|
+
propsInterface,
|
|
276
|
+
'',
|
|
277
|
+
component,
|
|
278
|
+
].join('\n');
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Gera arquivo de estilos (para MUI, retorna objeto de sx reusáveis)
|
|
282
|
+
*/
|
|
283
|
+
export function generateMuiStyles(ast) {
|
|
284
|
+
const styles = {};
|
|
285
|
+
for (const block of ast.styles) {
|
|
286
|
+
const className = block.selector.replace(/^\./, '').replace(/__/g, '_').replace(/--/g, '_');
|
|
287
|
+
styles[className] = stylesToSx(block.properties);
|
|
288
|
+
}
|
|
289
|
+
const stylesStr = Object.entries(styles)
|
|
290
|
+
.map(([key, value]) => ` ${key}: ${JSON.stringify(value, null, 2).replace(/\n/g, '\n ')},`)
|
|
291
|
+
.join('\n');
|
|
292
|
+
return [
|
|
293
|
+
'/**',
|
|
294
|
+
` * ${ast.name} Styles`,
|
|
295
|
+
' * Generated by PromptUI (MUI)',
|
|
296
|
+
' */',
|
|
297
|
+
'',
|
|
298
|
+
"import type { SxProps, Theme } from '@mui/material/styles';",
|
|
299
|
+
'',
|
|
300
|
+
`export const ${ast.fileName.replace(/-/g, '')}Styles: Record<string, SxProps<Theme>> = {`,
|
|
301
|
+
stylesStr,
|
|
302
|
+
'};',
|
|
303
|
+
].join('\n');
|
|
304
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailwind CSS Template
|
|
3
|
+
* Gera componentes React com classes Tailwind
|
|
4
|
+
*/
|
|
5
|
+
import type { IComponentAST, IStyleProperty } from '@promptui-lib/core';
|
|
6
|
+
/**
|
|
7
|
+
* Converte estilos para classes Tailwind
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateTailwindClasses(styles: IStyleProperty[]): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Gera componente React com Tailwind
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateTailwindComponent(ast: IComponentAST): string;
|
|
14
|
+
//# sourceMappingURL=tailwind.template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailwind.template.d.ts","sourceRoot":"","sources":["../../src/frameworks/tailwind.template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAY,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAuMlF;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,EAAE,CAY1E;AAuDD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAsCpE"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailwind CSS Template
|
|
3
|
+
* Gera componentes React com classes Tailwind
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Mapeamento de tokens SCSS → Tailwind classes
|
|
7
|
+
*/
|
|
8
|
+
const TOKEN_TO_TAILWIND = {
|
|
9
|
+
// Colors - Background
|
|
10
|
+
'$color-primary': 'bg-blue-500',
|
|
11
|
+
'$color-secondary': 'bg-gray-500',
|
|
12
|
+
'$color-success': 'bg-green-500',
|
|
13
|
+
'$color-error': 'bg-red-500',
|
|
14
|
+
'$color-warning': 'bg-yellow-500',
|
|
15
|
+
'$color-bg-primary': 'bg-white',
|
|
16
|
+
'$color-bg-secondary': 'bg-gray-50',
|
|
17
|
+
'$color-bg-tertiary': 'bg-gray-100',
|
|
18
|
+
// Colors - Text
|
|
19
|
+
'$color-text-primary': 'text-gray-900',
|
|
20
|
+
'$color-text-secondary': 'text-gray-600',
|
|
21
|
+
'$color-text-tertiary': 'text-gray-400',
|
|
22
|
+
'$color-text-inverse': 'text-white',
|
|
23
|
+
// Border colors
|
|
24
|
+
'$color-border': 'border-gray-200',
|
|
25
|
+
'$color-border-primary': 'border-gray-300',
|
|
26
|
+
// Spacing
|
|
27
|
+
'$spacing-xs': '1', // 4px = 0.25rem
|
|
28
|
+
'$spacing-sm': '2', // 8px = 0.5rem
|
|
29
|
+
'$spacing-md': '4', // 16px = 1rem
|
|
30
|
+
'$spacing-lg': '6', // 24px = 1.5rem
|
|
31
|
+
'$spacing-xl': '8', // 32px = 2rem
|
|
32
|
+
'$spacing-2xl': '12', // 48px = 3rem
|
|
33
|
+
// Border radius
|
|
34
|
+
'$radius-none': 'rounded-none',
|
|
35
|
+
'$radius-small': 'rounded',
|
|
36
|
+
'$radius-medium': 'rounded-md',
|
|
37
|
+
'$radius-large': 'rounded-lg',
|
|
38
|
+
'$radius-xl': 'rounded-xl',
|
|
39
|
+
'$radius-full': 'rounded-full',
|
|
40
|
+
// Font sizes
|
|
41
|
+
'$font-size-xs': 'text-xs',
|
|
42
|
+
'$font-size-sm': 'text-sm',
|
|
43
|
+
'$font-size-md': 'text-base',
|
|
44
|
+
'$font-size-lg': 'text-lg',
|
|
45
|
+
'$font-size-xl': 'text-xl',
|
|
46
|
+
'$font-size-2xl': 'text-2xl',
|
|
47
|
+
'$font-size-h1': 'text-3xl',
|
|
48
|
+
'$font-size-h2': 'text-2xl',
|
|
49
|
+
// Font weights
|
|
50
|
+
'$font-weight-regular': 'font-normal',
|
|
51
|
+
'$font-weight-medium': 'font-medium',
|
|
52
|
+
'$font-weight-semibold': 'font-semibold',
|
|
53
|
+
'$font-weight-bold': 'font-bold',
|
|
54
|
+
// Shadows
|
|
55
|
+
'$shadow-sm': 'shadow-sm',
|
|
56
|
+
'$shadow-md': 'shadow',
|
|
57
|
+
'$shadow-lg': 'shadow-lg',
|
|
58
|
+
'$shadow-modal': 'shadow-xl',
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Mapeamento de propriedades CSS → prefixo Tailwind
|
|
62
|
+
*/
|
|
63
|
+
const CSS_TO_TAILWIND_PREFIX = {
|
|
64
|
+
'display': '',
|
|
65
|
+
'flex-direction': 'flex-',
|
|
66
|
+
'align-items': 'items-',
|
|
67
|
+
'justify-content': 'justify-',
|
|
68
|
+
'gap': 'gap-',
|
|
69
|
+
'padding': 'p-',
|
|
70
|
+
'padding-top': 'pt-',
|
|
71
|
+
'padding-bottom': 'pb-',
|
|
72
|
+
'padding-left': 'pl-',
|
|
73
|
+
'padding-right': 'pr-',
|
|
74
|
+
'margin': 'm-',
|
|
75
|
+
'margin-top': 'mt-',
|
|
76
|
+
'margin-bottom': 'mb-',
|
|
77
|
+
'margin-left': 'ml-',
|
|
78
|
+
'margin-right': 'mr-',
|
|
79
|
+
'width': 'w-',
|
|
80
|
+
'height': 'h-',
|
|
81
|
+
'min-width': 'min-w-',
|
|
82
|
+
'max-width': 'max-w-',
|
|
83
|
+
'min-height': 'min-h-',
|
|
84
|
+
'max-height': 'max-h-',
|
|
85
|
+
'background-color': 'bg-',
|
|
86
|
+
'color': 'text-',
|
|
87
|
+
'border-radius': '',
|
|
88
|
+
'border': 'border',
|
|
89
|
+
'border-color': 'border-',
|
|
90
|
+
'font-size': '',
|
|
91
|
+
'font-weight': '',
|
|
92
|
+
'line-height': 'leading-',
|
|
93
|
+
'text-align': 'text-',
|
|
94
|
+
'overflow': 'overflow-',
|
|
95
|
+
'cursor': 'cursor-',
|
|
96
|
+
'opacity': 'opacity-',
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Mapeamentos de valores CSS → Tailwind
|
|
100
|
+
*/
|
|
101
|
+
const CSS_VALUE_TO_TAILWIND = {
|
|
102
|
+
'display': {
|
|
103
|
+
'flex': 'flex',
|
|
104
|
+
'block': 'block',
|
|
105
|
+
'inline': 'inline',
|
|
106
|
+
'inline-flex': 'inline-flex',
|
|
107
|
+
'grid': 'grid',
|
|
108
|
+
'none': 'hidden',
|
|
109
|
+
},
|
|
110
|
+
'flex-direction': {
|
|
111
|
+
'row': 'row',
|
|
112
|
+
'column': 'col',
|
|
113
|
+
'row-reverse': 'row-reverse',
|
|
114
|
+
'column-reverse': 'col-reverse',
|
|
115
|
+
},
|
|
116
|
+
'align-items': {
|
|
117
|
+
'flex-start': 'start',
|
|
118
|
+
'flex-end': 'end',
|
|
119
|
+
'center': 'center',
|
|
120
|
+
'baseline': 'baseline',
|
|
121
|
+
'stretch': 'stretch',
|
|
122
|
+
},
|
|
123
|
+
'justify-content': {
|
|
124
|
+
'flex-start': 'start',
|
|
125
|
+
'flex-end': 'end',
|
|
126
|
+
'center': 'center',
|
|
127
|
+
'space-between': 'between',
|
|
128
|
+
'space-around': 'around',
|
|
129
|
+
'space-evenly': 'evenly',
|
|
130
|
+
},
|
|
131
|
+
'text-align': {
|
|
132
|
+
'left': 'left',
|
|
133
|
+
'center': 'center',
|
|
134
|
+
'right': 'right',
|
|
135
|
+
'justify': 'justify',
|
|
136
|
+
},
|
|
137
|
+
'cursor': {
|
|
138
|
+
'pointer': 'pointer',
|
|
139
|
+
'default': 'default',
|
|
140
|
+
'not-allowed': 'not-allowed',
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Converte propriedade CSS para classe Tailwind
|
|
145
|
+
*/
|
|
146
|
+
function cssToTailwind(property, value) {
|
|
147
|
+
// Se o valor é um token, usa mapeamento direto
|
|
148
|
+
if (value.startsWith('$')) {
|
|
149
|
+
const tailwindClass = TOKEN_TO_TAILWIND[value];
|
|
150
|
+
if (tailwindClass) {
|
|
151
|
+
// Verifica se precisa ajustar para a propriedade
|
|
152
|
+
if (property === 'color' && tailwindClass.startsWith('bg-')) {
|
|
153
|
+
return tailwindClass.replace('bg-', 'text-');
|
|
154
|
+
}
|
|
155
|
+
return tailwindClass;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Mapeamento de valores específicos
|
|
159
|
+
const valueMap = CSS_VALUE_TO_TAILWIND[property];
|
|
160
|
+
if (valueMap && valueMap[value]) {
|
|
161
|
+
const prefix = CSS_TO_TAILWIND_PREFIX[property] ?? '';
|
|
162
|
+
return `${prefix}${valueMap[value]}`;
|
|
163
|
+
}
|
|
164
|
+
// Para spacing, converte px para unidades Tailwind
|
|
165
|
+
if (['padding', 'margin', 'gap', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right', 'margin-top', 'margin-bottom', 'margin-left', 'margin-right'].includes(property)) {
|
|
166
|
+
const numValue = parseInt(value);
|
|
167
|
+
if (!isNaN(numValue)) {
|
|
168
|
+
const prefix = CSS_TO_TAILWIND_PREFIX[property] ?? '';
|
|
169
|
+
// Mapeia px para escala Tailwind (4px = 1, 8px = 2, etc.)
|
|
170
|
+
const scale = Math.round(numValue / 4);
|
|
171
|
+
return `${prefix}${scale}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Width/Height específicos
|
|
175
|
+
if (property === 'width') {
|
|
176
|
+
if (value === '100%')
|
|
177
|
+
return 'w-full';
|
|
178
|
+
if (value === 'fit-content')
|
|
179
|
+
return 'w-fit';
|
|
180
|
+
if (value === 'auto')
|
|
181
|
+
return 'w-auto';
|
|
182
|
+
}
|
|
183
|
+
if (property === 'height') {
|
|
184
|
+
if (value === '100%')
|
|
185
|
+
return 'h-full';
|
|
186
|
+
if (value === 'fit-content')
|
|
187
|
+
return 'h-fit';
|
|
188
|
+
if (value === 'auto')
|
|
189
|
+
return 'h-auto';
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Converte estilos para classes Tailwind
|
|
195
|
+
*/
|
|
196
|
+
export function generateTailwindClasses(styles) {
|
|
197
|
+
const classes = [];
|
|
198
|
+
for (const style of styles) {
|
|
199
|
+
const value = style.token ?? style.value;
|
|
200
|
+
const tailwindClass = cssToTailwind(style.property, value);
|
|
201
|
+
if (tailwindClass) {
|
|
202
|
+
classes.push(tailwindClass);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return classes;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Gera JSX com classes Tailwind
|
|
209
|
+
*/
|
|
210
|
+
function generateTailwindJSX(node, styles, indent = 2) {
|
|
211
|
+
const spaces = ' '.repeat(indent);
|
|
212
|
+
const isRoot = indent === 2;
|
|
213
|
+
const nodeStyles = styles.get(`.${node.className}`) ?? [];
|
|
214
|
+
const tailwindClasses = generateTailwindClasses(nodeStyles);
|
|
215
|
+
const classStr = tailwindClasses.join(' ');
|
|
216
|
+
// Props string
|
|
217
|
+
let className;
|
|
218
|
+
if (isRoot) {
|
|
219
|
+
className = `className={\`${classStr} \${className}\`.trim()}`;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
className = `className="${classStr}"`;
|
|
223
|
+
}
|
|
224
|
+
// Tag
|
|
225
|
+
const tag = node.tag;
|
|
226
|
+
// Children
|
|
227
|
+
if (node.selfClosing) {
|
|
228
|
+
return `${spaces}<${tag} ${className} />`;
|
|
229
|
+
}
|
|
230
|
+
const childrenContent = [];
|
|
231
|
+
for (const child of node.children) {
|
|
232
|
+
if (typeof child === 'string' || (typeof child === 'object' && 'type' in child && child.type === 'text')) {
|
|
233
|
+
const text = typeof child === 'string' ? child : child.value;
|
|
234
|
+
childrenContent.push(`${spaces} {children ?? '${text}'}`);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
childrenContent.push(generateTailwindJSX(child, styles, indent + 2));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (childrenContent.length === 0) {
|
|
241
|
+
return `${spaces}<${tag} ${className} />`;
|
|
242
|
+
}
|
|
243
|
+
return [
|
|
244
|
+
`${spaces}<${tag} ${className}>`,
|
|
245
|
+
...childrenContent,
|
|
246
|
+
`${spaces}</${tag}>`,
|
|
247
|
+
].join('\n');
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Gera componente React com Tailwind
|
|
251
|
+
*/
|
|
252
|
+
export function generateTailwindComponent(ast) {
|
|
253
|
+
// Cria mapa de estilos por selector
|
|
254
|
+
const stylesMap = new Map();
|
|
255
|
+
for (const block of ast.styles) {
|
|
256
|
+
stylesMap.set(block.selector, block.properties);
|
|
257
|
+
}
|
|
258
|
+
// Props interface
|
|
259
|
+
const propsInterface = `export interface I${ast.name}Props {
|
|
260
|
+
children?: ReactNode;
|
|
261
|
+
className?: string;
|
|
262
|
+
}`;
|
|
263
|
+
// JSX
|
|
264
|
+
const jsx = generateTailwindJSX(ast.jsx, stylesMap);
|
|
265
|
+
// Component
|
|
266
|
+
const component = `export const ${ast.name} = ({
|
|
267
|
+
children,
|
|
268
|
+
className = '',
|
|
269
|
+
}: I${ast.name}Props) => {
|
|
270
|
+
return (
|
|
271
|
+
${jsx}
|
|
272
|
+
);
|
|
273
|
+
};`;
|
|
274
|
+
return [
|
|
275
|
+
'/**',
|
|
276
|
+
` * ${ast.name}`,
|
|
277
|
+
' * Generated by PromptUI (Tailwind)',
|
|
278
|
+
' */',
|
|
279
|
+
'',
|
|
280
|
+
"import type { ReactNode } from 'react';",
|
|
281
|
+
'',
|
|
282
|
+
propsInterface,
|
|
283
|
+
'',
|
|
284
|
+
component,
|
|
285
|
+
].join('\n');
|
|
286
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCSS Generator
|
|
3
|
+
* Gera código SCSS com metodologia BEM a partir do AST
|
|
4
|
+
*/
|
|
5
|
+
import type { IComponentAST } from '@promptui-lib/core';
|
|
6
|
+
/**
|
|
7
|
+
* Gera código SCSS completo
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateSCSS(ast: IComponentAST): string;
|
|
10
|
+
/**
|
|
11
|
+
* Gera SCSS simples (não aninhado)
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateFlatSCSS(ast: IComponentAST): string;
|
|
14
|
+
//# sourceMappingURL=scss-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scss-generator.d.ts","sourceRoot":"","sources":["../../src/generators/scss-generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA+B,MAAM,oBAAoB,CAAC;AAoHrF;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAavD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAc3D"}
|