@wireweave/core 1.0.0-beta.20260110141318 → 1.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/index.cjs +823 -3067
- package/dist/index.d.cts +3 -168
- package/dist/index.d.ts +3 -168
- package/dist/index.js +823 -3054
- package/dist/parser.cjs +292 -636
- package/dist/parser.d.cts +1 -1
- package/dist/parser.d.ts +1 -1
- package/dist/parser.js +292 -636
- package/dist/renderer.cjs +525 -1756
- package/dist/renderer.d.cts +58 -105
- package/dist/renderer.d.ts +58 -105
- package/dist/renderer.js +525 -1756
- package/dist/{types-lcJzPcR0.d.cts → types-DtovIYS6.d.cts} +2 -40
- package/dist/{types-lcJzPcR0.d.ts → types-DtovIYS6.d.ts} +2 -40
- package/package.json +1 -1
package/dist/renderer.cjs
CHANGED
|
@@ -118,15 +118,10 @@ function generateContainerStyles(prefix) {
|
|
|
118
118
|
padding: 16px;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
/* Cards in flex rows
|
|
121
|
+
/* Cards in flex rows should expand equally */
|
|
122
122
|
.${prefix}-row > .${prefix}-card {
|
|
123
|
-
flex: 0 1 auto;
|
|
124
|
-
min-width: 0;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/* Cards without explicit width should expand to fill space */
|
|
128
|
-
.${prefix}-row > .${prefix}-card-flex {
|
|
129
123
|
flex: 1 1 0%;
|
|
124
|
+
min-width: 0;
|
|
130
125
|
}
|
|
131
126
|
|
|
132
127
|
.${prefix}-card-title {
|
|
@@ -282,11 +277,6 @@ function generateTextStyles(prefix) {
|
|
|
282
277
|
line-height: 1.25;
|
|
283
278
|
}
|
|
284
279
|
|
|
285
|
-
/* Remove bottom margin when title is in a row (inline with other elements) */
|
|
286
|
-
.${prefix}-row .${prefix}-title {
|
|
287
|
-
margin-bottom: 0;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
280
|
h1.${prefix}-title { font-size: 36px; }
|
|
291
281
|
h2.${prefix}-title { font-size: 30px; }
|
|
292
282
|
h3.${prefix}-title { font-size: 24px; }
|
|
@@ -681,30 +671,6 @@ img.${prefix}-image {
|
|
|
681
671
|
font-size: 14px;
|
|
682
672
|
}
|
|
683
673
|
|
|
684
|
-
.${prefix}-placeholder-with-children {
|
|
685
|
-
position: relative;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
.${prefix}-placeholder-label {
|
|
689
|
-
position: absolute;
|
|
690
|
-
top: 50%;
|
|
691
|
-
left: 50%;
|
|
692
|
-
transform: translate(-50%, -50%);
|
|
693
|
-
z-index: 0;
|
|
694
|
-
pointer-events: none;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
.${prefix}-placeholder-overlay {
|
|
698
|
-
position: absolute;
|
|
699
|
-
top: 0;
|
|
700
|
-
left: 0;
|
|
701
|
-
right: 0;
|
|
702
|
-
bottom: 0;
|
|
703
|
-
z-index: 1;
|
|
704
|
-
display: flex;
|
|
705
|
-
flex-direction: column;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
674
|
.${prefix}-avatar {
|
|
709
675
|
display: inline-flex;
|
|
710
676
|
align-items: center;
|
|
@@ -820,12 +786,12 @@ svg.${prefix}-icon {
|
|
|
820
786
|
display: block;
|
|
821
787
|
}
|
|
822
788
|
|
|
823
|
-
/* Icon size tokens
|
|
789
|
+
/* Icon size tokens */
|
|
824
790
|
svg.${prefix}-icon-xs { width: 12px; height: 12px; }
|
|
825
|
-
svg.${prefix}-icon-sm { width:
|
|
826
|
-
svg.${prefix}-icon-md { width:
|
|
827
|
-
svg.${prefix}-icon-lg { width:
|
|
828
|
-
svg.${prefix}-icon-xl { width:
|
|
791
|
+
svg.${prefix}-icon-sm { width: 14px; height: 14px; }
|
|
792
|
+
svg.${prefix}-icon-md { width: 16px; height: 16px; }
|
|
793
|
+
svg.${prefix}-icon-lg { width: 20px; height: 20px; }
|
|
794
|
+
svg.${prefix}-icon-xl { width: 24px; height: 24px; }
|
|
829
795
|
|
|
830
796
|
.${prefix}-icon svg {
|
|
831
797
|
display: block;
|
|
@@ -1121,27 +1087,6 @@ function generateNavigationStyles(_theme, prefix) {
|
|
|
1121
1087
|
cursor: not-allowed;
|
|
1122
1088
|
}
|
|
1123
1089
|
|
|
1124
|
-
.${prefix}-nav-group {
|
|
1125
|
-
display: flex;
|
|
1126
|
-
flex-direction: column;
|
|
1127
|
-
gap: 4px;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
.${prefix}-nav-group-label {
|
|
1131
|
-
font-size: 11px;
|
|
1132
|
-
font-weight: 500;
|
|
1133
|
-
color: var(--${prefix}-muted);
|
|
1134
|
-
text-transform: uppercase;
|
|
1135
|
-
letter-spacing: 0.05em;
|
|
1136
|
-
padding: 8px 16px 4px;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
.${prefix}-nav-divider {
|
|
1140
|
-
margin: 8px 0;
|
|
1141
|
-
border: none;
|
|
1142
|
-
border-top: 1px solid var(--${prefix}-border);
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
1090
|
.${prefix}-tabs {
|
|
1146
1091
|
border-bottom: 1px solid var(--${prefix}-border);
|
|
1147
1092
|
}
|
|
@@ -1359,6 +1304,7 @@ function generateBaseStyles(prefix) {
|
|
|
1359
1304
|
font-family: var(--${prefix}-font);
|
|
1360
1305
|
color: var(--${prefix}-fg);
|
|
1361
1306
|
background: var(--${prefix}-bg);
|
|
1307
|
+
min-height: 100vh;
|
|
1362
1308
|
box-sizing: border-box;
|
|
1363
1309
|
position: relative;
|
|
1364
1310
|
display: flex;
|
|
@@ -1369,19 +1315,10 @@ function generateBaseStyles(prefix) {
|
|
|
1369
1315
|
overflow: hidden;
|
|
1370
1316
|
}
|
|
1371
1317
|
|
|
1372
|
-
/* Col direct child of page should fill page height */
|
|
1373
|
-
.${prefix}-page > .${prefix}-col {
|
|
1374
|
-
flex: 1;
|
|
1375
|
-
min-height: 0;
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
1318
|
/* Row containing sidebar should fill remaining space */
|
|
1379
1319
|
.${prefix}-page > .${prefix}-row:has(.${prefix}-sidebar),
|
|
1380
|
-
.${prefix}-page > .${prefix}-row:has(.${prefix}-main)
|
|
1381
|
-
.${prefix}-page > .${prefix}-col > .${prefix}-row:has(.${prefix}-sidebar),
|
|
1382
|
-
.${prefix}-page > .${prefix}-col > .${prefix}-row:has(.${prefix}-main) {
|
|
1320
|
+
.${prefix}-page > .${prefix}-row:has(.${prefix}-main) {
|
|
1383
1321
|
flex: 1;
|
|
1384
|
-
min-height: 0;
|
|
1385
1322
|
align-items: stretch;
|
|
1386
1323
|
}
|
|
1387
1324
|
|
|
@@ -1424,15 +1361,10 @@ function generateGridClasses(_theme, prefix) {
|
|
|
1424
1361
|
box-sizing: border-box;
|
|
1425
1362
|
}
|
|
1426
1363
|
|
|
1427
|
-
/* When explicit width is set, don't flex-grow */
|
|
1428
|
-
.${prefix}-row[style*="width:"],
|
|
1429
|
-
.${prefix}-col[style*="width:"] {
|
|
1430
|
-
flex: 0 0 auto;
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
1364
|
`;
|
|
1434
1365
|
for (let i = 1; i <= 12; i++) {
|
|
1435
|
-
|
|
1366
|
+
const width = (i / 12 * 100).toFixed(4);
|
|
1367
|
+
css += `.${prefix}-col-${i} { flex: 0 0 auto; width: ${width}%; }
|
|
1436
1368
|
`;
|
|
1437
1369
|
}
|
|
1438
1370
|
return css;
|
|
@@ -1600,20 +1532,6 @@ function generateLayoutClasses(prefix) {
|
|
|
1600
1532
|
.${prefix}-main {
|
|
1601
1533
|
flex: 1;
|
|
1602
1534
|
padding: 16px;
|
|
1603
|
-
display: flex;
|
|
1604
|
-
flex-direction: column;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
/* Scrollable main content */
|
|
1608
|
-
.${prefix}-main.${prefix}-scroll {
|
|
1609
|
-
overflow-y: auto;
|
|
1610
|
-
overflow-x: hidden;
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
/* Main content should align to top, not stretch to fill */
|
|
1614
|
-
/* But allow explicit flex=1 to override */
|
|
1615
|
-
.${prefix}-main > .${prefix}-col:not(.${prefix}-flex-1) {
|
|
1616
|
-
flex: 0 0 auto;
|
|
1617
1535
|
}
|
|
1618
1536
|
|
|
1619
1537
|
.${prefix}-footer {
|
|
@@ -1630,7 +1548,6 @@ function generateLayoutClasses(prefix) {
|
|
|
1630
1548
|
border-right: 1px solid var(--${prefix}-border);
|
|
1631
1549
|
padding: 16px 16px 16px 20px;
|
|
1632
1550
|
flex-shrink: 0;
|
|
1633
|
-
align-self: stretch;
|
|
1634
1551
|
}
|
|
1635
1552
|
|
|
1636
1553
|
.${prefix}-sidebar-right {
|
|
@@ -48200,39 +48117,14 @@ var lucideIcons = {
|
|
|
48200
48117
|
]
|
|
48201
48118
|
]
|
|
48202
48119
|
};
|
|
48203
|
-
var iconAliases = {
|
|
48204
|
-
"home": "house",
|
|
48205
|
-
"plus-square": "square-plus",
|
|
48206
|
-
"minus-square": "square-minus",
|
|
48207
|
-
"x-square": "square-x",
|
|
48208
|
-
"check-square": "square-check",
|
|
48209
|
-
"edit": "pencil",
|
|
48210
|
-
"edit-2": "pencil",
|
|
48211
|
-
"edit-3": "pencil-line",
|
|
48212
|
-
"trash": "trash-2",
|
|
48213
|
-
"delete": "trash-2",
|
|
48214
|
-
"close": "x",
|
|
48215
|
-
"menu": "menu",
|
|
48216
|
-
"hamburger": "menu",
|
|
48217
|
-
"dots": "more-horizontal",
|
|
48218
|
-
"dots-vertical": "more-vertical",
|
|
48219
|
-
"cog": "settings",
|
|
48220
|
-
"gear": "settings"
|
|
48221
|
-
};
|
|
48222
48120
|
function getIconData(name) {
|
|
48223
48121
|
if (lucideIcons[name]) {
|
|
48224
48122
|
return lucideIcons[name];
|
|
48225
48123
|
}
|
|
48226
|
-
if (iconAliases[name] && lucideIcons[iconAliases[name]]) {
|
|
48227
|
-
return lucideIcons[iconAliases[name]];
|
|
48228
|
-
}
|
|
48229
48124
|
const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
48230
48125
|
if (lucideIcons[kebabName]) {
|
|
48231
48126
|
return lucideIcons[kebabName];
|
|
48232
48127
|
}
|
|
48233
|
-
if (iconAliases[kebabName] && lucideIcons[iconAliases[kebabName]]) {
|
|
48234
|
-
return lucideIcons[iconAliases[kebabName]];
|
|
48235
|
-
}
|
|
48236
48128
|
return void 0;
|
|
48237
48129
|
}
|
|
48238
48130
|
function renderIconSvg(data, _size = 24, strokeWidth = 2, className = "", styleAttr = "") {
|
|
@@ -48342,7 +48234,7 @@ var HtmlRenderer = class extends BaseRenderer {
|
|
|
48342
48234
|
const title = node.title ? `<title>${this.escapeHtml(node.title)}</title>
|
|
48343
48235
|
` : "";
|
|
48344
48236
|
const commonStyles = this.buildCommonStyles(node);
|
|
48345
|
-
const viewportStyle = `
|
|
48237
|
+
const viewportStyle = `width: ${viewport.width}px; height: ${viewport.height}px`;
|
|
48346
48238
|
const combinedStyle = commonStyles ? `${viewportStyle}; ${commonStyles}` : viewportStyle;
|
|
48347
48239
|
const dataAttrs = `data-viewport-width="${viewport.width}" data-viewport-height="${viewport.height}" data-viewport-label="${viewport.label}"`;
|
|
48348
48240
|
return `<div class="${classes}" style="${combinedStyle}" ${dataAttrs}>
|
|
@@ -48508,7 +48400,6 @@ ${children}
|
|
|
48508
48400
|
renderMain(node) {
|
|
48509
48401
|
const classes = this.buildClassString([
|
|
48510
48402
|
`${this.prefix}-main`,
|
|
48511
|
-
node.scroll ? `${this.prefix}-scroll` : void 0,
|
|
48512
48403
|
...this.getCommonClasses(node)
|
|
48513
48404
|
]);
|
|
48514
48405
|
const styles = this.buildCommonStyles(node);
|
|
@@ -48594,10 +48485,6 @@ ${children}
|
|
|
48594
48485
|
/**
|
|
48595
48486
|
* Build common inline styles for all values
|
|
48596
48487
|
*
|
|
48597
|
-
* Position values (x, y) for absolute positioning:
|
|
48598
|
-
* - When x or y is specified, element gets position: absolute
|
|
48599
|
-
* - x → left, y → top
|
|
48600
|
-
*
|
|
48601
48488
|
* Spacing values (p, m, gap) use token system:
|
|
48602
48489
|
* - number: spacing token (e.g., p=4 → padding: 16px from token table)
|
|
48603
48490
|
* - ValueWithUnit: direct CSS value (e.g., p=16px → padding: 16px)
|
|
@@ -48612,17 +48499,6 @@ ${children}
|
|
|
48612
48499
|
*/
|
|
48613
48500
|
buildCommonStyles(props) {
|
|
48614
48501
|
const styles = [];
|
|
48615
|
-
if (props.x !== void 0 || props.y !== void 0) {
|
|
48616
|
-
styles.push("position: absolute");
|
|
48617
|
-
if (props.x !== void 0) {
|
|
48618
|
-
const xValue = resolveSizeValueToCss(props.x);
|
|
48619
|
-
if (xValue) styles.push(`left: ${xValue}`);
|
|
48620
|
-
}
|
|
48621
|
-
if (props.y !== void 0) {
|
|
48622
|
-
const yValue = resolveSizeValueToCss(props.y);
|
|
48623
|
-
if (yValue) styles.push(`top: ${yValue}`);
|
|
48624
|
-
}
|
|
48625
|
-
}
|
|
48626
48502
|
const wValue = resolveSizeValueToCss(props.w);
|
|
48627
48503
|
if (wValue) {
|
|
48628
48504
|
styles.push(`width: ${wValue}`);
|
|
@@ -48732,10 +48608,8 @@ ${children}
|
|
|
48732
48608
|
// Container Node Renderers
|
|
48733
48609
|
// ===========================================
|
|
48734
48610
|
renderCard(node) {
|
|
48735
|
-
const hasExplicitWidth = node.w !== void 0;
|
|
48736
48611
|
const classes = this.buildClassString([
|
|
48737
48612
|
`${this.prefix}-card`,
|
|
48738
|
-
!hasExplicitWidth ? `${this.prefix}-card-flex` : void 0,
|
|
48739
48613
|
node.shadow ? `${this.prefix}-card-shadow-${node.shadow}` : void 0,
|
|
48740
48614
|
...this.getCommonClasses(node)
|
|
48741
48615
|
]);
|
|
@@ -49072,19 +48946,11 @@ ${slider}`;
|
|
|
49072
48946
|
renderPlaceholder(node) {
|
|
49073
48947
|
const classes = this.buildClassString([
|
|
49074
48948
|
`${this.prefix}-placeholder`,
|
|
49075
|
-
node.children && node.children.length > 0 ? `${this.prefix}-placeholder-with-children` : void 0,
|
|
49076
48949
|
...this.getCommonClasses(node)
|
|
49077
48950
|
]);
|
|
49078
48951
|
const styles = this.buildCommonStyles(node);
|
|
49079
48952
|
const styleAttr = styles ? ` style="${styles}"` : "";
|
|
49080
48953
|
const label = node.label ? this.escapeHtml(node.label) : "Placeholder";
|
|
49081
|
-
if (node.children && node.children.length > 0) {
|
|
49082
|
-
const childrenHtml = this.renderChildren(node.children);
|
|
49083
|
-
return `<div class="${classes}"${styleAttr}>
|
|
49084
|
-
<span class="${this.prefix}-placeholder-label">${label}</span>
|
|
49085
|
-
<div class="${this.prefix}-placeholder-overlay">${childrenHtml}</div>
|
|
49086
|
-
</div>`;
|
|
49087
|
-
}
|
|
49088
48954
|
return `<div class="${classes}"${styleAttr}>${label}</div>`;
|
|
49089
48955
|
}
|
|
49090
48956
|
renderAvatar(node) {
|
|
@@ -49330,12 +49196,6 @@ ${items}
|
|
|
49330
49196
|
]);
|
|
49331
49197
|
const styles = this.buildCommonStyles(node);
|
|
49332
49198
|
const styleAttr = styles ? ` style="${styles}"` : "";
|
|
49333
|
-
if (node.children && node.children.length > 0) {
|
|
49334
|
-
const content = this.renderNavChildren(node.children);
|
|
49335
|
-
return `<nav class="${classes}"${styleAttr}>
|
|
49336
|
-
${content}
|
|
49337
|
-
</nav>`;
|
|
49338
|
-
}
|
|
49339
49199
|
const items = node.items.map((item) => {
|
|
49340
49200
|
if (typeof item === "string") {
|
|
49341
49201
|
return `<a class="${this.prefix}-nav-link" href="#">${this.escapeHtml(item)}</a>`;
|
|
@@ -49345,48 +49205,12 @@ ${content}
|
|
|
49345
49205
|
item.active ? `${this.prefix}-nav-link-active` : void 0,
|
|
49346
49206
|
item.disabled ? `${this.prefix}-nav-link-disabled` : void 0
|
|
49347
49207
|
]);
|
|
49348
|
-
|
|
49349
|
-
return `<a class="${linkClasses}" href="${item.href || "#"}">${iconHtml}${this.escapeHtml(item.label)}</a>`;
|
|
49208
|
+
return `<a class="${linkClasses}" href="${item.href || "#"}">${this.escapeHtml(item.label)}</a>`;
|
|
49350
49209
|
}).join("\n");
|
|
49351
49210
|
return `<nav class="${classes}"${styleAttr}>
|
|
49352
49211
|
${items}
|
|
49353
49212
|
</nav>`;
|
|
49354
49213
|
}
|
|
49355
|
-
renderNavChildren(children) {
|
|
49356
|
-
return children.map((child) => {
|
|
49357
|
-
if (child.type === "divider") {
|
|
49358
|
-
return `<hr class="${this.prefix}-nav-divider" />`;
|
|
49359
|
-
}
|
|
49360
|
-
if (child.type === "group") {
|
|
49361
|
-
const groupItems = child.items.map((item) => {
|
|
49362
|
-
if (item.type === "divider") {
|
|
49363
|
-
return `<hr class="${this.prefix}-nav-divider" />`;
|
|
49364
|
-
}
|
|
49365
|
-
return this.renderNavItem(item);
|
|
49366
|
-
}).join("\n");
|
|
49367
|
-
return `<div class="${this.prefix}-nav-group">
|
|
49368
|
-
<div class="${this.prefix}-nav-group-label">${this.escapeHtml(child.label)}</div>
|
|
49369
|
-
${groupItems}
|
|
49370
|
-
</div>`;
|
|
49371
|
-
}
|
|
49372
|
-
if (child.type === "item") {
|
|
49373
|
-
return this.renderNavItem(child);
|
|
49374
|
-
}
|
|
49375
|
-
return "";
|
|
49376
|
-
}).join("\n");
|
|
49377
|
-
}
|
|
49378
|
-
renderNavItem(item) {
|
|
49379
|
-
const linkClasses = this.buildClassString([
|
|
49380
|
-
`${this.prefix}-nav-link`,
|
|
49381
|
-
item.active ? `${this.prefix}-nav-link-active` : void 0,
|
|
49382
|
-
item.disabled ? `${this.prefix}-nav-link-disabled` : void 0
|
|
49383
|
-
]);
|
|
49384
|
-
const iconHtml = item.icon ? this.renderIconHtml(item.icon) + " " : "";
|
|
49385
|
-
return `<a class="${linkClasses}" href="${item.href || "#"}">${iconHtml}${this.escapeHtml(item.label)}</a>`;
|
|
49386
|
-
}
|
|
49387
|
-
renderIconHtml(iconName) {
|
|
49388
|
-
return `<span class="${this.prefix}-icon" data-icon="${iconName}"></span>`;
|
|
49389
|
-
}
|
|
49390
49214
|
renderTabs(node) {
|
|
49391
49215
|
const classes = this.buildClassString([
|
|
49392
49216
|
`${this.prefix}-tabs`,
|
|
@@ -49541,239 +49365,13 @@ function createHtmlRenderer(options) {
|
|
|
49541
49365
|
return new HtmlRenderer(options);
|
|
49542
49366
|
}
|
|
49543
49367
|
|
|
49544
|
-
// src/renderer/svg/flex-layout.ts
|
|
49545
|
-
function computeFlexLayout(items, config) {
|
|
49546
|
-
const { mainSize, crossSize, justifyContent, alignItems, gap } = config;
|
|
49547
|
-
const computed = items.map((props, index) => {
|
|
49548
|
-
let flexBasis;
|
|
49549
|
-
if (props.basis === "auto" || props.basis === "content") {
|
|
49550
|
-
flexBasis = props.contentSize;
|
|
49551
|
-
} else {
|
|
49552
|
-
flexBasis = props.basis;
|
|
49553
|
-
}
|
|
49554
|
-
flexBasis = clamp(flexBasis, props.minSize, props.maxSize);
|
|
49555
|
-
return {
|
|
49556
|
-
index,
|
|
49557
|
-
props,
|
|
49558
|
-
flexBasis,
|
|
49559
|
-
mainSize: flexBasis,
|
|
49560
|
-
crossSize: 0,
|
|
49561
|
-
mainPosition: 0,
|
|
49562
|
-
crossPosition: 0,
|
|
49563
|
-
frozen: false,
|
|
49564
|
-
scaledShrinkFactor: props.shrink * flexBasis
|
|
49565
|
-
};
|
|
49566
|
-
});
|
|
49567
|
-
const totalGap = Math.max(0, (items.length - 1) * gap);
|
|
49568
|
-
const totalFlexBasis = computed.reduce((sum, item) => sum + item.flexBasis, 0);
|
|
49569
|
-
let freeSpace = mainSize - totalFlexBasis - totalGap;
|
|
49570
|
-
if (freeSpace !== 0) {
|
|
49571
|
-
resolveFlexibleLengths(computed, freeSpace);
|
|
49572
|
-
}
|
|
49573
|
-
distributeMainAxis(computed, mainSize, totalGap, gap, justifyContent);
|
|
49574
|
-
const crossSizeMax = crossSize ?? Math.max(...computed.map((item) => item.props.contentSize), 0);
|
|
49575
|
-
alignCrossAxis(computed, crossSizeMax, alignItems);
|
|
49576
|
-
const mainSizeUsed = computed.reduce((sum, item) => sum + item.mainSize, 0) + totalGap;
|
|
49577
|
-
return {
|
|
49578
|
-
items: computed,
|
|
49579
|
-
mainSizeUsed,
|
|
49580
|
-
crossSizeMax
|
|
49581
|
-
};
|
|
49582
|
-
}
|
|
49583
|
-
function resolveFlexibleLengths(items, initialFreeSpace) {
|
|
49584
|
-
items.forEach((item) => {
|
|
49585
|
-
item.frozen = false;
|
|
49586
|
-
item.mainSize = item.flexBasis;
|
|
49587
|
-
});
|
|
49588
|
-
let freeSpace = initialFreeSpace;
|
|
49589
|
-
const isGrowing = freeSpace > 0;
|
|
49590
|
-
let iteration = 0;
|
|
49591
|
-
const maxIterations = items.length + 1;
|
|
49592
|
-
while (iteration < maxIterations) {
|
|
49593
|
-
iteration++;
|
|
49594
|
-
const unfrozen = items.filter((item) => !item.frozen);
|
|
49595
|
-
if (unfrozen.length === 0) break;
|
|
49596
|
-
let flexFactorSum;
|
|
49597
|
-
if (isGrowing) {
|
|
49598
|
-
flexFactorSum = unfrozen.reduce((sum, item) => sum + item.props.grow, 0);
|
|
49599
|
-
} else {
|
|
49600
|
-
flexFactorSum = unfrozen.reduce((sum, item) => sum + item.scaledShrinkFactor, 0);
|
|
49601
|
-
}
|
|
49602
|
-
if (flexFactorSum === 0) {
|
|
49603
|
-
unfrozen.forEach((item) => item.frozen = true);
|
|
49604
|
-
break;
|
|
49605
|
-
}
|
|
49606
|
-
const usedSpace = items.reduce((sum, item) => sum + item.mainSize, 0);
|
|
49607
|
-
const containerMainSize = usedSpace + freeSpace;
|
|
49608
|
-
freeSpace = containerMainSize - usedSpace;
|
|
49609
|
-
let totalViolation = 0;
|
|
49610
|
-
for (const item of unfrozen) {
|
|
49611
|
-
let flexFraction;
|
|
49612
|
-
if (isGrowing) {
|
|
49613
|
-
flexFraction = item.props.grow / flexFactorSum;
|
|
49614
|
-
} else {
|
|
49615
|
-
flexFraction = item.scaledShrinkFactor / flexFactorSum;
|
|
49616
|
-
}
|
|
49617
|
-
const deltaSize = freeSpace * flexFraction;
|
|
49618
|
-
const targetSize = item.flexBasis + deltaSize;
|
|
49619
|
-
const clampedSize = clamp(targetSize, item.props.minSize, item.props.maxSize);
|
|
49620
|
-
const violation = clampedSize - targetSize;
|
|
49621
|
-
item.mainSize = clampedSize;
|
|
49622
|
-
totalViolation += violation;
|
|
49623
|
-
if (violation !== 0) {
|
|
49624
|
-
item.frozen = true;
|
|
49625
|
-
}
|
|
49626
|
-
}
|
|
49627
|
-
if (Math.abs(totalViolation) < 0.01) {
|
|
49628
|
-
unfrozen.forEach((item) => item.frozen = true);
|
|
49629
|
-
break;
|
|
49630
|
-
}
|
|
49631
|
-
freeSpace = containerMainSize - items.reduce((sum, item) => sum + item.mainSize, 0);
|
|
49632
|
-
}
|
|
49633
|
-
}
|
|
49634
|
-
function distributeMainAxis(items, containerSize, totalGap, gap, justifyContent) {
|
|
49635
|
-
if (items.length === 0) return;
|
|
49636
|
-
const totalItemSize = items.reduce((sum, item) => sum + item.mainSize, 0);
|
|
49637
|
-
const freeSpace = containerSize - totalItemSize - totalGap;
|
|
49638
|
-
let position = 0;
|
|
49639
|
-
let itemGap = gap;
|
|
49640
|
-
let leadingSpace = 0;
|
|
49641
|
-
switch (justifyContent) {
|
|
49642
|
-
case "flex-start":
|
|
49643
|
-
leadingSpace = 0;
|
|
49644
|
-
break;
|
|
49645
|
-
case "flex-end":
|
|
49646
|
-
leadingSpace = freeSpace;
|
|
49647
|
-
break;
|
|
49648
|
-
case "center":
|
|
49649
|
-
leadingSpace = freeSpace / 2;
|
|
49650
|
-
break;
|
|
49651
|
-
case "space-between":
|
|
49652
|
-
leadingSpace = 0;
|
|
49653
|
-
if (items.length > 1) {
|
|
49654
|
-
itemGap = gap + freeSpace / (items.length - 1);
|
|
49655
|
-
}
|
|
49656
|
-
break;
|
|
49657
|
-
case "space-around":
|
|
49658
|
-
if (items.length > 0) {
|
|
49659
|
-
const spacePerItem = freeSpace / items.length;
|
|
49660
|
-
leadingSpace = spacePerItem / 2;
|
|
49661
|
-
itemGap = gap + spacePerItem;
|
|
49662
|
-
}
|
|
49663
|
-
break;
|
|
49664
|
-
case "space-evenly":
|
|
49665
|
-
if (items.length > 0) {
|
|
49666
|
-
const totalSpaces = items.length + 1;
|
|
49667
|
-
const spaceSize = freeSpace / totalSpaces;
|
|
49668
|
-
leadingSpace = spaceSize;
|
|
49669
|
-
itemGap = gap + spaceSize;
|
|
49670
|
-
}
|
|
49671
|
-
break;
|
|
49672
|
-
}
|
|
49673
|
-
position = leadingSpace;
|
|
49674
|
-
for (let i = 0; i < items.length; i++) {
|
|
49675
|
-
items[i].mainPosition = position;
|
|
49676
|
-
position += items[i].mainSize;
|
|
49677
|
-
if (i < items.length - 1) {
|
|
49678
|
-
position += itemGap;
|
|
49679
|
-
}
|
|
49680
|
-
}
|
|
49681
|
-
}
|
|
49682
|
-
function alignCrossAxis(items, containerCrossSize, alignItems) {
|
|
49683
|
-
for (const item of items) {
|
|
49684
|
-
const align = item.props.alignSelf ?? alignItems;
|
|
49685
|
-
const itemCrossSize = item.props.contentSize;
|
|
49686
|
-
item.crossSize = align === "stretch" ? containerCrossSize : itemCrossSize;
|
|
49687
|
-
switch (align) {
|
|
49688
|
-
case "flex-start":
|
|
49689
|
-
item.crossPosition = 0;
|
|
49690
|
-
break;
|
|
49691
|
-
case "flex-end":
|
|
49692
|
-
item.crossPosition = containerCrossSize - item.crossSize;
|
|
49693
|
-
break;
|
|
49694
|
-
case "center":
|
|
49695
|
-
item.crossPosition = (containerCrossSize - item.crossSize) / 2;
|
|
49696
|
-
break;
|
|
49697
|
-
case "stretch":
|
|
49698
|
-
item.crossPosition = 0;
|
|
49699
|
-
item.crossSize = containerCrossSize;
|
|
49700
|
-
break;
|
|
49701
|
-
case "baseline":
|
|
49702
|
-
item.crossPosition = 0;
|
|
49703
|
-
break;
|
|
49704
|
-
}
|
|
49705
|
-
}
|
|
49706
|
-
}
|
|
49707
|
-
function clamp(value, min, max) {
|
|
49708
|
-
return Math.max(min, Math.min(max, value));
|
|
49709
|
-
}
|
|
49710
|
-
function toJustifyContent(justify) {
|
|
49711
|
-
switch (justify) {
|
|
49712
|
-
case "start":
|
|
49713
|
-
return "flex-start";
|
|
49714
|
-
case "end":
|
|
49715
|
-
return "flex-end";
|
|
49716
|
-
case "center":
|
|
49717
|
-
return "center";
|
|
49718
|
-
case "between":
|
|
49719
|
-
return "space-between";
|
|
49720
|
-
case "around":
|
|
49721
|
-
return "space-around";
|
|
49722
|
-
case "evenly":
|
|
49723
|
-
return "space-evenly";
|
|
49724
|
-
default:
|
|
49725
|
-
return "flex-start";
|
|
49726
|
-
}
|
|
49727
|
-
}
|
|
49728
|
-
function toAlignItems(align) {
|
|
49729
|
-
switch (align) {
|
|
49730
|
-
case "start":
|
|
49731
|
-
return "flex-start";
|
|
49732
|
-
case "end":
|
|
49733
|
-
return "flex-end";
|
|
49734
|
-
case "center":
|
|
49735
|
-
return "center";
|
|
49736
|
-
case "stretch":
|
|
49737
|
-
return "stretch";
|
|
49738
|
-
case "baseline":
|
|
49739
|
-
return "baseline";
|
|
49740
|
-
default:
|
|
49741
|
-
return "stretch";
|
|
49742
|
-
}
|
|
49743
|
-
}
|
|
49744
|
-
function createFlexItemProps(contentSize, options = {}) {
|
|
49745
|
-
return {
|
|
49746
|
-
basis: options.basis ?? "auto",
|
|
49747
|
-
grow: options.grow ?? 0,
|
|
49748
|
-
shrink: options.shrink ?? 1,
|
|
49749
|
-
minSize: options.minSize ?? 0,
|
|
49750
|
-
maxSize: options.maxSize ?? Infinity,
|
|
49751
|
-
contentSize,
|
|
49752
|
-
alignSelf: options.alignSelf
|
|
49753
|
-
};
|
|
49754
|
-
}
|
|
49755
|
-
function createFlexGrowItemProps(contentSize, options = {}) {
|
|
49756
|
-
return {
|
|
49757
|
-
basis: options.basis ?? 0,
|
|
49758
|
-
grow: options.grow ?? 1,
|
|
49759
|
-
shrink: options.shrink ?? 1,
|
|
49760
|
-
minSize: options.minSize ?? 0,
|
|
49761
|
-
maxSize: options.maxSize ?? Infinity,
|
|
49762
|
-
contentSize,
|
|
49763
|
-
alignSelf: options.alignSelf
|
|
49764
|
-
};
|
|
49765
|
-
}
|
|
49766
|
-
|
|
49767
49368
|
// src/renderer/svg/index.ts
|
|
49768
49369
|
var SvgRenderer = class {
|
|
49769
49370
|
options;
|
|
49770
49371
|
theme;
|
|
49771
|
-
|
|
49772
|
-
|
|
49773
|
-
|
|
49774
|
-
clipPathCounter = 0;
|
|
49775
|
-
// Default spacing values
|
|
49776
|
-
DEFAULT_GAP = 16;
|
|
49372
|
+
currentX = 0;
|
|
49373
|
+
currentY = 0;
|
|
49374
|
+
contentWidth = 0;
|
|
49777
49375
|
constructor(options = {}) {
|
|
49778
49376
|
this.options = {
|
|
49779
49377
|
width: options.width ?? 800,
|
|
@@ -49784,41 +49382,28 @@ var SvgRenderer = class {
|
|
|
49784
49382
|
fontFamily: options.fontFamily ?? "system-ui, -apple-system, sans-serif"
|
|
49785
49383
|
};
|
|
49786
49384
|
this.theme = defaultTheme;
|
|
49385
|
+
this.contentWidth = this.options.width - this.options.padding * 2;
|
|
49787
49386
|
}
|
|
49788
49387
|
/**
|
|
49789
49388
|
* Render a wireframe document to SVG
|
|
49790
49389
|
*/
|
|
49791
49390
|
render(doc) {
|
|
49792
|
-
this.
|
|
49793
|
-
this.
|
|
49391
|
+
this.currentX = this.options.padding;
|
|
49392
|
+
this.currentY = this.options.padding;
|
|
49794
49393
|
const firstPage = doc.children[0];
|
|
49795
49394
|
let width = this.options.width;
|
|
49796
49395
|
let height = this.options.height;
|
|
49797
|
-
if (firstPage) {
|
|
49798
|
-
const
|
|
49799
|
-
|
|
49800
|
-
|
|
49801
|
-
|
|
49802
|
-
if (hasExplicitWidth) {
|
|
49803
|
-
width = pageAny.width;
|
|
49804
|
-
}
|
|
49805
|
-
if (hasExplicitHeight) {
|
|
49806
|
-
height = pageAny.height;
|
|
49807
|
-
}
|
|
49808
|
-
} else if (firstPage.viewport !== void 0 || firstPage.device !== void 0) {
|
|
49809
|
-
const viewport = resolveViewport(firstPage.viewport, firstPage.device);
|
|
49810
|
-
width = viewport.width;
|
|
49811
|
-
height = viewport.height;
|
|
49812
|
-
}
|
|
49396
|
+
if (firstPage && (firstPage.viewport !== void 0 || firstPage.device !== void 0)) {
|
|
49397
|
+
const viewport = resolveViewport(firstPage.viewport, firstPage.device);
|
|
49398
|
+
width = viewport.width;
|
|
49399
|
+
height = viewport.height;
|
|
49400
|
+
this.contentWidth = width - this.options.padding * 2;
|
|
49813
49401
|
}
|
|
49814
|
-
this.pageWidth = width;
|
|
49815
|
-
this.pageHeight = height;
|
|
49816
49402
|
const content = doc.children.map((page) => this.renderPage(page)).join("\n");
|
|
49817
|
-
const allDefs = this.generateDefs() + "\n" + this.clipPathDefs.join("\n");
|
|
49818
49403
|
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
49819
49404
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
49820
49405
|
<defs>
|
|
49821
|
-
${
|
|
49406
|
+
${this.generateDefs()}
|
|
49822
49407
|
</defs>
|
|
49823
49408
|
<rect width="100%" height="100%" fill="${this.options.background}"/>
|
|
49824
49409
|
<g transform="scale(${this.options.scale})">
|
|
@@ -49828,7 +49413,7 @@ var SvgRenderer = class {
|
|
|
49828
49413
|
return { svg, width, height };
|
|
49829
49414
|
}
|
|
49830
49415
|
/**
|
|
49831
|
-
* Generate SVG defs (styles)
|
|
49416
|
+
* Generate SVG defs (styles, patterns, etc.)
|
|
49832
49417
|
*/
|
|
49833
49418
|
generateDefs() {
|
|
49834
49419
|
return `
|
|
@@ -49839,1500 +49424,684 @@ var SvgRenderer = class {
|
|
|
49839
49424
|
</style>
|
|
49840
49425
|
`;
|
|
49841
49426
|
}
|
|
49842
|
-
// ===========================================
|
|
49843
|
-
// Page Layout
|
|
49844
|
-
// ===========================================
|
|
49845
|
-
renderPage(page) {
|
|
49846
|
-
const padding = this.options.padding;
|
|
49847
|
-
const contentWidth = this.pageWidth - padding * 2;
|
|
49848
|
-
const contentHeight = this.pageHeight - padding * 2;
|
|
49849
|
-
const constraints = {
|
|
49850
|
-
maxWidth: contentWidth,
|
|
49851
|
-
maxHeight: contentHeight
|
|
49852
|
-
};
|
|
49853
|
-
const childBoxes = [];
|
|
49854
|
-
let currentY = padding;
|
|
49855
|
-
const isCentered = page.centered === true;
|
|
49856
|
-
const hasHeader = page.children.some((c) => c.type === "Header");
|
|
49857
|
-
const hasFooter = page.children.some((c) => c.type === "Footer");
|
|
49858
|
-
const hasMain = page.children.some((c) => c.type === "Main");
|
|
49859
|
-
if (hasHeader || hasFooter || hasMain) {
|
|
49860
|
-
return this.renderPageWithFixedLayout(page, padding, contentWidth, contentHeight);
|
|
49861
|
-
}
|
|
49862
|
-
const measurements = page.children.map((child) => this.measureNode(child, constraints));
|
|
49863
|
-
const gap = this.getGap(page) || this.DEFAULT_GAP;
|
|
49864
|
-
const totalChildrenHeight = measurements.reduce((sum, m, i) => {
|
|
49865
|
-
return sum + m.height + (i > 0 ? gap : 0);
|
|
49866
|
-
}, 0);
|
|
49867
|
-
if (isCentered) {
|
|
49868
|
-
const availableHeight = contentHeight;
|
|
49869
|
-
currentY = padding + Math.max(0, (availableHeight - totalChildrenHeight) / 2);
|
|
49870
|
-
}
|
|
49871
|
-
for (let i = 0; i < page.children.length; i++) {
|
|
49872
|
-
const child = page.children[i];
|
|
49873
|
-
const measurement = measurements[i];
|
|
49874
|
-
let childX = padding;
|
|
49875
|
-
if (isCentered || this.shouldCenterHorizontally(child)) {
|
|
49876
|
-
childX = padding + (contentWidth - measurement.width) / 2;
|
|
49877
|
-
}
|
|
49878
|
-
const box = this.layoutNode(child, childX, currentY, constraints);
|
|
49879
|
-
childBoxes.push(box);
|
|
49880
|
-
currentY += box.height + gap;
|
|
49881
|
-
}
|
|
49882
|
-
const elements = [];
|
|
49883
|
-
for (const box of childBoxes) {
|
|
49884
|
-
elements.push(this.renderBox(box));
|
|
49885
|
-
}
|
|
49886
|
-
return elements.join("\n");
|
|
49887
|
-
}
|
|
49888
49427
|
/**
|
|
49889
|
-
* Render page
|
|
49890
|
-
* Header at top, Footer at bottom, Main fills remaining space
|
|
49428
|
+
* Render a page node
|
|
49891
49429
|
*/
|
|
49892
|
-
|
|
49893
|
-
const constraints = {
|
|
49894
|
-
maxWidth: contentWidth,
|
|
49895
|
-
maxHeight: contentHeight
|
|
49896
|
-
};
|
|
49897
|
-
const header = page.children.find((c) => c.type === "Header");
|
|
49898
|
-
const footer = page.children.find((c) => c.type === "Footer");
|
|
49899
|
-
const otherChildren = page.children.filter((c) => c.type !== "Header" && c.type !== "Footer");
|
|
49430
|
+
renderPage(node) {
|
|
49900
49431
|
const elements = [];
|
|
49901
|
-
|
|
49902
|
-
|
|
49903
|
-
let currentY = padding;
|
|
49904
|
-
if (header) {
|
|
49905
|
-
const headerMeasure = this.measureNode(header, constraints);
|
|
49906
|
-
headerHeight = headerMeasure.height;
|
|
49907
|
-
const headerBox = this.layoutNode(header, padding, currentY, constraints);
|
|
49908
|
-
elements.push(this.renderBox(headerBox));
|
|
49909
|
-
}
|
|
49910
|
-
if (footer) {
|
|
49911
|
-
const footerMeasure = this.measureNode(footer, constraints);
|
|
49912
|
-
footerHeight = footerMeasure.height;
|
|
49913
|
-
const footerY = this.pageHeight - padding - footerHeight;
|
|
49914
|
-
const footerBox = this.layoutNode(footer, padding, footerY, constraints);
|
|
49915
|
-
elements.push(this.renderBox(footerBox));
|
|
49432
|
+
if (node.title) {
|
|
49433
|
+
elements.push(this.renderPageTitle(node.title));
|
|
49916
49434
|
}
|
|
49917
|
-
const
|
|
49918
|
-
|
|
49919
|
-
const mainHeight = mainEndY - mainStartY;
|
|
49920
|
-
if (otherChildren.length > 0) {
|
|
49921
|
-
const mainConstraints = {
|
|
49922
|
-
maxWidth: contentWidth,
|
|
49923
|
-
maxHeight: mainHeight
|
|
49924
|
-
};
|
|
49925
|
-
const clipId = `main-clip-${this.clipPathCounter++}`;
|
|
49926
|
-
this.clipPathDefs.push(`<clipPath id="${clipId}"><rect x="${padding}" y="${mainStartY}" width="${contentWidth}" height="${mainHeight}"/></clipPath>`);
|
|
49927
|
-
const mainContent = [];
|
|
49928
|
-
mainContent.push(`<g clip-path="url(#${clipId})">`);
|
|
49929
|
-
let childY = mainStartY;
|
|
49930
|
-
const gap = this.getGap(page) || 0;
|
|
49931
|
-
for (const child of otherChildren) {
|
|
49932
|
-
const childBox = this.layoutNode(child, padding, childY, mainConstraints);
|
|
49933
|
-
mainContent.push(this.renderBox(childBox));
|
|
49934
|
-
childY += childBox.height + gap;
|
|
49935
|
-
}
|
|
49936
|
-
mainContent.push(`</g>`);
|
|
49937
|
-
elements.push(mainContent.join("\n"));
|
|
49435
|
+
for (const child of node.children) {
|
|
49436
|
+
elements.push(this.renderNode(child));
|
|
49938
49437
|
}
|
|
49939
49438
|
return elements.join("\n");
|
|
49940
49439
|
}
|
|
49941
|
-
|
|
49942
|
-
|
|
49440
|
+
/**
|
|
49441
|
+
* Render page title
|
|
49442
|
+
*/
|
|
49443
|
+
renderPageTitle(title) {
|
|
49444
|
+
const fontSize = 24;
|
|
49445
|
+
const y = this.currentY + fontSize;
|
|
49446
|
+
this.currentY += fontSize + 16;
|
|
49447
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(title)}</text>`;
|
|
49943
49448
|
}
|
|
49944
|
-
|
|
49945
|
-
|
|
49946
|
-
|
|
49947
|
-
|
|
49449
|
+
/**
|
|
49450
|
+
* Render any AST node
|
|
49451
|
+
*/
|
|
49452
|
+
renderNode(node) {
|
|
49948
49453
|
switch (node.type) {
|
|
49454
|
+
// Layout nodes
|
|
49949
49455
|
case "Row":
|
|
49950
|
-
return this.
|
|
49456
|
+
return this.renderRow(node);
|
|
49951
49457
|
case "Col":
|
|
49952
|
-
return this.
|
|
49458
|
+
return this.renderCol(node);
|
|
49953
49459
|
case "Header":
|
|
49954
|
-
return this.
|
|
49955
|
-
case "Footer":
|
|
49956
|
-
return this.measureFooter(node, constraints);
|
|
49460
|
+
return this.renderHeader(node);
|
|
49957
49461
|
case "Main":
|
|
49958
|
-
return this.
|
|
49462
|
+
return this.renderMain(node);
|
|
49463
|
+
case "Footer":
|
|
49464
|
+
return this.renderFooter(node);
|
|
49959
49465
|
case "Sidebar":
|
|
49960
|
-
return this.
|
|
49466
|
+
return this.renderSidebar(node);
|
|
49467
|
+
// Container nodes
|
|
49961
49468
|
case "Card":
|
|
49962
|
-
return this.
|
|
49469
|
+
return this.renderCard(node);
|
|
49963
49470
|
case "Modal":
|
|
49964
|
-
return this.
|
|
49965
|
-
|
|
49966
|
-
return this.measureTitle(node);
|
|
49471
|
+
return this.renderModal(node);
|
|
49472
|
+
// Text nodes
|
|
49967
49473
|
case "Text":
|
|
49968
|
-
return this.
|
|
49969
|
-
case "
|
|
49970
|
-
return this.
|
|
49474
|
+
return this.renderText(node);
|
|
49475
|
+
case "Title":
|
|
49476
|
+
return this.renderTitle(node);
|
|
49477
|
+
case "Link":
|
|
49478
|
+
return this.renderLink(node);
|
|
49479
|
+
// Input nodes
|
|
49971
49480
|
case "Input":
|
|
49972
|
-
return this.
|
|
49481
|
+
return this.renderInput(node);
|
|
49973
49482
|
case "Textarea":
|
|
49974
|
-
return this.
|
|
49483
|
+
return this.renderTextarea(node);
|
|
49975
49484
|
case "Select":
|
|
49976
|
-
return this.
|
|
49485
|
+
return this.renderSelect(node);
|
|
49977
49486
|
case "Checkbox":
|
|
49978
|
-
return this.
|
|
49487
|
+
return this.renderCheckbox(node);
|
|
49979
49488
|
case "Radio":
|
|
49980
|
-
return this.
|
|
49489
|
+
return this.renderRadio(node);
|
|
49981
49490
|
case "Switch":
|
|
49982
|
-
return this.
|
|
49983
|
-
|
|
49984
|
-
|
|
49491
|
+
return this.renderSwitch(node);
|
|
49492
|
+
// Button
|
|
49493
|
+
case "Button":
|
|
49494
|
+
return this.renderButton(node);
|
|
49495
|
+
// Display nodes
|
|
49985
49496
|
case "Image":
|
|
49986
|
-
return this.
|
|
49497
|
+
return this.renderImage(node);
|
|
49987
49498
|
case "Placeholder":
|
|
49988
|
-
return this.
|
|
49499
|
+
return this.renderPlaceholder(node);
|
|
49989
49500
|
case "Avatar":
|
|
49990
|
-
return this.
|
|
49501
|
+
return this.renderAvatar(node);
|
|
49991
49502
|
case "Badge":
|
|
49992
|
-
return this.
|
|
49503
|
+
return this.renderBadge(node);
|
|
49504
|
+
// Data nodes
|
|
49993
49505
|
case "Table":
|
|
49994
|
-
return this.
|
|
49506
|
+
return this.renderTable(node);
|
|
49995
49507
|
case "List":
|
|
49996
|
-
return this.
|
|
49508
|
+
return this.renderList(node);
|
|
49509
|
+
// Feedback nodes
|
|
49997
49510
|
case "Alert":
|
|
49998
|
-
return this.
|
|
49511
|
+
return this.renderAlert(node);
|
|
49999
49512
|
case "Progress":
|
|
50000
|
-
return this.
|
|
49513
|
+
return this.renderProgress(node);
|
|
50001
49514
|
case "Spinner":
|
|
50002
|
-
return this.
|
|
49515
|
+
return this.renderSpinner(node);
|
|
49516
|
+
// Navigation nodes
|
|
50003
49517
|
case "Nav":
|
|
50004
|
-
return this.
|
|
49518
|
+
return this.renderNav(node);
|
|
50005
49519
|
case "Tabs":
|
|
50006
|
-
return this.
|
|
49520
|
+
return this.renderTabs(node);
|
|
50007
49521
|
case "Breadcrumb":
|
|
50008
|
-
return this.
|
|
50009
|
-
case "Icon":
|
|
50010
|
-
return this.measureIcon(node);
|
|
50011
|
-
case "Divider":
|
|
50012
|
-
return this.measureDivider(node, constraints);
|
|
49522
|
+
return this.renderBreadcrumb(node);
|
|
50013
49523
|
default:
|
|
50014
|
-
return
|
|
50015
|
-
}
|
|
50016
|
-
}
|
|
50017
|
-
measureRow(node, constraints) {
|
|
50018
|
-
const padding = this.getPadding(node);
|
|
50019
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50020
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50021
|
-
const childMeasurements = node.children.map(
|
|
50022
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50023
|
-
);
|
|
50024
|
-
const maxChildHeight = Math.max(...childMeasurements.map((m) => m.height), 0);
|
|
50025
|
-
const totalChildWidth = childMeasurements.reduce((sum, m) => sum + m.width, 0);
|
|
50026
|
-
const totalGapWidth = Math.max(0, (node.children.length - 1) * gap);
|
|
50027
|
-
const contentWidth = totalChildWidth + totalGapWidth + padding.left + padding.right;
|
|
50028
|
-
const hasExplicitWidth = "w" in node && node.w !== void 0;
|
|
50029
|
-
const width = hasExplicitWidth ? constraints.maxWidth : Math.min(contentWidth, constraints.maxWidth);
|
|
50030
|
-
return {
|
|
50031
|
-
width,
|
|
50032
|
-
height: maxChildHeight + padding.top + padding.bottom
|
|
50033
|
-
};
|
|
50034
|
-
}
|
|
50035
|
-
measureCol(node, constraints) {
|
|
50036
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50037
|
-
const padding = this.getPadding(node);
|
|
50038
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50039
|
-
const childMeasurements = node.children.map(
|
|
50040
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50041
|
-
);
|
|
50042
|
-
const totalHeight = childMeasurements.reduce(
|
|
50043
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50044
|
-
0
|
|
50045
|
-
);
|
|
50046
|
-
const maxChildWidth = Math.max(...childMeasurements.map((m) => m.width), 0);
|
|
50047
|
-
return {
|
|
50048
|
-
width: Math.max(maxChildWidth + padding.left + padding.right, constraints.maxWidth),
|
|
50049
|
-
height: totalHeight + padding.top + padding.bottom
|
|
50050
|
-
};
|
|
50051
|
-
}
|
|
50052
|
-
measureHeader(node, constraints) {
|
|
50053
|
-
const padding = this.getPadding(node);
|
|
50054
|
-
const height = this.resolveSize(node.h) || 56;
|
|
50055
|
-
return {
|
|
50056
|
-
width: constraints.maxWidth,
|
|
50057
|
-
height: height + padding.top + padding.bottom
|
|
50058
|
-
};
|
|
50059
|
-
}
|
|
50060
|
-
measureFooter(node, constraints) {
|
|
50061
|
-
const padding = this.getPadding(node);
|
|
50062
|
-
const height = this.resolveSize(node.h) || 60;
|
|
50063
|
-
return {
|
|
50064
|
-
width: constraints.maxWidth,
|
|
50065
|
-
height: height + padding.top + padding.bottom
|
|
50066
|
-
};
|
|
50067
|
-
}
|
|
50068
|
-
measureMain(node, constraints) {
|
|
50069
|
-
const padding = this.getPadding(node);
|
|
50070
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50071
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50072
|
-
const childMeasurements = node.children.map(
|
|
50073
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50074
|
-
);
|
|
50075
|
-
const totalHeight = childMeasurements.reduce(
|
|
50076
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50077
|
-
0
|
|
50078
|
-
);
|
|
50079
|
-
return {
|
|
50080
|
-
width: constraints.maxWidth,
|
|
50081
|
-
height: totalHeight + padding.top + padding.bottom
|
|
50082
|
-
};
|
|
50083
|
-
}
|
|
50084
|
-
measureSidebar(node, constraints) {
|
|
50085
|
-
const width = this.resolveSize(node.w) || 200;
|
|
50086
|
-
const padding = this.getPadding(node);
|
|
50087
|
-
const gap = this.getGap(node) ?? 8;
|
|
50088
|
-
const innerWidth = width - padding.left - padding.right;
|
|
50089
|
-
const childMeasurements = node.children.map(
|
|
50090
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50091
|
-
);
|
|
50092
|
-
const contentHeight = childMeasurements.reduce(
|
|
50093
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50094
|
-
0
|
|
50095
|
-
) + padding.top + padding.bottom;
|
|
50096
|
-
const explicitHeight = this.resolveSize(node.h);
|
|
50097
|
-
const height = explicitHeight || constraints.maxHeight || contentHeight;
|
|
50098
|
-
return { width, height };
|
|
50099
|
-
}
|
|
50100
|
-
measureCard(node, constraints) {
|
|
50101
|
-
let cardWidth = this.resolveSize(node.w);
|
|
50102
|
-
if (!cardWidth) {
|
|
50103
|
-
cardWidth = Math.min(360, constraints.maxWidth);
|
|
50104
|
-
} else {
|
|
50105
|
-
cardWidth = Math.min(cardWidth, constraints.maxWidth);
|
|
50106
|
-
}
|
|
50107
|
-
const explicitHeight = this.resolveSize(node.h);
|
|
50108
|
-
if (explicitHeight) {
|
|
50109
|
-
return { width: cardWidth, height: explicitHeight };
|
|
50110
|
-
}
|
|
50111
|
-
const padding = this.getPadding(node);
|
|
50112
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50113
|
-
const innerWidth = cardWidth - padding.left - padding.right;
|
|
50114
|
-
const childMeasurements = node.children.map(
|
|
50115
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50116
|
-
);
|
|
50117
|
-
let contentHeight = 0;
|
|
50118
|
-
if (node.title) {
|
|
50119
|
-
contentHeight += 28;
|
|
50120
|
-
}
|
|
50121
|
-
contentHeight += childMeasurements.reduce(
|
|
50122
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50123
|
-
0
|
|
50124
|
-
);
|
|
50125
|
-
return {
|
|
50126
|
-
width: cardWidth,
|
|
50127
|
-
height: contentHeight + padding.top + padding.bottom
|
|
50128
|
-
};
|
|
50129
|
-
}
|
|
50130
|
-
measureModal(node, constraints) {
|
|
50131
|
-
const width = this.resolveSize(node.w) || 400;
|
|
50132
|
-
const padding = this.getPadding(node);
|
|
50133
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50134
|
-
const innerWidth = width - padding.left - padding.right;
|
|
50135
|
-
const childMeasurements = node.children.map(
|
|
50136
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50137
|
-
);
|
|
50138
|
-
let contentHeight = node.title ? 40 : 0;
|
|
50139
|
-
contentHeight += childMeasurements.reduce(
|
|
50140
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50141
|
-
0
|
|
50142
|
-
);
|
|
50143
|
-
return {
|
|
50144
|
-
width,
|
|
50145
|
-
height: contentHeight + padding.top + padding.bottom
|
|
50146
|
-
};
|
|
50147
|
-
}
|
|
50148
|
-
measureTitle(node) {
|
|
50149
|
-
const level = node.level || 1;
|
|
50150
|
-
const fontSize = this.getTitleFontSize(level);
|
|
50151
|
-
const textWidth = this.estimateTextWidth(node.content, fontSize);
|
|
50152
|
-
return { width: textWidth, height: fontSize + 8 };
|
|
50153
|
-
}
|
|
50154
|
-
measureText(node) {
|
|
50155
|
-
const fontSize = this.resolveFontSize(node.size);
|
|
50156
|
-
const textWidth = this.estimateTextWidth(node.content, fontSize);
|
|
50157
|
-
return { width: textWidth, height: fontSize + 8 };
|
|
50158
|
-
}
|
|
50159
|
-
measureButton(node, constraints) {
|
|
50160
|
-
const hasIcon = !!node.icon;
|
|
50161
|
-
const isIconOnly = hasIcon && !node.content.trim();
|
|
50162
|
-
const iconSize = 16;
|
|
50163
|
-
const padding = 16;
|
|
50164
|
-
let width;
|
|
50165
|
-
if (this.isFullWidth(node)) {
|
|
50166
|
-
width = constraints.maxWidth;
|
|
50167
|
-
} else if (isIconOnly) {
|
|
50168
|
-
width = iconSize + padding * 2;
|
|
50169
|
-
} else if (hasIcon) {
|
|
50170
|
-
width = Math.max(80, this.estimateTextWidth(node.content, 14) + iconSize + 48);
|
|
50171
|
-
} else {
|
|
50172
|
-
width = Math.max(80, this.estimateTextWidth(node.content, 14) + 32);
|
|
50173
|
-
}
|
|
50174
|
-
return { width, height: 40 };
|
|
50175
|
-
}
|
|
50176
|
-
measureInput(node, constraints) {
|
|
50177
|
-
let width;
|
|
50178
|
-
if (this.resolveSize(node.w)) {
|
|
50179
|
-
width = this.resolveSize(node.w);
|
|
50180
|
-
} else if (constraints.inHeader) {
|
|
50181
|
-
const placeholderWidth = node.placeholder ? this.estimateTextWidth(node.placeholder, 14) : 60;
|
|
50182
|
-
width = Math.max(120, placeholderWidth + 24 + 100);
|
|
50183
|
-
} else {
|
|
50184
|
-
width = constraints.maxWidth;
|
|
50185
|
-
}
|
|
50186
|
-
let height = 36;
|
|
50187
|
-
if (node.label) height += 24;
|
|
50188
|
-
return { width, height };
|
|
50189
|
-
}
|
|
50190
|
-
measureTextarea(node, constraints) {
|
|
50191
|
-
const width = this.resolveSize(node.w) || constraints.maxWidth;
|
|
50192
|
-
let height = node.rows ? node.rows * 24 : 100;
|
|
50193
|
-
if (node.label) height += 24;
|
|
50194
|
-
return { width, height };
|
|
50195
|
-
}
|
|
50196
|
-
measureSelect(node, constraints) {
|
|
50197
|
-
const width = this.resolveSize(node.w) || constraints.maxWidth;
|
|
50198
|
-
let height = 40;
|
|
50199
|
-
if (node.label) height += 24;
|
|
50200
|
-
return { width, height };
|
|
50201
|
-
}
|
|
50202
|
-
measureCheckbox(node) {
|
|
50203
|
-
const labelWidth = node.label ? this.estimateTextWidth(node.label, 14) + 8 : 0;
|
|
50204
|
-
return { width: 18 + labelWidth, height: 24 };
|
|
50205
|
-
}
|
|
50206
|
-
measureRadio(node) {
|
|
50207
|
-
const labelWidth = node.label ? this.estimateTextWidth(node.label, 14) + 8 : 0;
|
|
50208
|
-
return { width: 18 + labelWidth, height: 24 };
|
|
50209
|
-
}
|
|
50210
|
-
measureSwitch(node) {
|
|
50211
|
-
const labelWidth = node.label ? this.estimateTextWidth(node.label, 14) + 8 : 0;
|
|
50212
|
-
return { width: 44 + labelWidth, height: 28 };
|
|
50213
|
-
}
|
|
50214
|
-
measureLink(node) {
|
|
50215
|
-
const fontSize = 14;
|
|
50216
|
-
const textWidth = this.estimateTextWidth(node.content, fontSize);
|
|
50217
|
-
return { width: textWidth, height: fontSize + 8 };
|
|
50218
|
-
}
|
|
50219
|
-
measureImage(node, constraints) {
|
|
50220
|
-
let width;
|
|
50221
|
-
if (this.isFullWidth(node)) {
|
|
50222
|
-
width = constraints.maxWidth;
|
|
50223
|
-
} else {
|
|
50224
|
-
width = this.resolveSize(node.w) || 200;
|
|
50225
|
-
}
|
|
50226
|
-
const height = this.resolveSize(node.h) || 150;
|
|
50227
|
-
return { width, height };
|
|
50228
|
-
}
|
|
50229
|
-
measurePlaceholder(node, constraints) {
|
|
50230
|
-
let width;
|
|
50231
|
-
if (node.w !== void 0) {
|
|
50232
|
-
width = this.isFullWidth(node) ? constraints.maxWidth : this.resolveSize(node.w) || 200;
|
|
50233
|
-
} else {
|
|
50234
|
-
width = constraints.maxWidth || 200;
|
|
50235
|
-
}
|
|
50236
|
-
const height = this.resolveSize(node.h) || 100;
|
|
50237
|
-
return { width, height };
|
|
50238
|
-
}
|
|
50239
|
-
measureAvatar(node, constraints) {
|
|
50240
|
-
const sizes = { xs: 24, sm: 32, md: 40, lg: 48, xl: 64 };
|
|
50241
|
-
const defaultSize = constraints?.inHeader ? "sm" : "md";
|
|
50242
|
-
const size = sizes[node.size || defaultSize] || 40;
|
|
50243
|
-
return { width: size, height: size };
|
|
50244
|
-
}
|
|
50245
|
-
measureBadge(node) {
|
|
50246
|
-
const width = Math.max(24, this.estimateTextWidth(node.content, 12) + 16);
|
|
50247
|
-
return { width, height: 22 };
|
|
50248
|
-
}
|
|
50249
|
-
measureTable(node) {
|
|
50250
|
-
const columns = node.columns || [];
|
|
50251
|
-
const rows = node.rows || [];
|
|
50252
|
-
const rowCount = rows.length || 3;
|
|
50253
|
-
const colWidth = 120;
|
|
50254
|
-
const rowHeight = 40;
|
|
50255
|
-
return {
|
|
50256
|
-
width: columns.length * colWidth,
|
|
50257
|
-
height: (rowCount + 1) * rowHeight
|
|
50258
|
-
};
|
|
50259
|
-
}
|
|
50260
|
-
measureList(node) {
|
|
50261
|
-
const items = node.items || [];
|
|
50262
|
-
const maxItemWidth = Math.max(...items.map((item) => {
|
|
50263
|
-
const content = typeof item === "string" ? item : item.content;
|
|
50264
|
-
return this.estimateTextWidth(content, 14);
|
|
50265
|
-
}), 100);
|
|
50266
|
-
return { width: maxItemWidth + 24, height: items.length * 28 };
|
|
50267
|
-
}
|
|
50268
|
-
measureAlert(_node, constraints) {
|
|
50269
|
-
const width = Math.min(400, constraints.maxWidth);
|
|
50270
|
-
return { width, height: 48 };
|
|
50271
|
-
}
|
|
50272
|
-
measureProgress(node, constraints) {
|
|
50273
|
-
const width = Math.min(200, constraints.maxWidth);
|
|
50274
|
-
let height = 8;
|
|
50275
|
-
if (node.label) height += 24;
|
|
50276
|
-
return { width, height };
|
|
50277
|
-
}
|
|
50278
|
-
measureSpinner(node) {
|
|
50279
|
-
const sizes = { xs: 16, sm: 20, md: 24, lg: 32, xl: 40 };
|
|
50280
|
-
const size = sizes[node.size || "md"] || 24;
|
|
50281
|
-
return { width: size, height: size };
|
|
50282
|
-
}
|
|
50283
|
-
measureNav(node) {
|
|
50284
|
-
const items = node.items || [];
|
|
50285
|
-
if (node.vertical) {
|
|
50286
|
-
const maxWidth = Math.max(...items.map((item) => {
|
|
50287
|
-
const label = typeof item === "string" ? item : item.label;
|
|
50288
|
-
return this.estimateTextWidth(label, 14);
|
|
50289
|
-
}), 100);
|
|
50290
|
-
return { width: maxWidth, height: items.length * 32 };
|
|
50291
|
-
} else {
|
|
50292
|
-
const totalWidth = items.reduce((sum, item) => {
|
|
50293
|
-
const label = typeof item === "string" ? item : item.label;
|
|
50294
|
-
return sum + this.estimateTextWidth(label, 14) + 24;
|
|
50295
|
-
}, 0);
|
|
50296
|
-
return { width: totalWidth, height: 32 };
|
|
49524
|
+
return `<!-- Unsupported: ${node.type} -->`;
|
|
50297
49525
|
}
|
|
50298
49526
|
}
|
|
50299
|
-
measureTabs(node) {
|
|
50300
|
-
const items = node.items || [];
|
|
50301
|
-
const totalWidth = items.reduce((sum, item) => {
|
|
50302
|
-
const label = typeof item === "string" ? item : item;
|
|
50303
|
-
return sum + this.estimateTextWidth(label, 14) + 32;
|
|
50304
|
-
}, 0);
|
|
50305
|
-
return { width: totalWidth, height: 44 };
|
|
50306
|
-
}
|
|
50307
|
-
measureBreadcrumb(node) {
|
|
50308
|
-
const items = node.items || [];
|
|
50309
|
-
const totalWidth = items.reduce((sum, item, idx) => {
|
|
50310
|
-
const label = typeof item === "string" ? item : item.label;
|
|
50311
|
-
return sum + this.estimateTextWidth(label, 14) + (idx < items.length - 1 ? 24 : 0);
|
|
50312
|
-
}, 0);
|
|
50313
|
-
return { width: totalWidth, height: 28 };
|
|
50314
|
-
}
|
|
50315
|
-
measureIcon(node) {
|
|
50316
|
-
const sizes = { xs: 12, sm: 16, md: 20, lg: 24, xl: 32 };
|
|
50317
|
-
const size = sizes[node.size || "md"] || 20;
|
|
50318
|
-
return { width: size, height: size };
|
|
50319
|
-
}
|
|
50320
|
-
measureDivider(_node, constraints) {
|
|
50321
|
-
return { width: constraints.maxWidth, height: 1 };
|
|
50322
|
-
}
|
|
50323
49527
|
// ===========================================
|
|
50324
|
-
// Layout
|
|
49528
|
+
// Layout Renderers
|
|
50325
49529
|
// ===========================================
|
|
50326
|
-
|
|
50327
|
-
|
|
50328
|
-
|
|
50329
|
-
|
|
50330
|
-
|
|
50331
|
-
|
|
50332
|
-
|
|
50333
|
-
return this.layoutHeader(node, x, y, constraints);
|
|
50334
|
-
case "Footer":
|
|
50335
|
-
return this.layoutFooter(node, x, y, constraints);
|
|
50336
|
-
case "Main":
|
|
50337
|
-
return this.layoutMain(node, x, y, constraints);
|
|
50338
|
-
case "Sidebar":
|
|
50339
|
-
return this.layoutSidebar(node, x, y, constraints);
|
|
50340
|
-
case "Card":
|
|
50341
|
-
return this.layoutCard(node, x, y, constraints);
|
|
50342
|
-
default:
|
|
50343
|
-
const size = this.measureNode(node, constraints);
|
|
50344
|
-
return {
|
|
50345
|
-
x,
|
|
50346
|
-
y,
|
|
50347
|
-
width: size.width,
|
|
50348
|
-
height: size.height,
|
|
50349
|
-
node,
|
|
50350
|
-
children: []
|
|
50351
|
-
};
|
|
50352
|
-
}
|
|
50353
|
-
}
|
|
50354
|
-
layoutRow(node, x, y, constraints) {
|
|
50355
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50356
|
-
const padding = this.getPadding(node);
|
|
50357
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50358
|
-
const justify = node.justify || "start";
|
|
50359
|
-
const align = node.align || (constraints.inHeader ? "center" : "start");
|
|
50360
|
-
const childMeasurements = node.children.map(
|
|
50361
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50362
|
-
);
|
|
50363
|
-
const flexItems = node.children.map((child, i) => {
|
|
50364
|
-
const measurement = childMeasurements[i];
|
|
50365
|
-
if ("w" in child && child.w !== void 0 && child.w !== "full") {
|
|
50366
|
-
const resolved = this.resolveSize(child.w);
|
|
50367
|
-
if (resolved !== void 0) {
|
|
50368
|
-
return createFlexItemProps(measurement.height, {
|
|
50369
|
-
basis: resolved,
|
|
50370
|
-
grow: 0,
|
|
50371
|
-
shrink: 0,
|
|
50372
|
-
minSize: resolved,
|
|
50373
|
-
maxSize: resolved,
|
|
50374
|
-
contentSize: measurement.width
|
|
50375
|
-
});
|
|
50376
|
-
}
|
|
50377
|
-
}
|
|
50378
|
-
if (this.isFlexContainer(child)) {
|
|
50379
|
-
return createFlexGrowItemProps(measurement.height, {
|
|
50380
|
-
basis: 0,
|
|
50381
|
-
grow: 1,
|
|
50382
|
-
shrink: 1,
|
|
50383
|
-
minSize: 0,
|
|
50384
|
-
maxSize: Infinity,
|
|
50385
|
-
contentSize: measurement.width
|
|
50386
|
-
});
|
|
50387
|
-
}
|
|
50388
|
-
if (constraints.inHeader && child.type === "Input") {
|
|
50389
|
-
return createFlexGrowItemProps(measurement.height, {
|
|
50390
|
-
basis: measurement.width,
|
|
50391
|
-
// auto = content size
|
|
50392
|
-
grow: 1,
|
|
50393
|
-
shrink: 1,
|
|
50394
|
-
minSize: 120,
|
|
50395
|
-
// min-width: 120px
|
|
50396
|
-
maxSize: Infinity,
|
|
50397
|
-
contentSize: measurement.width
|
|
50398
|
-
});
|
|
50399
|
-
}
|
|
50400
|
-
return createFlexItemProps(measurement.height, {
|
|
50401
|
-
basis: measurement.width,
|
|
50402
|
-
// auto = content size
|
|
50403
|
-
grow: 0,
|
|
50404
|
-
shrink: 1,
|
|
50405
|
-
minSize: 0,
|
|
50406
|
-
maxSize: Infinity,
|
|
50407
|
-
contentSize: measurement.width
|
|
50408
|
-
});
|
|
50409
|
-
});
|
|
50410
|
-
const flexConfig = {
|
|
50411
|
-
mainSize: innerWidth,
|
|
50412
|
-
crossSize: void 0,
|
|
50413
|
-
// Will use max child height
|
|
50414
|
-
direction: "row",
|
|
50415
|
-
justifyContent: toJustifyContent(justify),
|
|
50416
|
-
alignItems: toAlignItems(align),
|
|
50417
|
-
gap
|
|
50418
|
-
};
|
|
50419
|
-
const flexResult = computeFlexLayout(flexItems, flexConfig);
|
|
50420
|
-
const maxChildHeight = Math.max(...childMeasurements.map((m) => m.height), 0);
|
|
50421
|
-
const innerMaxHeight = constraints.maxHeight ? constraints.maxHeight - padding.top - padding.bottom : void 0;
|
|
50422
|
-
const effectiveHeight = innerMaxHeight || maxChildHeight;
|
|
50423
|
-
const rowHeight = effectiveHeight + padding.top + padding.bottom;
|
|
50424
|
-
const children = [];
|
|
50425
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
50426
|
-
const child = node.children[i];
|
|
50427
|
-
const flexItem = flexResult.items[i];
|
|
50428
|
-
const measurement = childMeasurements[i];
|
|
50429
|
-
const childX = x + padding.left + flexItem.mainPosition;
|
|
50430
|
-
let childY = y + padding.top;
|
|
50431
|
-
switch (align) {
|
|
50432
|
-
case "center":
|
|
50433
|
-
childY = y + padding.top + (maxChildHeight - measurement.height) / 2;
|
|
50434
|
-
break;
|
|
50435
|
-
case "end":
|
|
50436
|
-
childY = y + padding.top + (maxChildHeight - measurement.height);
|
|
50437
|
-
break;
|
|
50438
|
-
}
|
|
50439
|
-
const childBox = this.layoutNode(child, childX, childY, {
|
|
50440
|
-
...constraints,
|
|
50441
|
-
maxWidth: flexItem.mainSize,
|
|
50442
|
-
maxHeight: effectiveHeight
|
|
50443
|
-
});
|
|
50444
|
-
children.push(childBox);
|
|
50445
|
-
}
|
|
50446
|
-
return {
|
|
50447
|
-
x,
|
|
50448
|
-
y,
|
|
50449
|
-
width: constraints.maxWidth,
|
|
50450
|
-
height: rowHeight,
|
|
50451
|
-
node,
|
|
50452
|
-
children,
|
|
50453
|
-
padding
|
|
50454
|
-
};
|
|
50455
|
-
}
|
|
50456
|
-
layoutCol(node, x, y, constraints) {
|
|
50457
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50458
|
-
const padding = this.getPadding(node);
|
|
50459
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50460
|
-
const innerHeight = constraints.maxHeight ? constraints.maxHeight - padding.top - padding.bottom : void 0;
|
|
50461
|
-
const align = node.align || "stretch";
|
|
50462
|
-
const childMeasurements = node.children.map(
|
|
50463
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50464
|
-
);
|
|
50465
|
-
const flexItems = node.children.map((child, i) => {
|
|
50466
|
-
const measurement = childMeasurements[i];
|
|
50467
|
-
if ("h" in child && child.h !== void 0) {
|
|
50468
|
-
const resolved = this.resolveSize(child.h);
|
|
50469
|
-
if (resolved !== void 0) {
|
|
50470
|
-
return createFlexItemProps(measurement.width, {
|
|
50471
|
-
basis: resolved,
|
|
50472
|
-
grow: 0,
|
|
50473
|
-
shrink: 0,
|
|
50474
|
-
minSize: resolved,
|
|
50475
|
-
maxSize: resolved,
|
|
50476
|
-
contentSize: measurement.height
|
|
50477
|
-
});
|
|
50478
|
-
}
|
|
49530
|
+
renderRow(node) {
|
|
49531
|
+
const savedX = this.currentX;
|
|
49532
|
+
const savedY = this.currentY;
|
|
49533
|
+
const elements = [];
|
|
49534
|
+
const totalSpan = node.children.reduce((sum, child) => {
|
|
49535
|
+
if ("span" in child && typeof child.span === "number") {
|
|
49536
|
+
return sum + child.span;
|
|
50479
49537
|
}
|
|
50480
|
-
|
|
50481
|
-
|
|
50482
|
-
|
|
50483
|
-
|
|
50484
|
-
shrink: 1,
|
|
50485
|
-
minSize: 0,
|
|
50486
|
-
maxSize: Infinity,
|
|
50487
|
-
contentSize: measurement.height
|
|
50488
|
-
});
|
|
50489
|
-
}
|
|
50490
|
-
return createFlexItemProps(measurement.width, {
|
|
50491
|
-
basis: measurement.height,
|
|
50492
|
-
// auto = content size
|
|
50493
|
-
grow: 0,
|
|
50494
|
-
shrink: 1,
|
|
50495
|
-
minSize: 0,
|
|
50496
|
-
maxSize: Infinity,
|
|
50497
|
-
contentSize: measurement.height
|
|
50498
|
-
});
|
|
50499
|
-
});
|
|
50500
|
-
const flexConfig = {
|
|
50501
|
-
mainSize: innerHeight ?? childMeasurements.reduce(
|
|
50502
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50503
|
-
0
|
|
50504
|
-
),
|
|
50505
|
-
crossSize: innerWidth,
|
|
50506
|
-
direction: "column",
|
|
50507
|
-
justifyContent: "flex-start",
|
|
50508
|
-
alignItems: toAlignItems(align),
|
|
50509
|
-
gap
|
|
50510
|
-
};
|
|
50511
|
-
const flexResult = computeFlexLayout(flexItems, flexConfig);
|
|
50512
|
-
const children = [];
|
|
50513
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
50514
|
-
const child = node.children[i];
|
|
50515
|
-
const flexItem = flexResult.items[i];
|
|
50516
|
-
const measurement = childMeasurements[i];
|
|
50517
|
-
let childX = x + padding.left;
|
|
50518
|
-
let childWidth = align === "stretch" ? innerWidth : measurement.width;
|
|
50519
|
-
switch (align) {
|
|
50520
|
-
case "center":
|
|
50521
|
-
childX = x + padding.left + (innerWidth - measurement.width) / 2;
|
|
50522
|
-
break;
|
|
50523
|
-
case "end":
|
|
50524
|
-
childX = x + padding.left + (innerWidth - measurement.width);
|
|
50525
|
-
break;
|
|
50526
|
-
}
|
|
50527
|
-
const childY = y + padding.top + flexItem.mainPosition;
|
|
50528
|
-
const childBox = this.layoutNode(child, childX, childY, {
|
|
50529
|
-
...constraints,
|
|
50530
|
-
maxWidth: childWidth,
|
|
50531
|
-
maxHeight: flexItem.mainSize
|
|
50532
|
-
});
|
|
50533
|
-
children.push(childBox);
|
|
50534
|
-
}
|
|
50535
|
-
const totalHeight = flexResult.mainSizeUsed;
|
|
50536
|
-
return {
|
|
50537
|
-
x,
|
|
50538
|
-
y,
|
|
50539
|
-
width: constraints.maxWidth,
|
|
50540
|
-
height: totalHeight + padding.top + padding.bottom,
|
|
50541
|
-
node,
|
|
50542
|
-
children,
|
|
50543
|
-
padding
|
|
50544
|
-
};
|
|
50545
|
-
}
|
|
50546
|
-
rowContainsSidebarOrMain(row) {
|
|
50547
|
-
return row.children.some(
|
|
50548
|
-
(child) => child.type === "Sidebar" || child.type === "Main"
|
|
50549
|
-
);
|
|
50550
|
-
}
|
|
50551
|
-
layoutHeader(node, x, y, constraints) {
|
|
50552
|
-
const padding = this.getPadding(node);
|
|
50553
|
-
const height = this.resolveSize(node.h) || 56;
|
|
50554
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50555
|
-
const children = [];
|
|
50556
|
-
let currentY = y + padding.top;
|
|
49538
|
+
return sum + 1;
|
|
49539
|
+
}, 0);
|
|
49540
|
+
const colWidth = this.contentWidth / Math.max(totalSpan, 1);
|
|
49541
|
+
let maxHeight = 0;
|
|
50557
49542
|
for (const child of node.children) {
|
|
50558
|
-
const
|
|
50559
|
-
|
|
50560
|
-
|
|
50561
|
-
|
|
50562
|
-
|
|
50563
|
-
|
|
50564
|
-
|
|
50565
|
-
|
|
50566
|
-
const verticalOffset = (height - childBox.height) / 2;
|
|
50567
|
-
childBox.y = y + padding.top + verticalOffset;
|
|
50568
|
-
this.adjustChildrenY(childBox, verticalOffset);
|
|
50569
|
-
children.push(childBox);
|
|
50570
|
-
currentY += childBox.height;
|
|
50571
|
-
}
|
|
50572
|
-
return {
|
|
50573
|
-
x,
|
|
50574
|
-
y,
|
|
50575
|
-
width: constraints.maxWidth,
|
|
50576
|
-
height: height + padding.top + padding.bottom,
|
|
50577
|
-
node,
|
|
50578
|
-
children,
|
|
50579
|
-
padding
|
|
50580
|
-
};
|
|
50581
|
-
}
|
|
50582
|
-
adjustChildrenY(box, offset) {
|
|
50583
|
-
for (const child of box.children) {
|
|
50584
|
-
child.y += offset;
|
|
50585
|
-
this.adjustChildrenY(child, offset);
|
|
49543
|
+
const span = "span" in child && typeof child.span === "number" ? child.span : 1;
|
|
49544
|
+
const childWidth = colWidth * span;
|
|
49545
|
+
const startY = this.currentY;
|
|
49546
|
+
elements.push(this.renderNode(child));
|
|
49547
|
+
const childHeight = this.currentY - startY;
|
|
49548
|
+
maxHeight = Math.max(maxHeight, childHeight);
|
|
49549
|
+
this.currentX += childWidth;
|
|
49550
|
+
this.currentY = savedY;
|
|
50586
49551
|
}
|
|
49552
|
+
this.currentX = savedX;
|
|
49553
|
+
this.currentY = savedY + maxHeight;
|
|
49554
|
+
return elements.join("\n");
|
|
50587
49555
|
}
|
|
50588
|
-
|
|
50589
|
-
|
|
50590
|
-
* Only layout containers without explicit width should flex
|
|
50591
|
-
*/
|
|
50592
|
-
isFlexContainer(node) {
|
|
50593
|
-
if (node.type === "Main") return true;
|
|
50594
|
-
if (node.type === "Col" && !("w" in node && node.w !== void 0)) return true;
|
|
50595
|
-
return false;
|
|
49556
|
+
renderCol(node) {
|
|
49557
|
+
return node.children.map((child) => this.renderNode(child)).join("\n");
|
|
50596
49558
|
}
|
|
50597
|
-
|
|
50598
|
-
const
|
|
50599
|
-
const
|
|
50600
|
-
const
|
|
50601
|
-
const
|
|
50602
|
-
|
|
50603
|
-
|
|
50604
|
-
|
|
50605
|
-
|
|
50606
|
-
|
|
50607
|
-
|
|
50608
|
-
|
|
50609
|
-
|
|
50610
|
-
const verticalOffset = (height - childBox.height) / 2;
|
|
50611
|
-
childBox.y = y + padding.top + verticalOffset;
|
|
50612
|
-
this.adjustChildrenY(childBox, verticalOffset);
|
|
50613
|
-
children.push(childBox);
|
|
50614
|
-
currentY += childBox.height;
|
|
50615
|
-
}
|
|
50616
|
-
return {
|
|
50617
|
-
x,
|
|
50618
|
-
y,
|
|
50619
|
-
width: constraints.maxWidth,
|
|
50620
|
-
height: height + padding.top + padding.bottom,
|
|
50621
|
-
node,
|
|
50622
|
-
children,
|
|
50623
|
-
padding
|
|
50624
|
-
};
|
|
49559
|
+
renderHeader(node) {
|
|
49560
|
+
const height = 60;
|
|
49561
|
+
const x = this.currentX;
|
|
49562
|
+
const y = this.currentY;
|
|
49563
|
+
const savedY = this.currentY;
|
|
49564
|
+
this.currentY += 16;
|
|
49565
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49566
|
+
this.currentY = savedY + height + 8;
|
|
49567
|
+
return `
|
|
49568
|
+
<g transform="translate(${x}, ${y})">
|
|
49569
|
+
<rect width="${this.contentWidth}" height="${height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49570
|
+
${children}
|
|
49571
|
+
</g>`;
|
|
50625
49572
|
}
|
|
50626
|
-
|
|
50627
|
-
|
|
50628
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50629
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50630
|
-
const childMeasurements = node.children.map(
|
|
50631
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50632
|
-
);
|
|
50633
|
-
const children = [];
|
|
50634
|
-
let currentY = y + padding.top;
|
|
50635
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
50636
|
-
const child = node.children[i];
|
|
50637
|
-
const childBox = this.layoutNode(child, x + padding.left, currentY, {
|
|
50638
|
-
...constraints,
|
|
50639
|
-
maxWidth: innerWidth
|
|
50640
|
-
});
|
|
50641
|
-
children.push(childBox);
|
|
50642
|
-
currentY += childBox.height + gap;
|
|
50643
|
-
}
|
|
50644
|
-
const totalHeight = childMeasurements.reduce(
|
|
50645
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50646
|
-
0
|
|
50647
|
-
);
|
|
50648
|
-
return {
|
|
50649
|
-
x,
|
|
50650
|
-
y,
|
|
50651
|
-
width: constraints.maxWidth,
|
|
50652
|
-
height: totalHeight + padding.top + padding.bottom,
|
|
50653
|
-
node,
|
|
50654
|
-
children,
|
|
50655
|
-
padding
|
|
50656
|
-
};
|
|
49573
|
+
renderMain(node) {
|
|
49574
|
+
return node.children.map((c) => this.renderNode(c)).join("\n");
|
|
50657
49575
|
}
|
|
50658
|
-
|
|
50659
|
-
const
|
|
50660
|
-
const
|
|
50661
|
-
const
|
|
50662
|
-
const
|
|
50663
|
-
|
|
50664
|
-
|
|
50665
|
-
|
|
50666
|
-
|
|
50667
|
-
|
|
50668
|
-
|
|
50669
|
-
}
|
|
50670
|
-
|
|
50671
|
-
currentY += childBox.height + gap;
|
|
50672
|
-
}
|
|
50673
|
-
const contentHeight = currentY - y - padding.top - gap + padding.bottom;
|
|
50674
|
-
const height = constraints.maxHeight || Math.max(contentHeight, 200);
|
|
50675
|
-
return {
|
|
50676
|
-
x,
|
|
50677
|
-
y,
|
|
50678
|
-
width,
|
|
50679
|
-
height,
|
|
50680
|
-
node,
|
|
50681
|
-
children,
|
|
50682
|
-
padding
|
|
50683
|
-
};
|
|
49576
|
+
renderFooter(node) {
|
|
49577
|
+
const height = 60;
|
|
49578
|
+
const x = this.currentX;
|
|
49579
|
+
const y = this.currentY;
|
|
49580
|
+
const savedY = this.currentY;
|
|
49581
|
+
this.currentY += 16;
|
|
49582
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49583
|
+
this.currentY = savedY + height + 8;
|
|
49584
|
+
return `
|
|
49585
|
+
<g transform="translate(${x}, ${y})">
|
|
49586
|
+
<rect width="${this.contentWidth}" height="${height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49587
|
+
${children}
|
|
49588
|
+
</g>`;
|
|
50684
49589
|
}
|
|
50685
|
-
|
|
50686
|
-
|
|
50687
|
-
|
|
50688
|
-
|
|
50689
|
-
|
|
50690
|
-
const
|
|
50691
|
-
|
|
50692
|
-
const
|
|
50693
|
-
|
|
50694
|
-
|
|
50695
|
-
|
|
50696
|
-
|
|
50697
|
-
|
|
50698
|
-
|
|
50699
|
-
const childBox = this.layoutNode(child, x + padding.left, currentY, {
|
|
50700
|
-
...constraints,
|
|
50701
|
-
maxWidth: innerWidth
|
|
50702
|
-
});
|
|
50703
|
-
children.push(childBox);
|
|
50704
|
-
currentY += childBox.height + gap;
|
|
50705
|
-
}
|
|
50706
|
-
const totalHeight = currentY - y - gap + padding.bottom;
|
|
50707
|
-
return {
|
|
50708
|
-
x,
|
|
50709
|
-
y,
|
|
50710
|
-
width: cardWidth,
|
|
50711
|
-
height: totalHeight,
|
|
50712
|
-
node,
|
|
50713
|
-
children,
|
|
50714
|
-
padding
|
|
50715
|
-
};
|
|
49590
|
+
renderSidebar(node) {
|
|
49591
|
+
const width = 200;
|
|
49592
|
+
const height = 300;
|
|
49593
|
+
const x = this.currentX;
|
|
49594
|
+
const y = this.currentY;
|
|
49595
|
+
const savedY = this.currentY;
|
|
49596
|
+
this.currentY += 16;
|
|
49597
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49598
|
+
this.currentY = savedY + height + 8;
|
|
49599
|
+
return `
|
|
49600
|
+
<g transform="translate(${x}, ${y})">
|
|
49601
|
+
<rect width="${width}" height="${height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49602
|
+
${children}
|
|
49603
|
+
</g>`;
|
|
50716
49604
|
}
|
|
50717
49605
|
// ===========================================
|
|
50718
|
-
//
|
|
49606
|
+
// Container Renderers
|
|
50719
49607
|
// ===========================================
|
|
50720
|
-
|
|
50721
|
-
|
|
50722
|
-
|
|
50723
|
-
|
|
50724
|
-
|
|
50725
|
-
|
|
50726
|
-
|
|
50727
|
-
case "Header":
|
|
50728
|
-
return this.renderHeaderBox(box);
|
|
50729
|
-
case "Footer":
|
|
50730
|
-
return this.renderFooterBox(box);
|
|
50731
|
-
case "Main":
|
|
50732
|
-
return this.renderMainBox(box);
|
|
50733
|
-
case "Sidebar":
|
|
50734
|
-
return this.renderSidebarBox(box);
|
|
50735
|
-
case "Card":
|
|
50736
|
-
return this.renderCardBox(box);
|
|
50737
|
-
case "Modal":
|
|
50738
|
-
return this.renderModalBox(box);
|
|
50739
|
-
case "Title":
|
|
50740
|
-
return this.renderTitleBox(box);
|
|
50741
|
-
case "Text":
|
|
50742
|
-
return this.renderTextBox(box);
|
|
50743
|
-
case "Button":
|
|
50744
|
-
return this.renderButtonBox(box);
|
|
50745
|
-
case "Input":
|
|
50746
|
-
return this.renderInputBox(box);
|
|
50747
|
-
case "Textarea":
|
|
50748
|
-
return this.renderTextareaBox(box);
|
|
50749
|
-
case "Select":
|
|
50750
|
-
return this.renderSelectBox(box);
|
|
50751
|
-
case "Checkbox":
|
|
50752
|
-
return this.renderCheckboxBox(box);
|
|
50753
|
-
case "Radio":
|
|
50754
|
-
return this.renderRadioBox(box);
|
|
50755
|
-
case "Switch":
|
|
50756
|
-
return this.renderSwitchBox(box);
|
|
50757
|
-
case "Link":
|
|
50758
|
-
return this.renderLinkBox(box);
|
|
50759
|
-
case "Image":
|
|
50760
|
-
return this.renderImageBox(box);
|
|
50761
|
-
case "Placeholder":
|
|
50762
|
-
return this.renderPlaceholderBox(box);
|
|
50763
|
-
case "Avatar":
|
|
50764
|
-
return this.renderAvatarBox(box);
|
|
50765
|
-
case "Badge":
|
|
50766
|
-
return this.renderBadgeBox(box);
|
|
50767
|
-
case "Table":
|
|
50768
|
-
return this.renderTableBox(box);
|
|
50769
|
-
case "List":
|
|
50770
|
-
return this.renderListBox(box);
|
|
50771
|
-
case "Alert":
|
|
50772
|
-
return this.renderAlertBox(box);
|
|
50773
|
-
case "Progress":
|
|
50774
|
-
return this.renderProgressBox(box);
|
|
50775
|
-
case "Spinner":
|
|
50776
|
-
return this.renderSpinnerBox(box);
|
|
50777
|
-
case "Nav":
|
|
50778
|
-
return this.renderNavBox(box);
|
|
50779
|
-
case "Tabs":
|
|
50780
|
-
return this.renderTabsBox(box);
|
|
50781
|
-
case "Breadcrumb":
|
|
50782
|
-
return this.renderBreadcrumbBox(box);
|
|
50783
|
-
case "Icon":
|
|
50784
|
-
return this.renderIconBox(box);
|
|
50785
|
-
case "Divider":
|
|
50786
|
-
return this.renderDividerBox(box);
|
|
50787
|
-
default:
|
|
50788
|
-
return `<!-- Unsupported: ${box.node.type} -->`;
|
|
50789
|
-
}
|
|
50790
|
-
}
|
|
50791
|
-
renderRowBox(box) {
|
|
50792
|
-
const childrenSvg = box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50793
|
-
return childrenSvg;
|
|
50794
|
-
}
|
|
50795
|
-
renderColBox(box) {
|
|
50796
|
-
const childrenSvg = box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50797
|
-
return childrenSvg;
|
|
50798
|
-
}
|
|
50799
|
-
renderHeaderBox(box) {
|
|
50800
|
-
const node = box.node;
|
|
50801
|
-
const hasBorder = node.border !== false;
|
|
50802
|
-
let svg = `<g>
|
|
50803
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" fill="${this.theme.colors.background}"/>`;
|
|
50804
|
-
if (hasBorder) {
|
|
50805
|
-
svg += `<line x1="${box.x}" y1="${box.y + box.height}" x2="${box.x + box.width}" y2="${box.y + box.height}" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50806
|
-
}
|
|
50807
|
-
svg += box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50808
|
-
svg += `</g>`;
|
|
50809
|
-
return svg;
|
|
50810
|
-
}
|
|
50811
|
-
renderFooterBox(box) {
|
|
50812
|
-
const node = box.node;
|
|
50813
|
-
const hasBorder = node.border !== false;
|
|
50814
|
-
let svg = `<g>
|
|
50815
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" fill="${this.theme.colors.background}"`;
|
|
50816
|
-
if (hasBorder) {
|
|
50817
|
-
svg += ` stroke="${this.theme.colors.border}" stroke-width="1"`;
|
|
50818
|
-
}
|
|
50819
|
-
svg += `/>`;
|
|
50820
|
-
svg += box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50821
|
-
svg += `</g>`;
|
|
50822
|
-
return svg;
|
|
50823
|
-
}
|
|
50824
|
-
renderMainBox(box) {
|
|
50825
|
-
const childrenSvg = box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50826
|
-
return childrenSvg;
|
|
50827
|
-
}
|
|
50828
|
-
renderSidebarBox(box) {
|
|
50829
|
-
let svg = `<g>
|
|
50830
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50831
|
-
svg += box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50832
|
-
svg += `</g>`;
|
|
50833
|
-
return svg;
|
|
50834
|
-
}
|
|
50835
|
-
renderCardBox(box) {
|
|
50836
|
-
const node = box.node;
|
|
50837
|
-
const shadowAttr = node.shadow ? 'filter="url(#shadow)"' : "";
|
|
50838
|
-
let svg = `<g>
|
|
50839
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1" ${shadowAttr}/>`;
|
|
49608
|
+
renderCard(node) {
|
|
49609
|
+
const width = Math.min(300, this.contentWidth);
|
|
49610
|
+
const x = this.currentX;
|
|
49611
|
+
const y = this.currentY;
|
|
49612
|
+
const savedY = this.currentY;
|
|
49613
|
+
this.currentY += 16;
|
|
49614
|
+
let titleSvg = "";
|
|
50840
49615
|
if (node.title) {
|
|
50841
|
-
const
|
|
50842
|
-
|
|
49616
|
+
const titleFontSize = 16;
|
|
49617
|
+
titleSvg = `<text x="16" y="${titleFontSize + 12}" font-size="${titleFontSize}" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(node.title)}</text>`;
|
|
49618
|
+
this.currentY += titleFontSize + 8;
|
|
50843
49619
|
}
|
|
50844
|
-
|
|
50845
|
-
|
|
50846
|
-
|
|
49620
|
+
const childStartY = this.currentY - savedY;
|
|
49621
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49622
|
+
const contentHeight = Math.max(this.currentY - savedY, 100);
|
|
49623
|
+
this.currentY = savedY + contentHeight + 16;
|
|
49624
|
+
return `
|
|
49625
|
+
<g transform="translate(${x}, ${y})">
|
|
49626
|
+
<rect width="${width}" height="${contentHeight}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49627
|
+
${titleSvg}
|
|
49628
|
+
<g transform="translate(16, ${childStartY})">
|
|
49629
|
+
${children}
|
|
49630
|
+
</g>
|
|
49631
|
+
</g>`;
|
|
50847
49632
|
}
|
|
50848
|
-
|
|
50849
|
-
const
|
|
50850
|
-
const
|
|
50851
|
-
const
|
|
50852
|
-
|
|
50853
|
-
|
|
50854
|
-
<rect x="${modalX}" y="${modalY}" width="${box.width}" height="${box.height}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
49633
|
+
renderModal(node) {
|
|
49634
|
+
const width = 400;
|
|
49635
|
+
const height = 300;
|
|
49636
|
+
const x = (this.options.width - width) / 2;
|
|
49637
|
+
const y = (this.options.height - height) / 2;
|
|
49638
|
+
let titleSvg = "";
|
|
50855
49639
|
if (node.title) {
|
|
50856
|
-
|
|
50857
|
-
}
|
|
50858
|
-
for (const child of box.children) {
|
|
50859
|
-
const adjustedChild = { ...child, x: modalX + (child.x - box.x), y: modalY + (child.y - box.y) };
|
|
50860
|
-
svg += this.renderBox(adjustedChild);
|
|
50861
|
-
}
|
|
50862
|
-
svg += `</g>`;
|
|
50863
|
-
return svg;
|
|
50864
|
-
}
|
|
50865
|
-
renderTitleBox(box) {
|
|
50866
|
-
const node = box.node;
|
|
50867
|
-
const level = node.level || 1;
|
|
50868
|
-
const fontSize = this.getTitleFontSize(level);
|
|
50869
|
-
const textY = box.y + fontSize;
|
|
50870
|
-
let textX = box.x;
|
|
50871
|
-
let anchor = "start";
|
|
50872
|
-
if (node.align === "center") {
|
|
50873
|
-
textX = box.x + box.width / 2;
|
|
50874
|
-
anchor = "middle";
|
|
50875
|
-
} else if (node.align === "right") {
|
|
50876
|
-
textX = box.x + box.width;
|
|
50877
|
-
anchor = "end";
|
|
49640
|
+
titleSvg = `<text x="20" y="30" font-size="18" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(node.title)}</text>`;
|
|
50878
49641
|
}
|
|
50879
|
-
|
|
49642
|
+
const savedX = this.currentX;
|
|
49643
|
+
const savedY = this.currentY;
|
|
49644
|
+
this.currentX = 20;
|
|
49645
|
+
this.currentY = 50;
|
|
49646
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49647
|
+
this.currentX = savedX;
|
|
49648
|
+
this.currentY = savedY;
|
|
49649
|
+
return `
|
|
49650
|
+
<g>
|
|
49651
|
+
<rect width="100%" height="100%" fill="rgba(0,0,0,0.5)" opacity="0.5"/>
|
|
49652
|
+
<g transform="translate(${x}, ${y})">
|
|
49653
|
+
<rect width="${width}" height="${height}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49654
|
+
${titleSvg}
|
|
49655
|
+
${children}
|
|
49656
|
+
</g>
|
|
49657
|
+
</g>`;
|
|
50880
49658
|
}
|
|
50881
|
-
|
|
50882
|
-
|
|
49659
|
+
// ===========================================
|
|
49660
|
+
// Text Renderers
|
|
49661
|
+
// ===========================================
|
|
49662
|
+
renderText(node) {
|
|
50883
49663
|
const fontSize = this.resolveFontSize(node.size);
|
|
50884
49664
|
const fill = node.muted ? this.theme.colors.muted : this.theme.colors.foreground;
|
|
50885
49665
|
const fontWeight = node.weight || "normal";
|
|
50886
|
-
const
|
|
50887
|
-
|
|
50888
|
-
|
|
50889
|
-
if (node.align === "center") {
|
|
50890
|
-
textX = box.x + box.width / 2;
|
|
50891
|
-
anchor = "middle";
|
|
50892
|
-
} else if (node.align === "right") {
|
|
50893
|
-
textX = box.x + box.width;
|
|
50894
|
-
anchor = "end";
|
|
50895
|
-
}
|
|
50896
|
-
return `<text x="${textX}" y="${textY}" font-size="${fontSize}" font-weight="${fontWeight}" fill="${fill}" text-anchor="${anchor}">${this.escapeXml(node.content)}</text>`;
|
|
49666
|
+
const y = this.currentY + fontSize;
|
|
49667
|
+
this.currentY += fontSize + 8;
|
|
49668
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" font-weight="${fontWeight}" fill="${fill}">${this.escapeXml(node.content)}</text>`;
|
|
50897
49669
|
}
|
|
50898
|
-
|
|
50899
|
-
const
|
|
50900
|
-
const
|
|
50901
|
-
const
|
|
50902
|
-
|
|
50903
|
-
|
|
50904
|
-
let strokeAttr = "";
|
|
50905
|
-
if (node.secondary) {
|
|
50906
|
-
fill = this.theme.colors.secondary;
|
|
50907
|
-
} else if (node.outline) {
|
|
50908
|
-
fill = "white";
|
|
50909
|
-
textFill = this.theme.colors.foreground;
|
|
50910
|
-
strokeAttr = `stroke="${this.theme.colors.border}" stroke-width="1"`;
|
|
50911
|
-
} else if (node.ghost) {
|
|
50912
|
-
fill = "transparent";
|
|
50913
|
-
textFill = this.theme.colors.foreground;
|
|
50914
|
-
}
|
|
50915
|
-
let svg = `<g>
|
|
50916
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="4" fill="${fill}" ${strokeAttr}/>`;
|
|
50917
|
-
if (hasIcon) {
|
|
50918
|
-
const iconData = getIconData(node.icon);
|
|
50919
|
-
if (iconData) {
|
|
50920
|
-
const iconSize = 16;
|
|
50921
|
-
const iconX = isIconOnly ? box.x + (box.width - iconSize) / 2 : box.x + 16;
|
|
50922
|
-
const iconY = box.y + (box.height - iconSize) / 2;
|
|
50923
|
-
svg += this.renderIconPaths(iconData, iconX, iconY, iconSize, textFill);
|
|
50924
|
-
}
|
|
50925
|
-
}
|
|
50926
|
-
if (!isIconOnly) {
|
|
50927
|
-
const textX = hasIcon ? box.x + 36 + (box.width - 52) / 2 : box.x + box.width / 2;
|
|
50928
|
-
svg += `<text x="${textX}" y="${box.y + box.height / 2 + 5}" font-size="14" fill="${textFill}" text-anchor="middle">${this.escapeXml(node.content)}</text>`;
|
|
50929
|
-
}
|
|
50930
|
-
svg += `</g>`;
|
|
50931
|
-
return svg;
|
|
49670
|
+
renderTitle(node) {
|
|
49671
|
+
const level = node.level || 1;
|
|
49672
|
+
const fontSize = this.getTitleFontSize(level);
|
|
49673
|
+
const y = this.currentY + fontSize;
|
|
49674
|
+
this.currentY += fontSize + 12;
|
|
49675
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(node.content)}</text>`;
|
|
50932
49676
|
}
|
|
50933
|
-
|
|
50934
|
-
const
|
|
50935
|
-
|
|
50936
|
-
|
|
49677
|
+
renderLink(node) {
|
|
49678
|
+
const fontSize = 14;
|
|
49679
|
+
const y = this.currentY + fontSize;
|
|
49680
|
+
this.currentY += fontSize + 8;
|
|
49681
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" fill="${this.theme.colors.primary}" text-decoration="underline">${this.escapeXml(node.content)}</text>`;
|
|
49682
|
+
}
|
|
49683
|
+
// ===========================================
|
|
49684
|
+
// Input Renderers
|
|
49685
|
+
// ===========================================
|
|
49686
|
+
renderInput(node) {
|
|
49687
|
+
const width = 280;
|
|
49688
|
+
const height = 40;
|
|
49689
|
+
const x = this.currentX;
|
|
49690
|
+
let y = this.currentY;
|
|
49691
|
+
let result = "";
|
|
50937
49692
|
if (node.label) {
|
|
50938
|
-
|
|
49693
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50939
49694
|
y += 24;
|
|
50940
49695
|
}
|
|
50941
|
-
const inputHeight = 36;
|
|
50942
49696
|
const placeholder = node.placeholder || "";
|
|
50943
|
-
|
|
50944
|
-
|
|
50945
|
-
|
|
50946
|
-
|
|
49697
|
+
result += `
|
|
49698
|
+
<g transform="translate(${x}, ${y})">
|
|
49699
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49700
|
+
<text x="12" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(placeholder)}</text>
|
|
49701
|
+
</g>`;
|
|
49702
|
+
this.currentY = y + height + 12;
|
|
49703
|
+
return result;
|
|
50947
49704
|
}
|
|
50948
|
-
|
|
50949
|
-
const
|
|
50950
|
-
|
|
50951
|
-
|
|
49705
|
+
renderTextarea(node) {
|
|
49706
|
+
const width = 280;
|
|
49707
|
+
const height = 100;
|
|
49708
|
+
const x = this.currentX;
|
|
49709
|
+
let y = this.currentY;
|
|
49710
|
+
let result = "";
|
|
50952
49711
|
if (node.label) {
|
|
50953
|
-
|
|
49712
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50954
49713
|
y += 24;
|
|
50955
49714
|
}
|
|
50956
|
-
const textareaHeight = box.height - (node.label ? 24 : 0);
|
|
50957
49715
|
const placeholder = node.placeholder || "";
|
|
50958
|
-
|
|
50959
|
-
|
|
50960
|
-
|
|
50961
|
-
|
|
49716
|
+
result += `
|
|
49717
|
+
<g transform="translate(${x}, ${y})">
|
|
49718
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49719
|
+
<text x="12" y="24" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(placeholder)}</text>
|
|
49720
|
+
</g>`;
|
|
49721
|
+
this.currentY = y + height + 12;
|
|
49722
|
+
return result;
|
|
50962
49723
|
}
|
|
50963
|
-
|
|
50964
|
-
const
|
|
50965
|
-
|
|
50966
|
-
|
|
49724
|
+
renderSelect(node) {
|
|
49725
|
+
const width = 280;
|
|
49726
|
+
const height = 40;
|
|
49727
|
+
const x = this.currentX;
|
|
49728
|
+
let y = this.currentY;
|
|
49729
|
+
let result = "";
|
|
50967
49730
|
if (node.label) {
|
|
50968
|
-
|
|
49731
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50969
49732
|
y += 24;
|
|
50970
49733
|
}
|
|
50971
|
-
const selectHeight = 40;
|
|
50972
49734
|
const placeholder = node.placeholder || "Select...";
|
|
50973
|
-
|
|
50974
|
-
|
|
50975
|
-
|
|
50976
|
-
|
|
50977
|
-
|
|
49735
|
+
result += `
|
|
49736
|
+
<g transform="translate(${x}, ${y})">
|
|
49737
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49738
|
+
<text x="12" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(placeholder)}</text>
|
|
49739
|
+
<path d="M${width - 24} ${height / 2 - 3} l6 6 l6 -6" fill="none" stroke="${this.theme.colors.muted}" stroke-width="1.5"/>
|
|
49740
|
+
</g>`;
|
|
49741
|
+
this.currentY = y + height + 12;
|
|
49742
|
+
return result;
|
|
50978
49743
|
}
|
|
50979
|
-
|
|
50980
|
-
const
|
|
49744
|
+
renderCheckbox(node) {
|
|
49745
|
+
const x = this.currentX;
|
|
49746
|
+
const y = this.currentY;
|
|
50981
49747
|
const size = 18;
|
|
50982
|
-
let
|
|
50983
|
-
|
|
49748
|
+
let result = `
|
|
49749
|
+
<g transform="translate(${x}, ${y})">
|
|
49750
|
+
<rect width="${size}" height="${size}" rx="3" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50984
49751
|
if (node.checked) {
|
|
50985
|
-
|
|
49752
|
+
result += `<path d="M4 9 L7 12 L14 5" fill="none" stroke="${this.theme.colors.foreground}" stroke-width="2"/>`;
|
|
50986
49753
|
}
|
|
50987
49754
|
if (node.label) {
|
|
50988
|
-
|
|
49755
|
+
result += `<text x="${size + 8}" y="${size - 3}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50989
49756
|
}
|
|
50990
|
-
|
|
50991
|
-
|
|
49757
|
+
result += "</g>";
|
|
49758
|
+
this.currentY += size + 12;
|
|
49759
|
+
return result;
|
|
50992
49760
|
}
|
|
50993
|
-
|
|
50994
|
-
const
|
|
49761
|
+
renderRadio(node) {
|
|
49762
|
+
const x = this.currentX;
|
|
49763
|
+
const y = this.currentY;
|
|
50995
49764
|
const size = 18;
|
|
50996
49765
|
const radius = size / 2;
|
|
50997
|
-
|
|
50998
|
-
|
|
50999
|
-
|
|
51000
|
-
<circle cx="${cx}" cy="${cy}" r="${radius - 1}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
49766
|
+
let result = `
|
|
49767
|
+
<g transform="translate(${x}, ${y})">
|
|
49768
|
+
<circle cx="${radius}" cy="${radius}" r="${radius - 1}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51001
49769
|
if (node.checked) {
|
|
51002
|
-
|
|
49770
|
+
result += `<circle cx="${radius}" cy="${radius}" r="${radius - 5}" fill="${this.theme.colors.foreground}"/>`;
|
|
51003
49771
|
}
|
|
51004
49772
|
if (node.label) {
|
|
51005
|
-
|
|
49773
|
+
result += `<text x="${size + 8}" y="${size - 3}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
51006
49774
|
}
|
|
51007
|
-
|
|
51008
|
-
|
|
49775
|
+
result += "</g>";
|
|
49776
|
+
this.currentY += size + 12;
|
|
49777
|
+
return result;
|
|
51009
49778
|
}
|
|
51010
|
-
|
|
51011
|
-
const
|
|
49779
|
+
renderSwitch(node) {
|
|
49780
|
+
const x = this.currentX;
|
|
49781
|
+
const y = this.currentY;
|
|
51012
49782
|
const width = 44;
|
|
51013
49783
|
const height = 24;
|
|
51014
49784
|
const radius = height / 2;
|
|
51015
49785
|
const isOn = node.checked;
|
|
51016
49786
|
const bgColor = isOn ? this.theme.colors.primary : this.theme.colors.border;
|
|
51017
|
-
const knobX = isOn ?
|
|
51018
|
-
let
|
|
51019
|
-
|
|
51020
|
-
<
|
|
49787
|
+
const knobX = isOn ? width - radius : radius;
|
|
49788
|
+
let result = `
|
|
49789
|
+
<g transform="translate(${x}, ${y})">
|
|
49790
|
+
<rect width="${width}" height="${height}" rx="${radius}" fill="${bgColor}"/>
|
|
49791
|
+
<circle cx="${knobX}" cy="${radius}" r="${radius - 3}" fill="white"/>`;
|
|
51021
49792
|
if (node.label) {
|
|
51022
|
-
|
|
49793
|
+
result += `<text x="${width + 8}" y="${height - 6}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
51023
49794
|
}
|
|
51024
|
-
|
|
51025
|
-
|
|
49795
|
+
result += "</g>";
|
|
49796
|
+
this.currentY += height + 12;
|
|
49797
|
+
return result;
|
|
51026
49798
|
}
|
|
51027
|
-
|
|
51028
|
-
|
|
51029
|
-
|
|
51030
|
-
|
|
51031
|
-
|
|
49799
|
+
// ===========================================
|
|
49800
|
+
// Button Renderer
|
|
49801
|
+
// ===========================================
|
|
49802
|
+
renderButton(node) {
|
|
49803
|
+
const content = node.content;
|
|
49804
|
+
const hasIcon = !!node.icon;
|
|
49805
|
+
const isIconOnly = hasIcon && !content.trim();
|
|
49806
|
+
const iconSize = 16;
|
|
49807
|
+
const padding = isIconOnly ? 8 : 16;
|
|
49808
|
+
let width;
|
|
49809
|
+
if (isIconOnly) {
|
|
49810
|
+
width = iconSize + padding * 2;
|
|
49811
|
+
} else if (hasIcon) {
|
|
49812
|
+
width = Math.max(80, content.length * 10 + iconSize + 40);
|
|
49813
|
+
} else {
|
|
49814
|
+
width = Math.max(80, content.length * 10 + 32);
|
|
49815
|
+
}
|
|
49816
|
+
const height = 36;
|
|
49817
|
+
const x = this.currentX;
|
|
49818
|
+
const y = this.currentY;
|
|
49819
|
+
let fill = this.theme.colors.primary;
|
|
49820
|
+
let textFill = "#ffffff";
|
|
49821
|
+
let isOutline = false;
|
|
49822
|
+
if (node.secondary) {
|
|
49823
|
+
fill = this.theme.colors.secondary;
|
|
49824
|
+
} else if (node.outline) {
|
|
49825
|
+
fill = "white";
|
|
49826
|
+
textFill = this.theme.colors.foreground;
|
|
49827
|
+
isOutline = true;
|
|
49828
|
+
} else if (node.ghost) {
|
|
49829
|
+
fill = "transparent";
|
|
49830
|
+
textFill = this.theme.colors.foreground;
|
|
49831
|
+
}
|
|
49832
|
+
this.currentY += height + 8;
|
|
49833
|
+
const strokeAttr = isOutline ? `stroke="${this.theme.colors.border}" stroke-width="1"` : "";
|
|
49834
|
+
let iconSvg = "";
|
|
49835
|
+
if (hasIcon) {
|
|
49836
|
+
const iconData = getIconData(node.icon);
|
|
49837
|
+
if (iconData) {
|
|
49838
|
+
const iconX = isIconOnly ? (width - iconSize) / 2 : padding;
|
|
49839
|
+
const iconY = (height - iconSize) / 2;
|
|
49840
|
+
iconSvg = this.renderIconPaths(iconData, iconX, iconY, iconSize, textFill);
|
|
49841
|
+
}
|
|
49842
|
+
}
|
|
49843
|
+
const textX = hasIcon && !isIconOnly ? padding + iconSize + 8 + (width - padding - iconSize - 8 - padding) / 2 : width / 2;
|
|
49844
|
+
const textContent = isIconOnly ? "" : `<text x="${textX}" y="${height / 2 + 5}" font-size="14" fill="${textFill}" text-anchor="middle">${this.escapeXml(content)}</text>`;
|
|
49845
|
+
return `
|
|
49846
|
+
<g transform="translate(${x}, ${y})">
|
|
49847
|
+
<rect width="${width}" height="${height}" rx="4" fill="${fill}" ${strokeAttr}/>
|
|
49848
|
+
${iconSvg}
|
|
49849
|
+
${textContent}
|
|
49850
|
+
</g>`;
|
|
49851
|
+
}
|
|
49852
|
+
/**
|
|
49853
|
+
* Render icon paths for SVG
|
|
49854
|
+
*/
|
|
49855
|
+
renderIconPaths(data, x, y, size, color) {
|
|
49856
|
+
const scale = size / 24;
|
|
49857
|
+
const paths = data.map(([tag, attrs]) => {
|
|
49858
|
+
const attrStr = Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(" ");
|
|
49859
|
+
return `<${tag} ${attrStr} />`;
|
|
49860
|
+
}).join("");
|
|
49861
|
+
return `<g transform="translate(${x}, ${y}) scale(${scale})" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${paths}</g>`;
|
|
51032
49862
|
}
|
|
51033
|
-
|
|
51034
|
-
|
|
51035
|
-
|
|
51036
|
-
|
|
51037
|
-
|
|
51038
|
-
|
|
51039
|
-
|
|
49863
|
+
// ===========================================
|
|
49864
|
+
// Display Renderers
|
|
49865
|
+
// ===========================================
|
|
49866
|
+
renderImage(node) {
|
|
49867
|
+
const width = node.w && typeof node.w === "number" ? node.w : 200;
|
|
49868
|
+
const height = node.h && typeof node.h === "number" ? node.h : 150;
|
|
49869
|
+
const x = this.currentX;
|
|
49870
|
+
const y = this.currentY;
|
|
49871
|
+
this.currentY += height + 12;
|
|
49872
|
+
return `
|
|
49873
|
+
<g transform="translate(${x}, ${y})">
|
|
49874
|
+
<rect width="${width}" height="${height}" fill="${this.theme.colors.muted}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49875
|
+
<line x1="0" y1="0" x2="${width}" y2="${height}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49876
|
+
<line x1="${width}" y1="0" x2="0" y2="${height}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49877
|
+
<text x="${width / 2}" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.foreground}" text-anchor="middle">${this.escapeXml(node.alt || "Image")}</text>
|
|
51040
49878
|
</g>`;
|
|
51041
49879
|
}
|
|
51042
|
-
|
|
51043
|
-
const
|
|
51044
|
-
const
|
|
51045
|
-
const
|
|
51046
|
-
|
|
51047
|
-
|
|
51048
|
-
|
|
51049
|
-
|
|
51050
|
-
|
|
51051
|
-
<
|
|
51052
|
-
<text x="${box.x + box.width / 2}" y="${box.y + box.height / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}" text-anchor="middle">${this.escapeXml(node.label || "Placeholder")}</text>
|
|
49880
|
+
renderPlaceholder(node) {
|
|
49881
|
+
const width = node.w && typeof node.w === "number" ? node.w : 200;
|
|
49882
|
+
const height = node.h && typeof node.h === "number" ? node.h : 100;
|
|
49883
|
+
const x = this.currentX;
|
|
49884
|
+
const y = this.currentY;
|
|
49885
|
+
this.currentY += height + 12;
|
|
49886
|
+
return `
|
|
49887
|
+
<g transform="translate(${x}, ${y})">
|
|
49888
|
+
<rect width="${width}" height="${height}" fill="${this.theme.colors.muted}" stroke="${this.theme.colors.border}" stroke-width="1" stroke-dasharray="4,4"/>
|
|
49889
|
+
<text x="${width / 2}" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.foreground}" text-anchor="middle">${this.escapeXml(node.label || "Placeholder")}</text>
|
|
51053
49890
|
</g>`;
|
|
51054
49891
|
}
|
|
51055
|
-
|
|
51056
|
-
const
|
|
51057
|
-
const
|
|
51058
|
-
const
|
|
51059
|
-
const
|
|
49892
|
+
renderAvatar(node) {
|
|
49893
|
+
const sizes = { xs: 24, sm: 32, md: 40, lg: 48, xl: 64 };
|
|
49894
|
+
const size = sizes[node.size || "md"] || 40;
|
|
49895
|
+
const radius = size / 2;
|
|
49896
|
+
const x = this.currentX;
|
|
49897
|
+
const y = this.currentY;
|
|
51060
49898
|
const initial = node.name ? node.name.charAt(0).toUpperCase() : "?";
|
|
51061
|
-
|
|
51062
|
-
|
|
51063
|
-
|
|
49899
|
+
this.currentY += size + 12;
|
|
49900
|
+
return `
|
|
49901
|
+
<g transform="translate(${x}, ${y})">
|
|
49902
|
+
<circle cx="${radius}" cy="${radius}" r="${radius}" fill="${this.theme.colors.muted}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49903
|
+
<text x="${radius}" y="${radius + 5}" font-size="${size / 2.5}" fill="${this.theme.colors.foreground}" text-anchor="middle">${initial}</text>
|
|
51064
49904
|
</g>`;
|
|
51065
49905
|
}
|
|
51066
|
-
|
|
51067
|
-
const
|
|
51068
|
-
|
|
51069
|
-
|
|
51070
|
-
|
|
49906
|
+
renderBadge(node) {
|
|
49907
|
+
const content = node.content;
|
|
49908
|
+
const width = Math.max(24, content.length * 8 + 16);
|
|
49909
|
+
const height = 22;
|
|
49910
|
+
const x = this.currentX;
|
|
49911
|
+
const y = this.currentY;
|
|
49912
|
+
const fill = this.theme.colors.muted;
|
|
49913
|
+
const textFill = this.theme.colors.foreground;
|
|
49914
|
+
this.currentY += height + 8;
|
|
49915
|
+
return `
|
|
49916
|
+
<g transform="translate(${x}, ${y})">
|
|
49917
|
+
<rect width="${width}" height="${height}" rx="11" fill="${fill}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49918
|
+
<text x="${width / 2}" y="${height / 2 + 4}" font-size="12" fill="${textFill}" text-anchor="middle">${this.escapeXml(content)}</text>
|
|
51071
49919
|
</g>`;
|
|
51072
49920
|
}
|
|
51073
|
-
|
|
51074
|
-
|
|
49921
|
+
// ===========================================
|
|
49922
|
+
// Data Renderers
|
|
49923
|
+
// ===========================================
|
|
49924
|
+
renderTable(node) {
|
|
51075
49925
|
const columns = node.columns || [];
|
|
51076
49926
|
const rows = node.rows || [];
|
|
51077
49927
|
const rowCount = rows.length || 3;
|
|
51078
49928
|
const colWidth = 120;
|
|
51079
49929
|
const rowHeight = 40;
|
|
51080
|
-
|
|
51081
|
-
|
|
49930
|
+
const x = this.currentX;
|
|
49931
|
+
const y = this.currentY;
|
|
49932
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
49933
|
+
svg += `<rect width="${columns.length * colWidth}" height="${rowHeight}" fill="${this.theme.colors.muted}"/>`;
|
|
51082
49934
|
columns.forEach((col, i) => {
|
|
51083
|
-
svg += `<text x="${
|
|
49935
|
+
svg += `<text x="${i * colWidth + 12}" y="${rowHeight / 2 + 5}" font-size="14" font-weight="600">${this.escapeXml(col)}</text>`;
|
|
51084
49936
|
});
|
|
51085
|
-
const displayRowCount = rows.length > 0 ? rows.length : rowCount;
|
|
49937
|
+
const displayRowCount = rows.length > 0 ? rows.length : Math.max(rowCount, 3);
|
|
51086
49938
|
for (let rowIdx = 0; rowIdx < displayRowCount; rowIdx++) {
|
|
51087
|
-
const rowY =
|
|
51088
|
-
svg += `<rect
|
|
49939
|
+
const rowY = (rowIdx + 1) * rowHeight;
|
|
49940
|
+
svg += `<rect y="${rowY}" width="${columns.length * colWidth}" height="${rowHeight}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51089
49941
|
columns.forEach((_, colIdx) => {
|
|
51090
49942
|
const cellContent = rows[rowIdx] && rows[rowIdx][colIdx] ? String(typeof rows[rowIdx][colIdx] === "object" ? "..." : rows[rowIdx][colIdx]) : "\u2014";
|
|
51091
|
-
svg += `<text x="${
|
|
49943
|
+
svg += `<text x="${colIdx * colWidth + 12}" y="${rowY + rowHeight / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(cellContent)}</text>`;
|
|
51092
49944
|
});
|
|
51093
49945
|
}
|
|
51094
49946
|
svg += "</g>";
|
|
49947
|
+
this.currentY += (displayRowCount + 1) * rowHeight + 16;
|
|
51095
49948
|
return svg;
|
|
51096
49949
|
}
|
|
51097
|
-
|
|
51098
|
-
const
|
|
49950
|
+
renderList(node) {
|
|
49951
|
+
const x = this.currentX;
|
|
49952
|
+
let y = this.currentY;
|
|
51099
49953
|
const items = node.items || [];
|
|
51100
49954
|
const ordered = node.ordered || false;
|
|
51101
|
-
let svg =
|
|
49955
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51102
49956
|
items.forEach((item, idx) => {
|
|
51103
49957
|
const marker = ordered ? `${idx + 1}.` : "\u2022";
|
|
51104
49958
|
const content = typeof item === "string" ? item : item.content;
|
|
51105
|
-
svg += `<text x="
|
|
49959
|
+
svg += `<text x="0" y="${idx * 24 + 16}" font-size="14" fill="${this.theme.colors.foreground}">${marker} ${this.escapeXml(content)}</text>`;
|
|
51106
49960
|
});
|
|
51107
49961
|
svg += "</g>";
|
|
49962
|
+
this.currentY += items.length * 24 + 12;
|
|
51108
49963
|
return svg;
|
|
51109
49964
|
}
|
|
51110
|
-
|
|
51111
|
-
|
|
51112
|
-
|
|
51113
|
-
|
|
51114
|
-
|
|
49965
|
+
// ===========================================
|
|
49966
|
+
// Feedback Renderers
|
|
49967
|
+
// ===========================================
|
|
49968
|
+
renderAlert(node) {
|
|
49969
|
+
const width = Math.min(400, this.contentWidth);
|
|
49970
|
+
const height = 48;
|
|
49971
|
+
const x = this.currentX;
|
|
49972
|
+
const y = this.currentY;
|
|
49973
|
+
this.currentY += height + 12;
|
|
49974
|
+
return `
|
|
49975
|
+
<g transform="translate(${x}, ${y})">
|
|
49976
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49977
|
+
<text x="16" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.content)}</text>
|
|
51115
49978
|
</g>`;
|
|
51116
49979
|
}
|
|
51117
|
-
|
|
51118
|
-
const
|
|
51119
|
-
|
|
51120
|
-
|
|
49980
|
+
renderProgress(node) {
|
|
49981
|
+
const width = 200;
|
|
49982
|
+
const height = 8;
|
|
49983
|
+
const x = this.currentX;
|
|
49984
|
+
let y = this.currentY;
|
|
49985
|
+
let result = "";
|
|
51121
49986
|
if (node.label) {
|
|
51122
|
-
|
|
49987
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
51123
49988
|
y += 24;
|
|
51124
49989
|
}
|
|
51125
|
-
const barHeight = 8;
|
|
51126
49990
|
const value = node.value || 0;
|
|
51127
49991
|
const max = node.max || 100;
|
|
51128
49992
|
const percent = Math.min(100, Math.max(0, value / max * 100));
|
|
51129
|
-
|
|
51130
|
-
|
|
51131
|
-
|
|
51132
|
-
|
|
49993
|
+
result += `
|
|
49994
|
+
<g transform="translate(${x}, ${y})">
|
|
49995
|
+
<rect width="${width}" height="${height}" rx="${height / 2}" fill="${this.theme.colors.muted}"/>
|
|
49996
|
+
<rect width="${width * percent / 100}" height="${height}" rx="${height / 2}" fill="${this.theme.colors.primary}"/>
|
|
49997
|
+
</g>`;
|
|
49998
|
+
this.currentY = y + height + 12;
|
|
49999
|
+
return result;
|
|
51133
50000
|
}
|
|
51134
|
-
|
|
51135
|
-
const
|
|
51136
|
-
const
|
|
51137
|
-
const
|
|
51138
|
-
|
|
51139
|
-
|
|
51140
|
-
|
|
50001
|
+
renderSpinner(node) {
|
|
50002
|
+
const sizes = { xs: 16, sm: 20, md: 24, lg: 32, xl: 40 };
|
|
50003
|
+
const size = sizes[node.size || "md"] || 24;
|
|
50004
|
+
const x = this.currentX + size / 2;
|
|
50005
|
+
const y = this.currentY + size / 2;
|
|
50006
|
+
const radius = size / 2 - 2;
|
|
50007
|
+
this.currentY += size + 12;
|
|
50008
|
+
return `
|
|
50009
|
+
<g transform="translate(${x}, ${y})">
|
|
50010
|
+
<circle r="${radius}" fill="none" stroke="${this.theme.colors.muted}" stroke-width="2"/>
|
|
50011
|
+
<path d="M0,-${radius} A${radius},${radius} 0 0,1 ${radius},0" fill="none" stroke="${this.theme.colors.primary}" stroke-width="2" stroke-linecap="round"/>
|
|
51141
50012
|
</g>`;
|
|
51142
50013
|
}
|
|
51143
|
-
|
|
51144
|
-
|
|
51145
|
-
|
|
51146
|
-
|
|
51147
|
-
if (node.children && node.children.length > 0) {
|
|
51148
|
-
let offsetY = 0;
|
|
51149
|
-
node.children.forEach((child) => {
|
|
51150
|
-
if (child.type === "divider") {
|
|
51151
|
-
offsetY += 16;
|
|
51152
|
-
svg += `<line x1="${box.x}" y1="${box.y + offsetY}" x2="${box.x + box.width - 32}" y2="${box.y + offsetY}" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51153
|
-
offsetY += 8;
|
|
51154
|
-
} else if (child.type === "group") {
|
|
51155
|
-
svg += `<text x="${box.x}" y="${box.y + offsetY + 16}" font-size="11" font-weight="500" fill="${this.theme.colors.muted}" text-transform="uppercase">${this.escapeXml(child.label)}</text>`;
|
|
51156
|
-
offsetY += 28;
|
|
51157
|
-
child.items.forEach((item) => {
|
|
51158
|
-
if (item.type === "divider") {
|
|
51159
|
-
offsetY += 8;
|
|
51160
|
-
svg += `<line x1="${box.x}" y1="${box.y + offsetY}" x2="${box.x + box.width - 32}" y2="${box.y + offsetY}" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51161
|
-
offsetY += 8;
|
|
51162
|
-
} else {
|
|
51163
|
-
const fill = item.active ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51164
|
-
const fontWeight = item.active ? 'font-weight="500"' : "";
|
|
51165
|
-
svg += `<text x="${box.x}" y="${box.y + offsetY + 16}" font-size="14" ${fontWeight} fill="${fill}">${this.escapeXml(item.label)}</text>`;
|
|
51166
|
-
offsetY += 32;
|
|
51167
|
-
}
|
|
51168
|
-
});
|
|
51169
|
-
} else if (child.type === "item") {
|
|
51170
|
-
const fill = child.active ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51171
|
-
const fontWeight = child.active ? 'font-weight="500"' : "";
|
|
51172
|
-
svg += `<text x="${box.x}" y="${box.y + offsetY + 16}" font-size="14" ${fontWeight} fill="${fill}">${this.escapeXml(child.label)}</text>`;
|
|
51173
|
-
offsetY += 32;
|
|
51174
|
-
}
|
|
51175
|
-
});
|
|
51176
|
-
svg += "</g>";
|
|
51177
|
-
return svg;
|
|
51178
|
-
}
|
|
50014
|
+
// ===========================================
|
|
50015
|
+
// Navigation Renderers
|
|
50016
|
+
// ===========================================
|
|
50017
|
+
renderNav(node) {
|
|
51179
50018
|
const items = node.items || [];
|
|
50019
|
+
const x = this.currentX;
|
|
50020
|
+
const y = this.currentY;
|
|
50021
|
+
const vertical = node.vertical || false;
|
|
50022
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51180
50023
|
if (vertical) {
|
|
51181
50024
|
items.forEach((item, idx) => {
|
|
51182
50025
|
const label = typeof item === "string" ? item : item.label;
|
|
51183
50026
|
const isActive = typeof item === "object" && item.active;
|
|
51184
50027
|
const fill = isActive ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51185
|
-
svg += `<text x="
|
|
50028
|
+
svg += `<text x="0" y="${idx * 32 + 16}" font-size="14" fill="${fill}">${this.escapeXml(label)}</text>`;
|
|
51186
50029
|
});
|
|
50030
|
+
this.currentY += items.length * 32 + 12;
|
|
51187
50031
|
} else {
|
|
51188
50032
|
let offsetX = 0;
|
|
51189
50033
|
items.forEach((item) => {
|
|
51190
50034
|
const label = typeof item === "string" ? item : item.label;
|
|
51191
50035
|
const isActive = typeof item === "object" && item.active;
|
|
51192
50036
|
const fill = isActive ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51193
|
-
svg += `<text x="${
|
|
51194
|
-
offsetX +=
|
|
50037
|
+
svg += `<text x="${offsetX}" y="16" font-size="14" fill="${fill}">${this.escapeXml(label)}</text>`;
|
|
50038
|
+
offsetX += label.length * 8 + 24;
|
|
51195
50039
|
});
|
|
50040
|
+
this.currentY += 32;
|
|
51196
50041
|
}
|
|
51197
50042
|
svg += "</g>";
|
|
51198
50043
|
return svg;
|
|
51199
50044
|
}
|
|
51200
|
-
|
|
51201
|
-
const node = box.node;
|
|
50045
|
+
renderTabs(node) {
|
|
51202
50046
|
const items = node.items || [];
|
|
50047
|
+
const x = this.currentX;
|
|
50048
|
+
const y = this.currentY;
|
|
51203
50049
|
const tabHeight = 40;
|
|
51204
|
-
let svg =
|
|
50050
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51205
50051
|
let offsetX = 0;
|
|
51206
|
-
items.forEach((item
|
|
50052
|
+
items.forEach((item) => {
|
|
51207
50053
|
const label = typeof item === "string" ? item : item;
|
|
51208
|
-
const tabWidth =
|
|
51209
|
-
|
|
51210
|
-
svg += `<
|
|
51211
|
-
svg += `<text x="${box.x + offsetX + tabWidth / 2}" y="${box.y + tabHeight / 2 + 5}" font-size="14" text-anchor="middle" fill="${this.theme.colors.foreground}">${this.escapeXml(label)}</text>`;
|
|
50054
|
+
const tabWidth = label.length * 10 + 24;
|
|
50055
|
+
svg += `<rect x="${offsetX}" width="${tabWidth}" height="${tabHeight}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50056
|
+
svg += `<text x="${offsetX + tabWidth / 2}" y="${tabHeight / 2 + 5}" font-size="14" text-anchor="middle">${this.escapeXml(label)}</text>`;
|
|
51212
50057
|
offsetX += tabWidth;
|
|
51213
50058
|
});
|
|
51214
50059
|
svg += "</g>";
|
|
50060
|
+
this.currentY += tabHeight + 12;
|
|
51215
50061
|
return svg;
|
|
51216
50062
|
}
|
|
51217
|
-
|
|
51218
|
-
const node = box.node;
|
|
50063
|
+
renderBreadcrumb(node) {
|
|
51219
50064
|
const items = node.items || [];
|
|
51220
50065
|
const separator = "/";
|
|
51221
|
-
|
|
50066
|
+
const x = this.currentX;
|
|
50067
|
+
const y = this.currentY;
|
|
50068
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51222
50069
|
let offsetX = 0;
|
|
51223
50070
|
items.forEach((item, idx) => {
|
|
51224
50071
|
const label = typeof item === "string" ? item : item.label;
|
|
51225
50072
|
const isLast = idx === items.length - 1;
|
|
51226
50073
|
const fill = isLast ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51227
|
-
svg += `<text x="${
|
|
51228
|
-
offsetX +=
|
|
50074
|
+
svg += `<text x="${offsetX}" y="16" font-size="14" fill="${fill}">${this.escapeXml(label)}</text>`;
|
|
50075
|
+
offsetX += label.length * 8 + 8;
|
|
51229
50076
|
if (!isLast) {
|
|
51230
|
-
svg += `<text x="${
|
|
50077
|
+
svg += `<text x="${offsetX}" y="16" font-size="14" fill="${this.theme.colors.muted}">${separator}</text>`;
|
|
51231
50078
|
offsetX += 16;
|
|
51232
50079
|
}
|
|
51233
50080
|
});
|
|
51234
50081
|
svg += "</g>";
|
|
50082
|
+
this.currentY += 28;
|
|
51235
50083
|
return svg;
|
|
51236
50084
|
}
|
|
51237
|
-
renderIconBox(box) {
|
|
51238
|
-
const node = box.node;
|
|
51239
|
-
const iconData = getIconData(node.name);
|
|
51240
|
-
if (!iconData) {
|
|
51241
|
-
return `<!-- Icon not found: ${node.name} -->`;
|
|
51242
|
-
}
|
|
51243
|
-
const color = this.theme.colors.foreground;
|
|
51244
|
-
return this.renderIconPaths(iconData, box.x, box.y, box.width, color);
|
|
51245
|
-
}
|
|
51246
|
-
renderDividerBox(box) {
|
|
51247
|
-
return `<line x1="${box.x}" y1="${box.y}" x2="${box.x + box.width}" y2="${box.y}" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51248
|
-
}
|
|
51249
50085
|
// ===========================================
|
|
51250
50086
|
// Utility Methods
|
|
51251
50087
|
// ===========================================
|
|
51252
|
-
|
|
51253
|
-
const
|
|
51254
|
-
|
|
51255
|
-
|
|
51256
|
-
|
|
51257
|
-
|
|
51258
|
-
|
|
51259
|
-
|
|
51260
|
-
|
|
51261
|
-
|
|
51262
|
-
|
|
51263
|
-
|
|
51264
|
-
return { top: 16, right: 16, bottom: 16, left: 16 };
|
|
51265
|
-
}
|
|
51266
|
-
return defaultPadding;
|
|
51267
|
-
}
|
|
51268
|
-
let p = 0;
|
|
51269
|
-
if ("p" in node && node.p !== void 0) {
|
|
51270
|
-
p = this.resolveSpacing(node.p);
|
|
51271
|
-
}
|
|
51272
|
-
let px = p;
|
|
51273
|
-
let py = p;
|
|
51274
|
-
if ("px" in node && node.px !== void 0) {
|
|
51275
|
-
px = this.resolveSpacing(node.px);
|
|
51276
|
-
}
|
|
51277
|
-
if ("py" in node && node.py !== void 0) {
|
|
51278
|
-
py = this.resolveSpacing(node.py);
|
|
51279
|
-
}
|
|
51280
|
-
if (node.type === "Header") {
|
|
51281
|
-
return { top: 0, right: px, bottom: 0, left: px };
|
|
51282
|
-
}
|
|
51283
|
-
return { top: py, right: px, bottom: py, left: px };
|
|
51284
|
-
}
|
|
51285
|
-
getGap(node) {
|
|
51286
|
-
if ("gap" in node && node.gap !== void 0) {
|
|
51287
|
-
return this.resolveSpacing(node.gap);
|
|
51288
|
-
}
|
|
51289
|
-
return void 0;
|
|
51290
|
-
}
|
|
51291
|
-
resolveSpacing(value) {
|
|
51292
|
-
if (typeof value === "number") {
|
|
51293
|
-
return value * 4;
|
|
51294
|
-
}
|
|
51295
|
-
if (typeof value === "object" && value && "value" in value) {
|
|
51296
|
-
return value.value;
|
|
51297
|
-
}
|
|
51298
|
-
return 0;
|
|
51299
|
-
}
|
|
51300
|
-
resolveSize(value) {
|
|
51301
|
-
if (value === void 0 || value === null) return void 0;
|
|
51302
|
-
if (typeof value === "number") return value;
|
|
51303
|
-
if (typeof value === "string") {
|
|
51304
|
-
if (value === "full") return void 0;
|
|
51305
|
-
const num = parseFloat(value);
|
|
51306
|
-
if (!isNaN(num)) return num;
|
|
51307
|
-
}
|
|
51308
|
-
if (typeof value === "object" && value && "value" in value) {
|
|
51309
|
-
return value.value;
|
|
51310
|
-
}
|
|
51311
|
-
return void 0;
|
|
51312
|
-
}
|
|
51313
|
-
isFullWidth(node) {
|
|
51314
|
-
if ("w" in node) {
|
|
51315
|
-
return node.w === "full";
|
|
51316
|
-
}
|
|
51317
|
-
return false;
|
|
51318
|
-
}
|
|
51319
|
-
estimateTextWidth(text, fontSize) {
|
|
51320
|
-
return text.length * fontSize * 0.6;
|
|
50088
|
+
getFontSize(size) {
|
|
50089
|
+
const sizes = {
|
|
50090
|
+
xs: 12,
|
|
50091
|
+
sm: 14,
|
|
50092
|
+
base: 16,
|
|
50093
|
+
md: 16,
|
|
50094
|
+
lg: 18,
|
|
50095
|
+
xl: 20,
|
|
50096
|
+
"2xl": 24,
|
|
50097
|
+
"3xl": 30
|
|
50098
|
+
};
|
|
50099
|
+
return sizes[size] || 16;
|
|
51321
50100
|
}
|
|
51322
50101
|
resolveFontSize(size) {
|
|
51323
50102
|
if (!size) return 16;
|
|
51324
50103
|
if (typeof size === "string") {
|
|
51325
|
-
|
|
51326
|
-
xs: 12,
|
|
51327
|
-
sm: 14,
|
|
51328
|
-
base: 16,
|
|
51329
|
-
md: 16,
|
|
51330
|
-
lg: 18,
|
|
51331
|
-
xl: 20,
|
|
51332
|
-
"2xl": 24,
|
|
51333
|
-
"3xl": 30
|
|
51334
|
-
};
|
|
51335
|
-
return sizes[size] || 16;
|
|
50104
|
+
return this.getFontSize(size);
|
|
51336
50105
|
}
|
|
51337
50106
|
if (typeof size === "object" && "value" in size) {
|
|
51338
50107
|
if (size.unit === "px") return size.value;
|
|
@@ -51343,8 +50112,15 @@ var SvgRenderer = class {
|
|
|
51343
50112
|
return 16;
|
|
51344
50113
|
}
|
|
51345
50114
|
getTitleFontSize(level) {
|
|
51346
|
-
const sizes = {
|
|
51347
|
-
|
|
50115
|
+
const sizes = {
|
|
50116
|
+
1: 32,
|
|
50117
|
+
2: 28,
|
|
50118
|
+
3: 24,
|
|
50119
|
+
4: 20,
|
|
50120
|
+
5: 18,
|
|
50121
|
+
6: 16
|
|
50122
|
+
};
|
|
50123
|
+
return sizes[level] || 24;
|
|
51348
50124
|
}
|
|
51349
50125
|
escapeXml(str) {
|
|
51350
50126
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -51405,22 +50181,15 @@ function renderToSvg2(document, options = {}) {
|
|
|
51405
50181
|
height = viewport.height;
|
|
51406
50182
|
}
|
|
51407
50183
|
}
|
|
50184
|
+
const padding = options.padding ?? 20;
|
|
51408
50185
|
const background = options.background ?? "#ffffff";
|
|
51409
50186
|
const { html, css } = render(document, { theme: "light" });
|
|
51410
50187
|
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
51411
50188
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
51412
50189
|
viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
51413
50190
|
<rect width="100%" height="100%" fill="${background}"/>
|
|
51414
|
-
<foreignObject x="
|
|
51415
|
-
<div xmlns="http://www.w3.org/1999/xhtml" style="
|
|
51416
|
-
width: ${width}px;
|
|
51417
|
-
height: ${height}px;
|
|
51418
|
-
overflow: hidden;
|
|
51419
|
-
display: flex;
|
|
51420
|
-
justify-content: center;
|
|
51421
|
-
align-items: center;
|
|
51422
|
-
box-sizing: border-box;
|
|
51423
|
-
">
|
|
50191
|
+
<foreignObject x="${padding}" y="${padding}" width="${width - padding * 2}" height="${height - padding * 2}">
|
|
50192
|
+
<div xmlns="http://www.w3.org/1999/xhtml" style="width: 100%; height: 100%; overflow: hidden;">
|
|
51424
50193
|
<style type="text/css">
|
|
51425
50194
|
${css}
|
|
51426
50195
|
</style>
|