@wireweave/core 1.0.0-beta.20260107130839 → 1.0.0-beta.20260107133417
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/index.cjs +0 -1
- package/dist/index.js +0 -1
- package/dist/parser.cjs +0 -1
- package/dist/parser.js +0 -1
- package/dist/renderer.cjs +0 -1
- package/dist/renderer.js +0 -1
- package/package.json +7 -4
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/parser.cjs.map +0 -1
- package/dist/parser.js.map +0 -1
- package/dist/renderer.cjs.map +0 -1
- package/dist/renderer.js.map +0 -1
- package/src/ast/guards.ts +0 -361
- package/src/ast/index.ts +0 -9
- package/src/ast/types.ts +0 -661
- package/src/ast/utils.ts +0 -238
- package/src/grammar/wireframe.peggy +0 -677
- package/src/icons/lucide-icons.ts +0 -46422
- package/src/index.ts +0 -20
- package/src/parser/generated-parser.js +0 -5199
- package/src/parser/index.ts +0 -214
- package/src/renderer/html/base.ts +0 -186
- package/src/renderer/html/components.ts +0 -1092
- package/src/renderer/html/index.ts +0 -1608
- package/src/renderer/html/layout.ts +0 -392
- package/src/renderer/index.ts +0 -143
- package/src/renderer/styles-components.ts +0 -1232
- package/src/renderer/styles.ts +0 -382
- package/src/renderer/svg/index.ts +0 -1050
- package/src/renderer/types.ts +0 -173
- package/src/types/index.ts +0 -138
- package/src/viewport/index.ts +0 -17
- package/src/viewport/presets.ts +0 -181
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Layout Renderer for wireweave
|
|
3
|
-
*
|
|
4
|
-
* Dedicated renderers for layout and grid components:
|
|
5
|
-
* - Row/Col grid system with responsive breakpoints
|
|
6
|
-
* - Semantic layout elements (header, main, footer, sidebar, section)
|
|
7
|
-
* - Flexbox utilities
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
AnyNode,
|
|
12
|
-
RowNode,
|
|
13
|
-
ColNode,
|
|
14
|
-
HeaderNode,
|
|
15
|
-
MainNode,
|
|
16
|
-
FooterNode,
|
|
17
|
-
SidebarNode,
|
|
18
|
-
SectionNode,
|
|
19
|
-
CommonProps,
|
|
20
|
-
WidthValue,
|
|
21
|
-
HeightValue,
|
|
22
|
-
} from '../../ast/types';
|
|
23
|
-
import type { RenderContext, ThemeConfig } from '../types';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Type for node renderer callback
|
|
27
|
-
*/
|
|
28
|
-
export type NodeRenderer = (node: AnyNode) => string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Type for children renderer callback
|
|
32
|
-
*/
|
|
33
|
-
export type ChildrenRenderer = (children: AnyNode[]) => string;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Layout node types
|
|
37
|
-
*/
|
|
38
|
-
export type LayoutNodeType = 'Row' | 'Col' | 'Header' | 'Main' | 'Footer' | 'Sidebar' | 'Section';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Check if a node type is a layout node
|
|
42
|
-
*/
|
|
43
|
-
export function isLayoutNodeType(type: string): type is LayoutNodeType {
|
|
44
|
-
return ['Row', 'Col', 'Header', 'Main', 'Footer', 'Sidebar', 'Section'].includes(type);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Render a layout node
|
|
49
|
-
*/
|
|
50
|
-
export function renderLayoutNode(
|
|
51
|
-
node: AnyNode,
|
|
52
|
-
context: RenderContext,
|
|
53
|
-
renderChildren: ChildrenRenderer,
|
|
54
|
-
escapeHtml: (text: string) => string
|
|
55
|
-
): string {
|
|
56
|
-
switch (node.type) {
|
|
57
|
-
case 'Row':
|
|
58
|
-
return renderRow(node as RowNode, context, renderChildren);
|
|
59
|
-
case 'Col':
|
|
60
|
-
return renderCol(node as ColNode, context, renderChildren);
|
|
61
|
-
case 'Header':
|
|
62
|
-
return renderHeader(node as HeaderNode, context, renderChildren);
|
|
63
|
-
case 'Main':
|
|
64
|
-
return renderMain(node as MainNode, context, renderChildren);
|
|
65
|
-
case 'Footer':
|
|
66
|
-
return renderFooter(node as FooterNode, context, renderChildren);
|
|
67
|
-
case 'Sidebar':
|
|
68
|
-
return renderSidebar(node as SidebarNode, context, renderChildren);
|
|
69
|
-
case 'Section':
|
|
70
|
-
return renderSection(node as SectionNode, context, renderChildren, escapeHtml);
|
|
71
|
-
default:
|
|
72
|
-
return '';
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ===========================================
|
|
77
|
-
// Row Renderer
|
|
78
|
-
// ===========================================
|
|
79
|
-
|
|
80
|
-
function renderRow(
|
|
81
|
-
node: RowNode,
|
|
82
|
-
context: RenderContext,
|
|
83
|
-
renderChildren: ChildrenRenderer
|
|
84
|
-
): string {
|
|
85
|
-
const prefix = context.options.classPrefix;
|
|
86
|
-
const classes = buildRowClasses(node, prefix);
|
|
87
|
-
const styles = buildRowStyles(node, context.theme);
|
|
88
|
-
const children = renderChildren(node.children);
|
|
89
|
-
|
|
90
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
91
|
-
return `<div class="${classes}"${styleAttr}>\n${children}\n</div>`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function buildRowClasses(node: RowNode, prefix: string): string {
|
|
95
|
-
const classes: string[] = [`${prefix}-row`];
|
|
96
|
-
|
|
97
|
-
// Flex properties
|
|
98
|
-
if (node.flex === true) classes.push(`${prefix}-flex`);
|
|
99
|
-
if (typeof node.flex === 'number') classes.push(`${prefix}-flex-${node.flex}`);
|
|
100
|
-
if (node.direction === 'row') classes.push(`${prefix}-flex-row`);
|
|
101
|
-
if (node.direction === 'column') classes.push(`${prefix}-flex-col`);
|
|
102
|
-
if (node.direction === 'row-reverse') classes.push(`${prefix}-flex-row-reverse`);
|
|
103
|
-
if (node.direction === 'column-reverse') classes.push(`${prefix}-flex-col-reverse`);
|
|
104
|
-
if (node.justify) classes.push(`${prefix}-justify-${node.justify}`);
|
|
105
|
-
if (node.align) classes.push(`${prefix}-align-${node.align}`);
|
|
106
|
-
if (node.wrap === true) classes.push(`${prefix}-flex-wrap`);
|
|
107
|
-
if (node.wrap === 'nowrap') classes.push(`${prefix}-flex-nowrap`);
|
|
108
|
-
if (node.gap !== undefined) classes.push(`${prefix}-gap-${node.gap}`);
|
|
109
|
-
|
|
110
|
-
// Spacing classes
|
|
111
|
-
addSpacingClasses(classes, node, prefix);
|
|
112
|
-
|
|
113
|
-
return classes.join(' ');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function buildRowStyles(_node: RowNode, _theme: ThemeConfig): string {
|
|
117
|
-
const styles: string[] = [];
|
|
118
|
-
|
|
119
|
-
// Custom gap as inline style (for non-standard values)
|
|
120
|
-
// Standard gap values are handled by classes
|
|
121
|
-
|
|
122
|
-
return styles.join('; ');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ===========================================
|
|
126
|
-
// Col Renderer
|
|
127
|
-
// ===========================================
|
|
128
|
-
|
|
129
|
-
function renderCol(
|
|
130
|
-
node: ColNode,
|
|
131
|
-
context: RenderContext,
|
|
132
|
-
renderChildren: ChildrenRenderer
|
|
133
|
-
): string {
|
|
134
|
-
const prefix = context.options.classPrefix;
|
|
135
|
-
const classes = buildColClasses(node, prefix);
|
|
136
|
-
const styles = buildColStyles(node, context.theme);
|
|
137
|
-
const children = renderChildren(node.children);
|
|
138
|
-
|
|
139
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
140
|
-
return `<div class="${classes}"${styleAttr}>\n${children}\n</div>`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function buildColClasses(node: ColNode, prefix: string): string {
|
|
144
|
-
const classes: string[] = [`${prefix}-col`];
|
|
145
|
-
|
|
146
|
-
// Grid span classes
|
|
147
|
-
if (node.span !== undefined) classes.push(`${prefix}-col-${node.span}`);
|
|
148
|
-
|
|
149
|
-
// Responsive breakpoint classes
|
|
150
|
-
if (node.sm !== undefined) classes.push(`${prefix}-col-sm-${node.sm}`);
|
|
151
|
-
if (node.md !== undefined) classes.push(`${prefix}-col-md-${node.md}`);
|
|
152
|
-
if (node.lg !== undefined) classes.push(`${prefix}-col-lg-${node.lg}`);
|
|
153
|
-
if (node.xl !== undefined) classes.push(`${prefix}-col-xl-${node.xl}`);
|
|
154
|
-
|
|
155
|
-
// Flex properties
|
|
156
|
-
if (node.flex === true) classes.push(`${prefix}-flex`);
|
|
157
|
-
if (typeof node.flex === 'number') classes.push(`${prefix}-flex-${node.flex}`);
|
|
158
|
-
if (node.direction === 'row') classes.push(`${prefix}-flex-row`);
|
|
159
|
-
if (node.direction === 'column') classes.push(`${prefix}-flex-col`);
|
|
160
|
-
if (node.justify) classes.push(`${prefix}-justify-${node.justify}`);
|
|
161
|
-
if (node.align) classes.push(`${prefix}-align-${node.align}`);
|
|
162
|
-
|
|
163
|
-
// Size classes (for predefined values)
|
|
164
|
-
if (node.w === 'full') classes.push(`${prefix}-w-full`);
|
|
165
|
-
if (node.w === 'auto') classes.push(`${prefix}-w-auto`);
|
|
166
|
-
if (node.w === 'fit') classes.push(`${prefix}-w-fit`);
|
|
167
|
-
if (node.h === 'full') classes.push(`${prefix}-h-full`);
|
|
168
|
-
if (node.h === 'auto') classes.push(`${prefix}-h-auto`);
|
|
169
|
-
if (node.h === 'screen') classes.push(`${prefix}-h-screen`);
|
|
170
|
-
|
|
171
|
-
// Spacing classes
|
|
172
|
-
addSpacingClasses(classes, node, prefix);
|
|
173
|
-
|
|
174
|
-
return classes.join(' ');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function buildColStyles(node: ColNode, _theme: ThemeConfig): string {
|
|
178
|
-
const styles: string[] = [];
|
|
179
|
-
|
|
180
|
-
// Width (numeric values as inline style)
|
|
181
|
-
if (typeof node.w === 'number') {
|
|
182
|
-
styles.push(`width: ${node.w}px`);
|
|
183
|
-
} else if (typeof node.w === 'string' && !['full', 'auto', 'fit', 'screen'].includes(node.w)) {
|
|
184
|
-
styles.push(`width: ${resolveSizeValue(node.w)}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Height (numeric values as inline style)
|
|
188
|
-
if (typeof node.h === 'number') {
|
|
189
|
-
styles.push(`height: ${node.h}px`);
|
|
190
|
-
} else if (typeof node.h === 'string' && !['full', 'auto', 'screen'].includes(node.h)) {
|
|
191
|
-
styles.push(`height: ${resolveSizeValue(node.h)}`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Order
|
|
195
|
-
if (node.order !== undefined) {
|
|
196
|
-
styles.push(`order: ${node.order}`);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return styles.join('; ');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// ===========================================
|
|
203
|
-
// Semantic Layout Renderers
|
|
204
|
-
// ===========================================
|
|
205
|
-
|
|
206
|
-
function renderHeader(
|
|
207
|
-
node: HeaderNode,
|
|
208
|
-
context: RenderContext,
|
|
209
|
-
renderChildren: ChildrenRenderer
|
|
210
|
-
): string {
|
|
211
|
-
const prefix = context.options.classPrefix;
|
|
212
|
-
const classes = buildSemanticClasses('header', node, prefix);
|
|
213
|
-
const styles = buildSemanticStyles(node, context.theme);
|
|
214
|
-
const children = renderChildren(node.children);
|
|
215
|
-
|
|
216
|
-
// Add no-border class if border is false
|
|
217
|
-
const borderClass = node.border === false ? ` ${prefix}-no-border` : '';
|
|
218
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
219
|
-
|
|
220
|
-
return `<header class="${classes}${borderClass}"${styleAttr}>\n${children}\n</header>`;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function renderMain(
|
|
224
|
-
node: MainNode,
|
|
225
|
-
context: RenderContext,
|
|
226
|
-
renderChildren: ChildrenRenderer
|
|
227
|
-
): string {
|
|
228
|
-
const prefix = context.options.classPrefix;
|
|
229
|
-
const classes = buildSemanticClasses('main', node, prefix);
|
|
230
|
-
const styles = buildSemanticStyles(node, context.theme);
|
|
231
|
-
const children = renderChildren(node.children);
|
|
232
|
-
|
|
233
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
234
|
-
return `<main class="${classes}"${styleAttr}>\n${children}\n</main>`;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function renderFooter(
|
|
238
|
-
node: FooterNode,
|
|
239
|
-
context: RenderContext,
|
|
240
|
-
renderChildren: ChildrenRenderer
|
|
241
|
-
): string {
|
|
242
|
-
const prefix = context.options.classPrefix;
|
|
243
|
-
const classes = buildSemanticClasses('footer', node, prefix);
|
|
244
|
-
const styles = buildSemanticStyles(node, context.theme);
|
|
245
|
-
const children = renderChildren(node.children);
|
|
246
|
-
|
|
247
|
-
// Add no-border class if border is false
|
|
248
|
-
const borderClass = node.border === false ? ` ${prefix}-no-border` : '';
|
|
249
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
250
|
-
|
|
251
|
-
return `<footer class="${classes}${borderClass}"${styleAttr}>\n${children}\n</footer>`;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function renderSidebar(
|
|
255
|
-
node: SidebarNode,
|
|
256
|
-
context: RenderContext,
|
|
257
|
-
renderChildren: ChildrenRenderer
|
|
258
|
-
): string {
|
|
259
|
-
const prefix = context.options.classPrefix;
|
|
260
|
-
const classes: string[] = [`${prefix}-sidebar`];
|
|
261
|
-
|
|
262
|
-
// Position class
|
|
263
|
-
if (node.position === 'right') {
|
|
264
|
-
classes.push(`${prefix}-sidebar-right`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Span width (using col classes for width)
|
|
268
|
-
if (node.span !== undefined) {
|
|
269
|
-
classes.push(`${prefix}-col-${node.span}`);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Flex properties
|
|
273
|
-
if (node.flex === true) classes.push(`${prefix}-flex`);
|
|
274
|
-
if (typeof node.flex === 'number') classes.push(`${prefix}-flex-${node.flex}`);
|
|
275
|
-
if (node.direction) classes.push(`${prefix}-flex-${node.direction}`);
|
|
276
|
-
if (node.justify) classes.push(`${prefix}-justify-${node.justify}`);
|
|
277
|
-
if (node.align) classes.push(`${prefix}-align-${node.align}`);
|
|
278
|
-
|
|
279
|
-
// Spacing classes
|
|
280
|
-
addSpacingClasses(classes, node, prefix);
|
|
281
|
-
|
|
282
|
-
const styles = buildSemanticStyles(node, context.theme);
|
|
283
|
-
const children = renderChildren(node.children);
|
|
284
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
285
|
-
|
|
286
|
-
return `<aside class="${classes.join(' ')}"${styleAttr}>\n${children}\n</aside>`;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function renderSection(
|
|
290
|
-
node: SectionNode,
|
|
291
|
-
context: RenderContext,
|
|
292
|
-
renderChildren: ChildrenRenderer,
|
|
293
|
-
escapeHtml: (text: string) => string
|
|
294
|
-
): string {
|
|
295
|
-
const prefix = context.options.classPrefix;
|
|
296
|
-
const classes = buildSemanticClasses('section', node, prefix);
|
|
297
|
-
const styles = buildSemanticStyles(node, context.theme);
|
|
298
|
-
const children = renderChildren(node.children);
|
|
299
|
-
|
|
300
|
-
const title = node.title
|
|
301
|
-
? `<h2 class="${prefix}-title">${escapeHtml(node.title)}</h2>\n`
|
|
302
|
-
: '';
|
|
303
|
-
const styleAttr = styles ? ` style="${styles}"` : '';
|
|
304
|
-
|
|
305
|
-
return `<section class="${classes}"${styleAttr}>\n${title}${children}\n</section>`;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// ===========================================
|
|
309
|
-
// Utility Functions
|
|
310
|
-
// ===========================================
|
|
311
|
-
|
|
312
|
-
function buildSemanticClasses(tag: string, node: CommonProps, prefix: string): string {
|
|
313
|
-
const classes: string[] = [`${prefix}-${tag}`];
|
|
314
|
-
|
|
315
|
-
// Flex properties
|
|
316
|
-
if (node.flex === true) classes.push(`${prefix}-flex`);
|
|
317
|
-
if (typeof node.flex === 'number') classes.push(`${prefix}-flex-${node.flex}`);
|
|
318
|
-
if (node.direction === 'row') classes.push(`${prefix}-flex-row`);
|
|
319
|
-
if (node.direction === 'column') classes.push(`${prefix}-flex-col`);
|
|
320
|
-
if (node.justify) classes.push(`${prefix}-justify-${node.justify}`);
|
|
321
|
-
if (node.align) classes.push(`${prefix}-align-${node.align}`);
|
|
322
|
-
if (node.gap !== undefined) classes.push(`${prefix}-gap-${node.gap}`);
|
|
323
|
-
|
|
324
|
-
// Spacing classes
|
|
325
|
-
addSpacingClasses(classes, node, prefix);
|
|
326
|
-
|
|
327
|
-
return classes.join(' ');
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
function buildSemanticStyles(node: CommonProps, _theme: ThemeConfig): string {
|
|
331
|
-
const styles: string[] = [];
|
|
332
|
-
|
|
333
|
-
// Width
|
|
334
|
-
if (typeof node.w === 'number') {
|
|
335
|
-
styles.push(`width: ${node.w}px`);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Height
|
|
339
|
-
if (typeof node.h === 'number') {
|
|
340
|
-
styles.push(`height: ${node.h}px`);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return styles.join('; ');
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
function addSpacingClasses(classes: string[], node: CommonProps, prefix: string): void {
|
|
347
|
-
// Padding
|
|
348
|
-
if (node.p !== undefined) classes.push(`${prefix}-p-${node.p}`);
|
|
349
|
-
if (node.px !== undefined) classes.push(`${prefix}-px-${node.px}`);
|
|
350
|
-
if (node.py !== undefined) classes.push(`${prefix}-py-${node.py}`);
|
|
351
|
-
if (node.pt !== undefined) classes.push(`${prefix}-pt-${node.pt}`);
|
|
352
|
-
if (node.pr !== undefined) classes.push(`${prefix}-pr-${node.pr}`);
|
|
353
|
-
if (node.pb !== undefined) classes.push(`${prefix}-pb-${node.pb}`);
|
|
354
|
-
if (node.pl !== undefined) classes.push(`${prefix}-pl-${node.pl}`);
|
|
355
|
-
|
|
356
|
-
// Margin
|
|
357
|
-
if (node.m !== undefined) classes.push(`${prefix}-m-${node.m}`);
|
|
358
|
-
if (node.mx !== undefined) classes.push(`${prefix}-mx-${node.mx}`);
|
|
359
|
-
if (node.my !== undefined) classes.push(`${prefix}-my-${node.my}`);
|
|
360
|
-
if (node.mt !== undefined) classes.push(`${prefix}-mt-${node.mt}`);
|
|
361
|
-
if (node.mr !== undefined) classes.push(`${prefix}-mr-${node.mr}`);
|
|
362
|
-
if (node.mb !== undefined) classes.push(`${prefix}-mb-${node.mb}`);
|
|
363
|
-
if (node.ml !== undefined) classes.push(`${prefix}-ml-${node.ml}`);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Resolve size value to CSS
|
|
368
|
-
*/
|
|
369
|
-
function resolveSizeValue(value: WidthValue | HeightValue): string {
|
|
370
|
-
if (typeof value === 'number') {
|
|
371
|
-
return `${value}px`;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// ValueWithUnit object: direct CSS value
|
|
375
|
-
if (typeof value === 'object' && 'value' in value && 'unit' in value) {
|
|
376
|
-
return `${value.value}${value.unit}`;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
switch (value) {
|
|
380
|
-
case 'full':
|
|
381
|
-
return '100%';
|
|
382
|
-
case 'auto':
|
|
383
|
-
return 'auto';
|
|
384
|
-
case 'screen':
|
|
385
|
-
return '100vh';
|
|
386
|
-
case 'fit':
|
|
387
|
-
return 'fit-content';
|
|
388
|
-
default:
|
|
389
|
-
// Exhaustive check - this should never be reached
|
|
390
|
-
return value as string;
|
|
391
|
-
}
|
|
392
|
-
}
|
package/src/renderer/index.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Renderer module for wireweave
|
|
3
|
-
*
|
|
4
|
-
* Provides render functions to convert AST to HTML/CSS and SVG
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { WireframeDocument } from '../ast/types';
|
|
8
|
-
import { createHtmlRenderer } from './html';
|
|
9
|
-
import { renderToSvg as renderSvg } from './svg';
|
|
10
|
-
import type { RenderOptions, RenderResult, SvgRenderOptions, SvgRenderResult } from './types';
|
|
11
|
-
import { resolveViewport } from '../viewport';
|
|
12
|
-
|
|
13
|
-
// Re-export types
|
|
14
|
-
export * from './types';
|
|
15
|
-
export { HtmlRenderer, createHtmlRenderer } from './html';
|
|
16
|
-
export { SvgRenderer, createSvgRenderer } from './svg';
|
|
17
|
-
export { generateStyles } from './styles';
|
|
18
|
-
export { generateComponentStyles } from './styles-components';
|
|
19
|
-
|
|
20
|
-
// Re-export icons (ensures they're bundled with renderer)
|
|
21
|
-
export { getIconData, renderIconSvg, lucideIcons } from '../icons/lucide-icons';
|
|
22
|
-
export type { IconData, IconElement } from '../icons/lucide-icons';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Render AST to HTML and CSS
|
|
26
|
-
*
|
|
27
|
-
* @param document - Parsed wireframe document
|
|
28
|
-
* @param options - Render options
|
|
29
|
-
* @returns Object containing HTML and CSS strings
|
|
30
|
-
*/
|
|
31
|
-
export function render(document: WireframeDocument, options: RenderOptions = {}): RenderResult {
|
|
32
|
-
const renderer = createHtmlRenderer(options);
|
|
33
|
-
return renderer.render(document);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Render AST to standalone HTML with embedded CSS
|
|
38
|
-
*
|
|
39
|
-
* @param document - Parsed wireframe document
|
|
40
|
-
* @param options - Render options
|
|
41
|
-
* @returns Complete HTML document string
|
|
42
|
-
*/
|
|
43
|
-
export function renderToHtml(document: WireframeDocument, options: RenderOptions = {}): string {
|
|
44
|
-
const { html, css } = render(document, options);
|
|
45
|
-
|
|
46
|
-
return `<!DOCTYPE html>
|
|
47
|
-
<html lang="en">
|
|
48
|
-
<head>
|
|
49
|
-
<meta charset="UTF-8">
|
|
50
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
51
|
-
<title>Wireframe</title>
|
|
52
|
-
<style>
|
|
53
|
-
/* Browser centering styles */
|
|
54
|
-
html, body {
|
|
55
|
-
margin: 0;
|
|
56
|
-
padding: 0;
|
|
57
|
-
min-height: 100vh;
|
|
58
|
-
background: #f4f4f5;
|
|
59
|
-
}
|
|
60
|
-
body {
|
|
61
|
-
display: flex;
|
|
62
|
-
justify-content: center;
|
|
63
|
-
align-items: center;
|
|
64
|
-
padding: 24px;
|
|
65
|
-
box-sizing: border-box;
|
|
66
|
-
}
|
|
67
|
-
${css}
|
|
68
|
-
</style>
|
|
69
|
-
</head>
|
|
70
|
-
<body>
|
|
71
|
-
${html}
|
|
72
|
-
</body>
|
|
73
|
-
</html>`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Render AST to SVG using foreignObject with HTML+CSS
|
|
78
|
-
*
|
|
79
|
-
* This approach embeds HTML+CSS inside SVG using foreignObject,
|
|
80
|
-
* which allows CSS flexbox/grid layouts to work properly.
|
|
81
|
-
*
|
|
82
|
-
* @param document - Parsed wireframe document
|
|
83
|
-
* @param options - SVG render options
|
|
84
|
-
* @returns Object containing SVG string and dimensions
|
|
85
|
-
*/
|
|
86
|
-
export function renderToSvg(
|
|
87
|
-
document: WireframeDocument,
|
|
88
|
-
options: SvgRenderOptions = {}
|
|
89
|
-
): SvgRenderResult {
|
|
90
|
-
// Check for viewport settings in the first page
|
|
91
|
-
const firstPage = document.children[0];
|
|
92
|
-
let width = options.width ?? 800;
|
|
93
|
-
let height = options.height ?? 600;
|
|
94
|
-
|
|
95
|
-
// Use page viewport/device if set and no explicit options provided
|
|
96
|
-
if (firstPage && options.width === undefined && options.height === undefined) {
|
|
97
|
-
if (firstPage.viewport !== undefined || firstPage.device !== undefined) {
|
|
98
|
-
const viewport = resolveViewport(firstPage.viewport, firstPage.device);
|
|
99
|
-
width = viewport.width;
|
|
100
|
-
height = viewport.height;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const padding = options.padding ?? 20;
|
|
105
|
-
const background = options.background ?? '#ffffff';
|
|
106
|
-
|
|
107
|
-
// Use HTML renderer to generate content
|
|
108
|
-
const { html, css } = render(document, { theme: 'light' });
|
|
109
|
-
|
|
110
|
-
// Build SVG with foreignObject containing HTML+CSS
|
|
111
|
-
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
112
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
113
|
-
viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
114
|
-
<rect width="100%" height="100%" fill="${background}"/>
|
|
115
|
-
<foreignObject x="${padding}" y="${padding}" width="${width - padding * 2}" height="${height - padding * 2}">
|
|
116
|
-
<div xmlns="http://www.w3.org/1999/xhtml" style="width: 100%; height: 100%; overflow: hidden;">
|
|
117
|
-
<style type="text/css">
|
|
118
|
-
${css}
|
|
119
|
-
</style>
|
|
120
|
-
${html}
|
|
121
|
-
</div>
|
|
122
|
-
</foreignObject>
|
|
123
|
-
</svg>`;
|
|
124
|
-
|
|
125
|
-
return { svg, width, height };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Render AST to pure SVG (without foreignObject)
|
|
130
|
-
*
|
|
131
|
-
* This uses the original SVG renderer with manual layout calculations.
|
|
132
|
-
* Use this when foreignObject is not supported.
|
|
133
|
-
*
|
|
134
|
-
* @param document - Parsed wireframe document
|
|
135
|
-
* @param options - SVG render options
|
|
136
|
-
* @returns Object containing SVG string and dimensions
|
|
137
|
-
*/
|
|
138
|
-
export function renderToPureSvg(
|
|
139
|
-
document: WireframeDocument,
|
|
140
|
-
options: SvgRenderOptions = {}
|
|
141
|
-
): SvgRenderResult {
|
|
142
|
-
return renderSvg(document, options);
|
|
143
|
-
}
|