@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.js
CHANGED
|
@@ -77,15 +77,10 @@ function generateContainerStyles(prefix) {
|
|
|
77
77
|
padding: 16px;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
/* Cards in flex rows
|
|
80
|
+
/* Cards in flex rows should expand equally */
|
|
81
81
|
.${prefix}-row > .${prefix}-card {
|
|
82
|
-
flex: 0 1 auto;
|
|
83
|
-
min-width: 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* Cards without explicit width should expand to fill space */
|
|
87
|
-
.${prefix}-row > .${prefix}-card-flex {
|
|
88
82
|
flex: 1 1 0%;
|
|
83
|
+
min-width: 0;
|
|
89
84
|
}
|
|
90
85
|
|
|
91
86
|
.${prefix}-card-title {
|
|
@@ -241,11 +236,6 @@ function generateTextStyles(prefix) {
|
|
|
241
236
|
line-height: 1.25;
|
|
242
237
|
}
|
|
243
238
|
|
|
244
|
-
/* Remove bottom margin when title is in a row (inline with other elements) */
|
|
245
|
-
.${prefix}-row .${prefix}-title {
|
|
246
|
-
margin-bottom: 0;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
239
|
h1.${prefix}-title { font-size: 36px; }
|
|
250
240
|
h2.${prefix}-title { font-size: 30px; }
|
|
251
241
|
h3.${prefix}-title { font-size: 24px; }
|
|
@@ -640,30 +630,6 @@ img.${prefix}-image {
|
|
|
640
630
|
font-size: 14px;
|
|
641
631
|
}
|
|
642
632
|
|
|
643
|
-
.${prefix}-placeholder-with-children {
|
|
644
|
-
position: relative;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
.${prefix}-placeholder-label {
|
|
648
|
-
position: absolute;
|
|
649
|
-
top: 50%;
|
|
650
|
-
left: 50%;
|
|
651
|
-
transform: translate(-50%, -50%);
|
|
652
|
-
z-index: 0;
|
|
653
|
-
pointer-events: none;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
.${prefix}-placeholder-overlay {
|
|
657
|
-
position: absolute;
|
|
658
|
-
top: 0;
|
|
659
|
-
left: 0;
|
|
660
|
-
right: 0;
|
|
661
|
-
bottom: 0;
|
|
662
|
-
z-index: 1;
|
|
663
|
-
display: flex;
|
|
664
|
-
flex-direction: column;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
633
|
.${prefix}-avatar {
|
|
668
634
|
display: inline-flex;
|
|
669
635
|
align-items: center;
|
|
@@ -779,12 +745,12 @@ svg.${prefix}-icon {
|
|
|
779
745
|
display: block;
|
|
780
746
|
}
|
|
781
747
|
|
|
782
|
-
/* Icon size tokens
|
|
748
|
+
/* Icon size tokens */
|
|
783
749
|
svg.${prefix}-icon-xs { width: 12px; height: 12px; }
|
|
784
|
-
svg.${prefix}-icon-sm { width:
|
|
785
|
-
svg.${prefix}-icon-md { width:
|
|
786
|
-
svg.${prefix}-icon-lg { width:
|
|
787
|
-
svg.${prefix}-icon-xl { width:
|
|
750
|
+
svg.${prefix}-icon-sm { width: 14px; height: 14px; }
|
|
751
|
+
svg.${prefix}-icon-md { width: 16px; height: 16px; }
|
|
752
|
+
svg.${prefix}-icon-lg { width: 20px; height: 20px; }
|
|
753
|
+
svg.${prefix}-icon-xl { width: 24px; height: 24px; }
|
|
788
754
|
|
|
789
755
|
.${prefix}-icon svg {
|
|
790
756
|
display: block;
|
|
@@ -1080,27 +1046,6 @@ function generateNavigationStyles(_theme, prefix) {
|
|
|
1080
1046
|
cursor: not-allowed;
|
|
1081
1047
|
}
|
|
1082
1048
|
|
|
1083
|
-
.${prefix}-nav-group {
|
|
1084
|
-
display: flex;
|
|
1085
|
-
flex-direction: column;
|
|
1086
|
-
gap: 4px;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
.${prefix}-nav-group-label {
|
|
1090
|
-
font-size: 11px;
|
|
1091
|
-
font-weight: 500;
|
|
1092
|
-
color: var(--${prefix}-muted);
|
|
1093
|
-
text-transform: uppercase;
|
|
1094
|
-
letter-spacing: 0.05em;
|
|
1095
|
-
padding: 8px 16px 4px;
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
.${prefix}-nav-divider {
|
|
1099
|
-
margin: 8px 0;
|
|
1100
|
-
border: none;
|
|
1101
|
-
border-top: 1px solid var(--${prefix}-border);
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
1049
|
.${prefix}-tabs {
|
|
1105
1050
|
border-bottom: 1px solid var(--${prefix}-border);
|
|
1106
1051
|
}
|
|
@@ -1318,6 +1263,7 @@ function generateBaseStyles(prefix) {
|
|
|
1318
1263
|
font-family: var(--${prefix}-font);
|
|
1319
1264
|
color: var(--${prefix}-fg);
|
|
1320
1265
|
background: var(--${prefix}-bg);
|
|
1266
|
+
min-height: 100vh;
|
|
1321
1267
|
box-sizing: border-box;
|
|
1322
1268
|
position: relative;
|
|
1323
1269
|
display: flex;
|
|
@@ -1328,19 +1274,10 @@ function generateBaseStyles(prefix) {
|
|
|
1328
1274
|
overflow: hidden;
|
|
1329
1275
|
}
|
|
1330
1276
|
|
|
1331
|
-
/* Col direct child of page should fill page height */
|
|
1332
|
-
.${prefix}-page > .${prefix}-col {
|
|
1333
|
-
flex: 1;
|
|
1334
|
-
min-height: 0;
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
1277
|
/* Row containing sidebar should fill remaining space */
|
|
1338
1278
|
.${prefix}-page > .${prefix}-row:has(.${prefix}-sidebar),
|
|
1339
|
-
.${prefix}-page > .${prefix}-row:has(.${prefix}-main)
|
|
1340
|
-
.${prefix}-page > .${prefix}-col > .${prefix}-row:has(.${prefix}-sidebar),
|
|
1341
|
-
.${prefix}-page > .${prefix}-col > .${prefix}-row:has(.${prefix}-main) {
|
|
1279
|
+
.${prefix}-page > .${prefix}-row:has(.${prefix}-main) {
|
|
1342
1280
|
flex: 1;
|
|
1343
|
-
min-height: 0;
|
|
1344
1281
|
align-items: stretch;
|
|
1345
1282
|
}
|
|
1346
1283
|
|
|
@@ -1383,15 +1320,10 @@ function generateGridClasses(_theme, prefix) {
|
|
|
1383
1320
|
box-sizing: border-box;
|
|
1384
1321
|
}
|
|
1385
1322
|
|
|
1386
|
-
/* When explicit width is set, don't flex-grow */
|
|
1387
|
-
.${prefix}-row[style*="width:"],
|
|
1388
|
-
.${prefix}-col[style*="width:"] {
|
|
1389
|
-
flex: 0 0 auto;
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
1323
|
`;
|
|
1393
1324
|
for (let i = 1; i <= 12; i++) {
|
|
1394
|
-
|
|
1325
|
+
const width = (i / 12 * 100).toFixed(4);
|
|
1326
|
+
css += `.${prefix}-col-${i} { flex: 0 0 auto; width: ${width}%; }
|
|
1395
1327
|
`;
|
|
1396
1328
|
}
|
|
1397
1329
|
return css;
|
|
@@ -1559,20 +1491,6 @@ function generateLayoutClasses(prefix) {
|
|
|
1559
1491
|
.${prefix}-main {
|
|
1560
1492
|
flex: 1;
|
|
1561
1493
|
padding: 16px;
|
|
1562
|
-
display: flex;
|
|
1563
|
-
flex-direction: column;
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
/* Scrollable main content */
|
|
1567
|
-
.${prefix}-main.${prefix}-scroll {
|
|
1568
|
-
overflow-y: auto;
|
|
1569
|
-
overflow-x: hidden;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
/* Main content should align to top, not stretch to fill */
|
|
1573
|
-
/* But allow explicit flex=1 to override */
|
|
1574
|
-
.${prefix}-main > .${prefix}-col:not(.${prefix}-flex-1) {
|
|
1575
|
-
flex: 0 0 auto;
|
|
1576
1494
|
}
|
|
1577
1495
|
|
|
1578
1496
|
.${prefix}-footer {
|
|
@@ -1589,7 +1507,6 @@ function generateLayoutClasses(prefix) {
|
|
|
1589
1507
|
border-right: 1px solid var(--${prefix}-border);
|
|
1590
1508
|
padding: 16px 16px 16px 20px;
|
|
1591
1509
|
flex-shrink: 0;
|
|
1592
|
-
align-self: stretch;
|
|
1593
1510
|
}
|
|
1594
1511
|
|
|
1595
1512
|
.${prefix}-sidebar-right {
|
|
@@ -48159,39 +48076,14 @@ var lucideIcons = {
|
|
|
48159
48076
|
]
|
|
48160
48077
|
]
|
|
48161
48078
|
};
|
|
48162
|
-
var iconAliases = {
|
|
48163
|
-
"home": "house",
|
|
48164
|
-
"plus-square": "square-plus",
|
|
48165
|
-
"minus-square": "square-minus",
|
|
48166
|
-
"x-square": "square-x",
|
|
48167
|
-
"check-square": "square-check",
|
|
48168
|
-
"edit": "pencil",
|
|
48169
|
-
"edit-2": "pencil",
|
|
48170
|
-
"edit-3": "pencil-line",
|
|
48171
|
-
"trash": "trash-2",
|
|
48172
|
-
"delete": "trash-2",
|
|
48173
|
-
"close": "x",
|
|
48174
|
-
"menu": "menu",
|
|
48175
|
-
"hamburger": "menu",
|
|
48176
|
-
"dots": "more-horizontal",
|
|
48177
|
-
"dots-vertical": "more-vertical",
|
|
48178
|
-
"cog": "settings",
|
|
48179
|
-
"gear": "settings"
|
|
48180
|
-
};
|
|
48181
48079
|
function getIconData(name) {
|
|
48182
48080
|
if (lucideIcons[name]) {
|
|
48183
48081
|
return lucideIcons[name];
|
|
48184
48082
|
}
|
|
48185
|
-
if (iconAliases[name] && lucideIcons[iconAliases[name]]) {
|
|
48186
|
-
return lucideIcons[iconAliases[name]];
|
|
48187
|
-
}
|
|
48188
48083
|
const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
48189
48084
|
if (lucideIcons[kebabName]) {
|
|
48190
48085
|
return lucideIcons[kebabName];
|
|
48191
48086
|
}
|
|
48192
|
-
if (iconAliases[kebabName] && lucideIcons[iconAliases[kebabName]]) {
|
|
48193
|
-
return lucideIcons[iconAliases[kebabName]];
|
|
48194
|
-
}
|
|
48195
48087
|
return void 0;
|
|
48196
48088
|
}
|
|
48197
48089
|
function renderIconSvg(data, _size = 24, strokeWidth = 2, className = "", styleAttr = "") {
|
|
@@ -48301,7 +48193,7 @@ var HtmlRenderer = class extends BaseRenderer {
|
|
|
48301
48193
|
const title = node.title ? `<title>${this.escapeHtml(node.title)}</title>
|
|
48302
48194
|
` : "";
|
|
48303
48195
|
const commonStyles = this.buildCommonStyles(node);
|
|
48304
|
-
const viewportStyle = `
|
|
48196
|
+
const viewportStyle = `width: ${viewport.width}px; height: ${viewport.height}px`;
|
|
48305
48197
|
const combinedStyle = commonStyles ? `${viewportStyle}; ${commonStyles}` : viewportStyle;
|
|
48306
48198
|
const dataAttrs = `data-viewport-width="${viewport.width}" data-viewport-height="${viewport.height}" data-viewport-label="${viewport.label}"`;
|
|
48307
48199
|
return `<div class="${classes}" style="${combinedStyle}" ${dataAttrs}>
|
|
@@ -48467,7 +48359,6 @@ ${children}
|
|
|
48467
48359
|
renderMain(node) {
|
|
48468
48360
|
const classes = this.buildClassString([
|
|
48469
48361
|
`${this.prefix}-main`,
|
|
48470
|
-
node.scroll ? `${this.prefix}-scroll` : void 0,
|
|
48471
48362
|
...this.getCommonClasses(node)
|
|
48472
48363
|
]);
|
|
48473
48364
|
const styles = this.buildCommonStyles(node);
|
|
@@ -48553,10 +48444,6 @@ ${children}
|
|
|
48553
48444
|
/**
|
|
48554
48445
|
* Build common inline styles for all values
|
|
48555
48446
|
*
|
|
48556
|
-
* Position values (x, y) for absolute positioning:
|
|
48557
|
-
* - When x or y is specified, element gets position: absolute
|
|
48558
|
-
* - x → left, y → top
|
|
48559
|
-
*
|
|
48560
48447
|
* Spacing values (p, m, gap) use token system:
|
|
48561
48448
|
* - number: spacing token (e.g., p=4 → padding: 16px from token table)
|
|
48562
48449
|
* - ValueWithUnit: direct CSS value (e.g., p=16px → padding: 16px)
|
|
@@ -48571,17 +48458,6 @@ ${children}
|
|
|
48571
48458
|
*/
|
|
48572
48459
|
buildCommonStyles(props) {
|
|
48573
48460
|
const styles = [];
|
|
48574
|
-
if (props.x !== void 0 || props.y !== void 0) {
|
|
48575
|
-
styles.push("position: absolute");
|
|
48576
|
-
if (props.x !== void 0) {
|
|
48577
|
-
const xValue = resolveSizeValueToCss(props.x);
|
|
48578
|
-
if (xValue) styles.push(`left: ${xValue}`);
|
|
48579
|
-
}
|
|
48580
|
-
if (props.y !== void 0) {
|
|
48581
|
-
const yValue = resolveSizeValueToCss(props.y);
|
|
48582
|
-
if (yValue) styles.push(`top: ${yValue}`);
|
|
48583
|
-
}
|
|
48584
|
-
}
|
|
48585
48461
|
const wValue = resolveSizeValueToCss(props.w);
|
|
48586
48462
|
if (wValue) {
|
|
48587
48463
|
styles.push(`width: ${wValue}`);
|
|
@@ -48691,10 +48567,8 @@ ${children}
|
|
|
48691
48567
|
// Container Node Renderers
|
|
48692
48568
|
// ===========================================
|
|
48693
48569
|
renderCard(node) {
|
|
48694
|
-
const hasExplicitWidth = node.w !== void 0;
|
|
48695
48570
|
const classes = this.buildClassString([
|
|
48696
48571
|
`${this.prefix}-card`,
|
|
48697
|
-
!hasExplicitWidth ? `${this.prefix}-card-flex` : void 0,
|
|
48698
48572
|
node.shadow ? `${this.prefix}-card-shadow-${node.shadow}` : void 0,
|
|
48699
48573
|
...this.getCommonClasses(node)
|
|
48700
48574
|
]);
|
|
@@ -49031,19 +48905,11 @@ ${slider}`;
|
|
|
49031
48905
|
renderPlaceholder(node) {
|
|
49032
48906
|
const classes = this.buildClassString([
|
|
49033
48907
|
`${this.prefix}-placeholder`,
|
|
49034
|
-
node.children && node.children.length > 0 ? `${this.prefix}-placeholder-with-children` : void 0,
|
|
49035
48908
|
...this.getCommonClasses(node)
|
|
49036
48909
|
]);
|
|
49037
48910
|
const styles = this.buildCommonStyles(node);
|
|
49038
48911
|
const styleAttr = styles ? ` style="${styles}"` : "";
|
|
49039
48912
|
const label = node.label ? this.escapeHtml(node.label) : "Placeholder";
|
|
49040
|
-
if (node.children && node.children.length > 0) {
|
|
49041
|
-
const childrenHtml = this.renderChildren(node.children);
|
|
49042
|
-
return `<div class="${classes}"${styleAttr}>
|
|
49043
|
-
<span class="${this.prefix}-placeholder-label">${label}</span>
|
|
49044
|
-
<div class="${this.prefix}-placeholder-overlay">${childrenHtml}</div>
|
|
49045
|
-
</div>`;
|
|
49046
|
-
}
|
|
49047
48913
|
return `<div class="${classes}"${styleAttr}>${label}</div>`;
|
|
49048
48914
|
}
|
|
49049
48915
|
renderAvatar(node) {
|
|
@@ -49289,12 +49155,6 @@ ${items}
|
|
|
49289
49155
|
]);
|
|
49290
49156
|
const styles = this.buildCommonStyles(node);
|
|
49291
49157
|
const styleAttr = styles ? ` style="${styles}"` : "";
|
|
49292
|
-
if (node.children && node.children.length > 0) {
|
|
49293
|
-
const content = this.renderNavChildren(node.children);
|
|
49294
|
-
return `<nav class="${classes}"${styleAttr}>
|
|
49295
|
-
${content}
|
|
49296
|
-
</nav>`;
|
|
49297
|
-
}
|
|
49298
49158
|
const items = node.items.map((item) => {
|
|
49299
49159
|
if (typeof item === "string") {
|
|
49300
49160
|
return `<a class="${this.prefix}-nav-link" href="#">${this.escapeHtml(item)}</a>`;
|
|
@@ -49304,48 +49164,12 @@ ${content}
|
|
|
49304
49164
|
item.active ? `${this.prefix}-nav-link-active` : void 0,
|
|
49305
49165
|
item.disabled ? `${this.prefix}-nav-link-disabled` : void 0
|
|
49306
49166
|
]);
|
|
49307
|
-
|
|
49308
|
-
return `<a class="${linkClasses}" href="${item.href || "#"}">${iconHtml}${this.escapeHtml(item.label)}</a>`;
|
|
49167
|
+
return `<a class="${linkClasses}" href="${item.href || "#"}">${this.escapeHtml(item.label)}</a>`;
|
|
49309
49168
|
}).join("\n");
|
|
49310
49169
|
return `<nav class="${classes}"${styleAttr}>
|
|
49311
49170
|
${items}
|
|
49312
49171
|
</nav>`;
|
|
49313
49172
|
}
|
|
49314
|
-
renderNavChildren(children) {
|
|
49315
|
-
return children.map((child) => {
|
|
49316
|
-
if (child.type === "divider") {
|
|
49317
|
-
return `<hr class="${this.prefix}-nav-divider" />`;
|
|
49318
|
-
}
|
|
49319
|
-
if (child.type === "group") {
|
|
49320
|
-
const groupItems = child.items.map((item) => {
|
|
49321
|
-
if (item.type === "divider") {
|
|
49322
|
-
return `<hr class="${this.prefix}-nav-divider" />`;
|
|
49323
|
-
}
|
|
49324
|
-
return this.renderNavItem(item);
|
|
49325
|
-
}).join("\n");
|
|
49326
|
-
return `<div class="${this.prefix}-nav-group">
|
|
49327
|
-
<div class="${this.prefix}-nav-group-label">${this.escapeHtml(child.label)}</div>
|
|
49328
|
-
${groupItems}
|
|
49329
|
-
</div>`;
|
|
49330
|
-
}
|
|
49331
|
-
if (child.type === "item") {
|
|
49332
|
-
return this.renderNavItem(child);
|
|
49333
|
-
}
|
|
49334
|
-
return "";
|
|
49335
|
-
}).join("\n");
|
|
49336
|
-
}
|
|
49337
|
-
renderNavItem(item) {
|
|
49338
|
-
const linkClasses = this.buildClassString([
|
|
49339
|
-
`${this.prefix}-nav-link`,
|
|
49340
|
-
item.active ? `${this.prefix}-nav-link-active` : void 0,
|
|
49341
|
-
item.disabled ? `${this.prefix}-nav-link-disabled` : void 0
|
|
49342
|
-
]);
|
|
49343
|
-
const iconHtml = item.icon ? this.renderIconHtml(item.icon) + " " : "";
|
|
49344
|
-
return `<a class="${linkClasses}" href="${item.href || "#"}">${iconHtml}${this.escapeHtml(item.label)}</a>`;
|
|
49345
|
-
}
|
|
49346
|
-
renderIconHtml(iconName) {
|
|
49347
|
-
return `<span class="${this.prefix}-icon" data-icon="${iconName}"></span>`;
|
|
49348
|
-
}
|
|
49349
49173
|
renderTabs(node) {
|
|
49350
49174
|
const classes = this.buildClassString([
|
|
49351
49175
|
`${this.prefix}-tabs`,
|
|
@@ -49500,239 +49324,13 @@ function createHtmlRenderer(options) {
|
|
|
49500
49324
|
return new HtmlRenderer(options);
|
|
49501
49325
|
}
|
|
49502
49326
|
|
|
49503
|
-
// src/renderer/svg/flex-layout.ts
|
|
49504
|
-
function computeFlexLayout(items, config) {
|
|
49505
|
-
const { mainSize, crossSize, justifyContent, alignItems, gap } = config;
|
|
49506
|
-
const computed = items.map((props, index) => {
|
|
49507
|
-
let flexBasis;
|
|
49508
|
-
if (props.basis === "auto" || props.basis === "content") {
|
|
49509
|
-
flexBasis = props.contentSize;
|
|
49510
|
-
} else {
|
|
49511
|
-
flexBasis = props.basis;
|
|
49512
|
-
}
|
|
49513
|
-
flexBasis = clamp(flexBasis, props.minSize, props.maxSize);
|
|
49514
|
-
return {
|
|
49515
|
-
index,
|
|
49516
|
-
props,
|
|
49517
|
-
flexBasis,
|
|
49518
|
-
mainSize: flexBasis,
|
|
49519
|
-
crossSize: 0,
|
|
49520
|
-
mainPosition: 0,
|
|
49521
|
-
crossPosition: 0,
|
|
49522
|
-
frozen: false,
|
|
49523
|
-
scaledShrinkFactor: props.shrink * flexBasis
|
|
49524
|
-
};
|
|
49525
|
-
});
|
|
49526
|
-
const totalGap = Math.max(0, (items.length - 1) * gap);
|
|
49527
|
-
const totalFlexBasis = computed.reduce((sum, item) => sum + item.flexBasis, 0);
|
|
49528
|
-
let freeSpace = mainSize - totalFlexBasis - totalGap;
|
|
49529
|
-
if (freeSpace !== 0) {
|
|
49530
|
-
resolveFlexibleLengths(computed, freeSpace);
|
|
49531
|
-
}
|
|
49532
|
-
distributeMainAxis(computed, mainSize, totalGap, gap, justifyContent);
|
|
49533
|
-
const crossSizeMax = crossSize ?? Math.max(...computed.map((item) => item.props.contentSize), 0);
|
|
49534
|
-
alignCrossAxis(computed, crossSizeMax, alignItems);
|
|
49535
|
-
const mainSizeUsed = computed.reduce((sum, item) => sum + item.mainSize, 0) + totalGap;
|
|
49536
|
-
return {
|
|
49537
|
-
items: computed,
|
|
49538
|
-
mainSizeUsed,
|
|
49539
|
-
crossSizeMax
|
|
49540
|
-
};
|
|
49541
|
-
}
|
|
49542
|
-
function resolveFlexibleLengths(items, initialFreeSpace) {
|
|
49543
|
-
items.forEach((item) => {
|
|
49544
|
-
item.frozen = false;
|
|
49545
|
-
item.mainSize = item.flexBasis;
|
|
49546
|
-
});
|
|
49547
|
-
let freeSpace = initialFreeSpace;
|
|
49548
|
-
const isGrowing = freeSpace > 0;
|
|
49549
|
-
let iteration = 0;
|
|
49550
|
-
const maxIterations = items.length + 1;
|
|
49551
|
-
while (iteration < maxIterations) {
|
|
49552
|
-
iteration++;
|
|
49553
|
-
const unfrozen = items.filter((item) => !item.frozen);
|
|
49554
|
-
if (unfrozen.length === 0) break;
|
|
49555
|
-
let flexFactorSum;
|
|
49556
|
-
if (isGrowing) {
|
|
49557
|
-
flexFactorSum = unfrozen.reduce((sum, item) => sum + item.props.grow, 0);
|
|
49558
|
-
} else {
|
|
49559
|
-
flexFactorSum = unfrozen.reduce((sum, item) => sum + item.scaledShrinkFactor, 0);
|
|
49560
|
-
}
|
|
49561
|
-
if (flexFactorSum === 0) {
|
|
49562
|
-
unfrozen.forEach((item) => item.frozen = true);
|
|
49563
|
-
break;
|
|
49564
|
-
}
|
|
49565
|
-
const usedSpace = items.reduce((sum, item) => sum + item.mainSize, 0);
|
|
49566
|
-
const containerMainSize = usedSpace + freeSpace;
|
|
49567
|
-
freeSpace = containerMainSize - usedSpace;
|
|
49568
|
-
let totalViolation = 0;
|
|
49569
|
-
for (const item of unfrozen) {
|
|
49570
|
-
let flexFraction;
|
|
49571
|
-
if (isGrowing) {
|
|
49572
|
-
flexFraction = item.props.grow / flexFactorSum;
|
|
49573
|
-
} else {
|
|
49574
|
-
flexFraction = item.scaledShrinkFactor / flexFactorSum;
|
|
49575
|
-
}
|
|
49576
|
-
const deltaSize = freeSpace * flexFraction;
|
|
49577
|
-
const targetSize = item.flexBasis + deltaSize;
|
|
49578
|
-
const clampedSize = clamp(targetSize, item.props.minSize, item.props.maxSize);
|
|
49579
|
-
const violation = clampedSize - targetSize;
|
|
49580
|
-
item.mainSize = clampedSize;
|
|
49581
|
-
totalViolation += violation;
|
|
49582
|
-
if (violation !== 0) {
|
|
49583
|
-
item.frozen = true;
|
|
49584
|
-
}
|
|
49585
|
-
}
|
|
49586
|
-
if (Math.abs(totalViolation) < 0.01) {
|
|
49587
|
-
unfrozen.forEach((item) => item.frozen = true);
|
|
49588
|
-
break;
|
|
49589
|
-
}
|
|
49590
|
-
freeSpace = containerMainSize - items.reduce((sum, item) => sum + item.mainSize, 0);
|
|
49591
|
-
}
|
|
49592
|
-
}
|
|
49593
|
-
function distributeMainAxis(items, containerSize, totalGap, gap, justifyContent) {
|
|
49594
|
-
if (items.length === 0) return;
|
|
49595
|
-
const totalItemSize = items.reduce((sum, item) => sum + item.mainSize, 0);
|
|
49596
|
-
const freeSpace = containerSize - totalItemSize - totalGap;
|
|
49597
|
-
let position = 0;
|
|
49598
|
-
let itemGap = gap;
|
|
49599
|
-
let leadingSpace = 0;
|
|
49600
|
-
switch (justifyContent) {
|
|
49601
|
-
case "flex-start":
|
|
49602
|
-
leadingSpace = 0;
|
|
49603
|
-
break;
|
|
49604
|
-
case "flex-end":
|
|
49605
|
-
leadingSpace = freeSpace;
|
|
49606
|
-
break;
|
|
49607
|
-
case "center":
|
|
49608
|
-
leadingSpace = freeSpace / 2;
|
|
49609
|
-
break;
|
|
49610
|
-
case "space-between":
|
|
49611
|
-
leadingSpace = 0;
|
|
49612
|
-
if (items.length > 1) {
|
|
49613
|
-
itemGap = gap + freeSpace / (items.length - 1);
|
|
49614
|
-
}
|
|
49615
|
-
break;
|
|
49616
|
-
case "space-around":
|
|
49617
|
-
if (items.length > 0) {
|
|
49618
|
-
const spacePerItem = freeSpace / items.length;
|
|
49619
|
-
leadingSpace = spacePerItem / 2;
|
|
49620
|
-
itemGap = gap + spacePerItem;
|
|
49621
|
-
}
|
|
49622
|
-
break;
|
|
49623
|
-
case "space-evenly":
|
|
49624
|
-
if (items.length > 0) {
|
|
49625
|
-
const totalSpaces = items.length + 1;
|
|
49626
|
-
const spaceSize = freeSpace / totalSpaces;
|
|
49627
|
-
leadingSpace = spaceSize;
|
|
49628
|
-
itemGap = gap + spaceSize;
|
|
49629
|
-
}
|
|
49630
|
-
break;
|
|
49631
|
-
}
|
|
49632
|
-
position = leadingSpace;
|
|
49633
|
-
for (let i = 0; i < items.length; i++) {
|
|
49634
|
-
items[i].mainPosition = position;
|
|
49635
|
-
position += items[i].mainSize;
|
|
49636
|
-
if (i < items.length - 1) {
|
|
49637
|
-
position += itemGap;
|
|
49638
|
-
}
|
|
49639
|
-
}
|
|
49640
|
-
}
|
|
49641
|
-
function alignCrossAxis(items, containerCrossSize, alignItems) {
|
|
49642
|
-
for (const item of items) {
|
|
49643
|
-
const align = item.props.alignSelf ?? alignItems;
|
|
49644
|
-
const itemCrossSize = item.props.contentSize;
|
|
49645
|
-
item.crossSize = align === "stretch" ? containerCrossSize : itemCrossSize;
|
|
49646
|
-
switch (align) {
|
|
49647
|
-
case "flex-start":
|
|
49648
|
-
item.crossPosition = 0;
|
|
49649
|
-
break;
|
|
49650
|
-
case "flex-end":
|
|
49651
|
-
item.crossPosition = containerCrossSize - item.crossSize;
|
|
49652
|
-
break;
|
|
49653
|
-
case "center":
|
|
49654
|
-
item.crossPosition = (containerCrossSize - item.crossSize) / 2;
|
|
49655
|
-
break;
|
|
49656
|
-
case "stretch":
|
|
49657
|
-
item.crossPosition = 0;
|
|
49658
|
-
item.crossSize = containerCrossSize;
|
|
49659
|
-
break;
|
|
49660
|
-
case "baseline":
|
|
49661
|
-
item.crossPosition = 0;
|
|
49662
|
-
break;
|
|
49663
|
-
}
|
|
49664
|
-
}
|
|
49665
|
-
}
|
|
49666
|
-
function clamp(value, min, max) {
|
|
49667
|
-
return Math.max(min, Math.min(max, value));
|
|
49668
|
-
}
|
|
49669
|
-
function toJustifyContent(justify) {
|
|
49670
|
-
switch (justify) {
|
|
49671
|
-
case "start":
|
|
49672
|
-
return "flex-start";
|
|
49673
|
-
case "end":
|
|
49674
|
-
return "flex-end";
|
|
49675
|
-
case "center":
|
|
49676
|
-
return "center";
|
|
49677
|
-
case "between":
|
|
49678
|
-
return "space-between";
|
|
49679
|
-
case "around":
|
|
49680
|
-
return "space-around";
|
|
49681
|
-
case "evenly":
|
|
49682
|
-
return "space-evenly";
|
|
49683
|
-
default:
|
|
49684
|
-
return "flex-start";
|
|
49685
|
-
}
|
|
49686
|
-
}
|
|
49687
|
-
function toAlignItems(align) {
|
|
49688
|
-
switch (align) {
|
|
49689
|
-
case "start":
|
|
49690
|
-
return "flex-start";
|
|
49691
|
-
case "end":
|
|
49692
|
-
return "flex-end";
|
|
49693
|
-
case "center":
|
|
49694
|
-
return "center";
|
|
49695
|
-
case "stretch":
|
|
49696
|
-
return "stretch";
|
|
49697
|
-
case "baseline":
|
|
49698
|
-
return "baseline";
|
|
49699
|
-
default:
|
|
49700
|
-
return "stretch";
|
|
49701
|
-
}
|
|
49702
|
-
}
|
|
49703
|
-
function createFlexItemProps(contentSize, options = {}) {
|
|
49704
|
-
return {
|
|
49705
|
-
basis: options.basis ?? "auto",
|
|
49706
|
-
grow: options.grow ?? 0,
|
|
49707
|
-
shrink: options.shrink ?? 1,
|
|
49708
|
-
minSize: options.minSize ?? 0,
|
|
49709
|
-
maxSize: options.maxSize ?? Infinity,
|
|
49710
|
-
contentSize,
|
|
49711
|
-
alignSelf: options.alignSelf
|
|
49712
|
-
};
|
|
49713
|
-
}
|
|
49714
|
-
function createFlexGrowItemProps(contentSize, options = {}) {
|
|
49715
|
-
return {
|
|
49716
|
-
basis: options.basis ?? 0,
|
|
49717
|
-
grow: options.grow ?? 1,
|
|
49718
|
-
shrink: options.shrink ?? 1,
|
|
49719
|
-
minSize: options.minSize ?? 0,
|
|
49720
|
-
maxSize: options.maxSize ?? Infinity,
|
|
49721
|
-
contentSize,
|
|
49722
|
-
alignSelf: options.alignSelf
|
|
49723
|
-
};
|
|
49724
|
-
}
|
|
49725
|
-
|
|
49726
49327
|
// src/renderer/svg/index.ts
|
|
49727
49328
|
var SvgRenderer = class {
|
|
49728
49329
|
options;
|
|
49729
49330
|
theme;
|
|
49730
|
-
|
|
49731
|
-
|
|
49732
|
-
|
|
49733
|
-
clipPathCounter = 0;
|
|
49734
|
-
// Default spacing values
|
|
49735
|
-
DEFAULT_GAP = 16;
|
|
49331
|
+
currentX = 0;
|
|
49332
|
+
currentY = 0;
|
|
49333
|
+
contentWidth = 0;
|
|
49736
49334
|
constructor(options = {}) {
|
|
49737
49335
|
this.options = {
|
|
49738
49336
|
width: options.width ?? 800,
|
|
@@ -49743,41 +49341,28 @@ var SvgRenderer = class {
|
|
|
49743
49341
|
fontFamily: options.fontFamily ?? "system-ui, -apple-system, sans-serif"
|
|
49744
49342
|
};
|
|
49745
49343
|
this.theme = defaultTheme;
|
|
49344
|
+
this.contentWidth = this.options.width - this.options.padding * 2;
|
|
49746
49345
|
}
|
|
49747
49346
|
/**
|
|
49748
49347
|
* Render a wireframe document to SVG
|
|
49749
49348
|
*/
|
|
49750
49349
|
render(doc) {
|
|
49751
|
-
this.
|
|
49752
|
-
this.
|
|
49350
|
+
this.currentX = this.options.padding;
|
|
49351
|
+
this.currentY = this.options.padding;
|
|
49753
49352
|
const firstPage = doc.children[0];
|
|
49754
49353
|
let width = this.options.width;
|
|
49755
49354
|
let height = this.options.height;
|
|
49756
|
-
if (firstPage) {
|
|
49757
|
-
const
|
|
49758
|
-
|
|
49759
|
-
|
|
49760
|
-
|
|
49761
|
-
if (hasExplicitWidth) {
|
|
49762
|
-
width = pageAny.width;
|
|
49763
|
-
}
|
|
49764
|
-
if (hasExplicitHeight) {
|
|
49765
|
-
height = pageAny.height;
|
|
49766
|
-
}
|
|
49767
|
-
} else if (firstPage.viewport !== void 0 || firstPage.device !== void 0) {
|
|
49768
|
-
const viewport = resolveViewport(firstPage.viewport, firstPage.device);
|
|
49769
|
-
width = viewport.width;
|
|
49770
|
-
height = viewport.height;
|
|
49771
|
-
}
|
|
49355
|
+
if (firstPage && (firstPage.viewport !== void 0 || firstPage.device !== void 0)) {
|
|
49356
|
+
const viewport = resolveViewport(firstPage.viewport, firstPage.device);
|
|
49357
|
+
width = viewport.width;
|
|
49358
|
+
height = viewport.height;
|
|
49359
|
+
this.contentWidth = width - this.options.padding * 2;
|
|
49772
49360
|
}
|
|
49773
|
-
this.pageWidth = width;
|
|
49774
|
-
this.pageHeight = height;
|
|
49775
49361
|
const content = doc.children.map((page) => this.renderPage(page)).join("\n");
|
|
49776
|
-
const allDefs = this.generateDefs() + "\n" + this.clipPathDefs.join("\n");
|
|
49777
49362
|
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
49778
49363
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
49779
49364
|
<defs>
|
|
49780
|
-
${
|
|
49365
|
+
${this.generateDefs()}
|
|
49781
49366
|
</defs>
|
|
49782
49367
|
<rect width="100%" height="100%" fill="${this.options.background}"/>
|
|
49783
49368
|
<g transform="scale(${this.options.scale})">
|
|
@@ -49787,7 +49372,7 @@ var SvgRenderer = class {
|
|
|
49787
49372
|
return { svg, width, height };
|
|
49788
49373
|
}
|
|
49789
49374
|
/**
|
|
49790
|
-
* Generate SVG defs (styles)
|
|
49375
|
+
* Generate SVG defs (styles, patterns, etc.)
|
|
49791
49376
|
*/
|
|
49792
49377
|
generateDefs() {
|
|
49793
49378
|
return `
|
|
@@ -49798,1500 +49383,684 @@ var SvgRenderer = class {
|
|
|
49798
49383
|
</style>
|
|
49799
49384
|
`;
|
|
49800
49385
|
}
|
|
49801
|
-
// ===========================================
|
|
49802
|
-
// Page Layout
|
|
49803
|
-
// ===========================================
|
|
49804
|
-
renderPage(page) {
|
|
49805
|
-
const padding = this.options.padding;
|
|
49806
|
-
const contentWidth = this.pageWidth - padding * 2;
|
|
49807
|
-
const contentHeight = this.pageHeight - padding * 2;
|
|
49808
|
-
const constraints = {
|
|
49809
|
-
maxWidth: contentWidth,
|
|
49810
|
-
maxHeight: contentHeight
|
|
49811
|
-
};
|
|
49812
|
-
const childBoxes = [];
|
|
49813
|
-
let currentY = padding;
|
|
49814
|
-
const isCentered = page.centered === true;
|
|
49815
|
-
const hasHeader = page.children.some((c) => c.type === "Header");
|
|
49816
|
-
const hasFooter = page.children.some((c) => c.type === "Footer");
|
|
49817
|
-
const hasMain = page.children.some((c) => c.type === "Main");
|
|
49818
|
-
if (hasHeader || hasFooter || hasMain) {
|
|
49819
|
-
return this.renderPageWithFixedLayout(page, padding, contentWidth, contentHeight);
|
|
49820
|
-
}
|
|
49821
|
-
const measurements = page.children.map((child) => this.measureNode(child, constraints));
|
|
49822
|
-
const gap = this.getGap(page) || this.DEFAULT_GAP;
|
|
49823
|
-
const totalChildrenHeight = measurements.reduce((sum, m, i) => {
|
|
49824
|
-
return sum + m.height + (i > 0 ? gap : 0);
|
|
49825
|
-
}, 0);
|
|
49826
|
-
if (isCentered) {
|
|
49827
|
-
const availableHeight = contentHeight;
|
|
49828
|
-
currentY = padding + Math.max(0, (availableHeight - totalChildrenHeight) / 2);
|
|
49829
|
-
}
|
|
49830
|
-
for (let i = 0; i < page.children.length; i++) {
|
|
49831
|
-
const child = page.children[i];
|
|
49832
|
-
const measurement = measurements[i];
|
|
49833
|
-
let childX = padding;
|
|
49834
|
-
if (isCentered || this.shouldCenterHorizontally(child)) {
|
|
49835
|
-
childX = padding + (contentWidth - measurement.width) / 2;
|
|
49836
|
-
}
|
|
49837
|
-
const box = this.layoutNode(child, childX, currentY, constraints);
|
|
49838
|
-
childBoxes.push(box);
|
|
49839
|
-
currentY += box.height + gap;
|
|
49840
|
-
}
|
|
49841
|
-
const elements = [];
|
|
49842
|
-
for (const box of childBoxes) {
|
|
49843
|
-
elements.push(this.renderBox(box));
|
|
49844
|
-
}
|
|
49845
|
-
return elements.join("\n");
|
|
49846
|
-
}
|
|
49847
49386
|
/**
|
|
49848
|
-
* Render page
|
|
49849
|
-
* Header at top, Footer at bottom, Main fills remaining space
|
|
49387
|
+
* Render a page node
|
|
49850
49388
|
*/
|
|
49851
|
-
|
|
49852
|
-
const constraints = {
|
|
49853
|
-
maxWidth: contentWidth,
|
|
49854
|
-
maxHeight: contentHeight
|
|
49855
|
-
};
|
|
49856
|
-
const header = page.children.find((c) => c.type === "Header");
|
|
49857
|
-
const footer = page.children.find((c) => c.type === "Footer");
|
|
49858
|
-
const otherChildren = page.children.filter((c) => c.type !== "Header" && c.type !== "Footer");
|
|
49389
|
+
renderPage(node) {
|
|
49859
49390
|
const elements = [];
|
|
49860
|
-
|
|
49861
|
-
|
|
49862
|
-
let currentY = padding;
|
|
49863
|
-
if (header) {
|
|
49864
|
-
const headerMeasure = this.measureNode(header, constraints);
|
|
49865
|
-
headerHeight = headerMeasure.height;
|
|
49866
|
-
const headerBox = this.layoutNode(header, padding, currentY, constraints);
|
|
49867
|
-
elements.push(this.renderBox(headerBox));
|
|
49868
|
-
}
|
|
49869
|
-
if (footer) {
|
|
49870
|
-
const footerMeasure = this.measureNode(footer, constraints);
|
|
49871
|
-
footerHeight = footerMeasure.height;
|
|
49872
|
-
const footerY = this.pageHeight - padding - footerHeight;
|
|
49873
|
-
const footerBox = this.layoutNode(footer, padding, footerY, constraints);
|
|
49874
|
-
elements.push(this.renderBox(footerBox));
|
|
49391
|
+
if (node.title) {
|
|
49392
|
+
elements.push(this.renderPageTitle(node.title));
|
|
49875
49393
|
}
|
|
49876
|
-
const
|
|
49877
|
-
|
|
49878
|
-
const mainHeight = mainEndY - mainStartY;
|
|
49879
|
-
if (otherChildren.length > 0) {
|
|
49880
|
-
const mainConstraints = {
|
|
49881
|
-
maxWidth: contentWidth,
|
|
49882
|
-
maxHeight: mainHeight
|
|
49883
|
-
};
|
|
49884
|
-
const clipId = `main-clip-${this.clipPathCounter++}`;
|
|
49885
|
-
this.clipPathDefs.push(`<clipPath id="${clipId}"><rect x="${padding}" y="${mainStartY}" width="${contentWidth}" height="${mainHeight}"/></clipPath>`);
|
|
49886
|
-
const mainContent = [];
|
|
49887
|
-
mainContent.push(`<g clip-path="url(#${clipId})">`);
|
|
49888
|
-
let childY = mainStartY;
|
|
49889
|
-
const gap = this.getGap(page) || 0;
|
|
49890
|
-
for (const child of otherChildren) {
|
|
49891
|
-
const childBox = this.layoutNode(child, padding, childY, mainConstraints);
|
|
49892
|
-
mainContent.push(this.renderBox(childBox));
|
|
49893
|
-
childY += childBox.height + gap;
|
|
49894
|
-
}
|
|
49895
|
-
mainContent.push(`</g>`);
|
|
49896
|
-
elements.push(mainContent.join("\n"));
|
|
49394
|
+
for (const child of node.children) {
|
|
49395
|
+
elements.push(this.renderNode(child));
|
|
49897
49396
|
}
|
|
49898
49397
|
return elements.join("\n");
|
|
49899
49398
|
}
|
|
49900
|
-
|
|
49901
|
-
|
|
49399
|
+
/**
|
|
49400
|
+
* Render page title
|
|
49401
|
+
*/
|
|
49402
|
+
renderPageTitle(title) {
|
|
49403
|
+
const fontSize = 24;
|
|
49404
|
+
const y = this.currentY + fontSize;
|
|
49405
|
+
this.currentY += fontSize + 16;
|
|
49406
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(title)}</text>`;
|
|
49902
49407
|
}
|
|
49903
|
-
|
|
49904
|
-
|
|
49905
|
-
|
|
49906
|
-
|
|
49408
|
+
/**
|
|
49409
|
+
* Render any AST node
|
|
49410
|
+
*/
|
|
49411
|
+
renderNode(node) {
|
|
49907
49412
|
switch (node.type) {
|
|
49413
|
+
// Layout nodes
|
|
49908
49414
|
case "Row":
|
|
49909
|
-
return this.
|
|
49415
|
+
return this.renderRow(node);
|
|
49910
49416
|
case "Col":
|
|
49911
|
-
return this.
|
|
49417
|
+
return this.renderCol(node);
|
|
49912
49418
|
case "Header":
|
|
49913
|
-
return this.
|
|
49914
|
-
case "Footer":
|
|
49915
|
-
return this.measureFooter(node, constraints);
|
|
49419
|
+
return this.renderHeader(node);
|
|
49916
49420
|
case "Main":
|
|
49917
|
-
return this.
|
|
49421
|
+
return this.renderMain(node);
|
|
49422
|
+
case "Footer":
|
|
49423
|
+
return this.renderFooter(node);
|
|
49918
49424
|
case "Sidebar":
|
|
49919
|
-
return this.
|
|
49425
|
+
return this.renderSidebar(node);
|
|
49426
|
+
// Container nodes
|
|
49920
49427
|
case "Card":
|
|
49921
|
-
return this.
|
|
49428
|
+
return this.renderCard(node);
|
|
49922
49429
|
case "Modal":
|
|
49923
|
-
return this.
|
|
49924
|
-
|
|
49925
|
-
return this.measureTitle(node);
|
|
49430
|
+
return this.renderModal(node);
|
|
49431
|
+
// Text nodes
|
|
49926
49432
|
case "Text":
|
|
49927
|
-
return this.
|
|
49928
|
-
case "
|
|
49929
|
-
return this.
|
|
49433
|
+
return this.renderText(node);
|
|
49434
|
+
case "Title":
|
|
49435
|
+
return this.renderTitle(node);
|
|
49436
|
+
case "Link":
|
|
49437
|
+
return this.renderLink(node);
|
|
49438
|
+
// Input nodes
|
|
49930
49439
|
case "Input":
|
|
49931
|
-
return this.
|
|
49440
|
+
return this.renderInput(node);
|
|
49932
49441
|
case "Textarea":
|
|
49933
|
-
return this.
|
|
49442
|
+
return this.renderTextarea(node);
|
|
49934
49443
|
case "Select":
|
|
49935
|
-
return this.
|
|
49444
|
+
return this.renderSelect(node);
|
|
49936
49445
|
case "Checkbox":
|
|
49937
|
-
return this.
|
|
49446
|
+
return this.renderCheckbox(node);
|
|
49938
49447
|
case "Radio":
|
|
49939
|
-
return this.
|
|
49448
|
+
return this.renderRadio(node);
|
|
49940
49449
|
case "Switch":
|
|
49941
|
-
return this.
|
|
49942
|
-
|
|
49943
|
-
|
|
49450
|
+
return this.renderSwitch(node);
|
|
49451
|
+
// Button
|
|
49452
|
+
case "Button":
|
|
49453
|
+
return this.renderButton(node);
|
|
49454
|
+
// Display nodes
|
|
49944
49455
|
case "Image":
|
|
49945
|
-
return this.
|
|
49456
|
+
return this.renderImage(node);
|
|
49946
49457
|
case "Placeholder":
|
|
49947
|
-
return this.
|
|
49458
|
+
return this.renderPlaceholder(node);
|
|
49948
49459
|
case "Avatar":
|
|
49949
|
-
return this.
|
|
49460
|
+
return this.renderAvatar(node);
|
|
49950
49461
|
case "Badge":
|
|
49951
|
-
return this.
|
|
49462
|
+
return this.renderBadge(node);
|
|
49463
|
+
// Data nodes
|
|
49952
49464
|
case "Table":
|
|
49953
|
-
return this.
|
|
49465
|
+
return this.renderTable(node);
|
|
49954
49466
|
case "List":
|
|
49955
|
-
return this.
|
|
49467
|
+
return this.renderList(node);
|
|
49468
|
+
// Feedback nodes
|
|
49956
49469
|
case "Alert":
|
|
49957
|
-
return this.
|
|
49470
|
+
return this.renderAlert(node);
|
|
49958
49471
|
case "Progress":
|
|
49959
|
-
return this.
|
|
49472
|
+
return this.renderProgress(node);
|
|
49960
49473
|
case "Spinner":
|
|
49961
|
-
return this.
|
|
49474
|
+
return this.renderSpinner(node);
|
|
49475
|
+
// Navigation nodes
|
|
49962
49476
|
case "Nav":
|
|
49963
|
-
return this.
|
|
49477
|
+
return this.renderNav(node);
|
|
49964
49478
|
case "Tabs":
|
|
49965
|
-
return this.
|
|
49479
|
+
return this.renderTabs(node);
|
|
49966
49480
|
case "Breadcrumb":
|
|
49967
|
-
return this.
|
|
49968
|
-
case "Icon":
|
|
49969
|
-
return this.measureIcon(node);
|
|
49970
|
-
case "Divider":
|
|
49971
|
-
return this.measureDivider(node, constraints);
|
|
49481
|
+
return this.renderBreadcrumb(node);
|
|
49972
49482
|
default:
|
|
49973
|
-
return
|
|
49974
|
-
}
|
|
49975
|
-
}
|
|
49976
|
-
measureRow(node, constraints) {
|
|
49977
|
-
const padding = this.getPadding(node);
|
|
49978
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
49979
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
49980
|
-
const childMeasurements = node.children.map(
|
|
49981
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
49982
|
-
);
|
|
49983
|
-
const maxChildHeight = Math.max(...childMeasurements.map((m) => m.height), 0);
|
|
49984
|
-
const totalChildWidth = childMeasurements.reduce((sum, m) => sum + m.width, 0);
|
|
49985
|
-
const totalGapWidth = Math.max(0, (node.children.length - 1) * gap);
|
|
49986
|
-
const contentWidth = totalChildWidth + totalGapWidth + padding.left + padding.right;
|
|
49987
|
-
const hasExplicitWidth = "w" in node && node.w !== void 0;
|
|
49988
|
-
const width = hasExplicitWidth ? constraints.maxWidth : Math.min(contentWidth, constraints.maxWidth);
|
|
49989
|
-
return {
|
|
49990
|
-
width,
|
|
49991
|
-
height: maxChildHeight + padding.top + padding.bottom
|
|
49992
|
-
};
|
|
49993
|
-
}
|
|
49994
|
-
measureCol(node, constraints) {
|
|
49995
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
49996
|
-
const padding = this.getPadding(node);
|
|
49997
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
49998
|
-
const childMeasurements = node.children.map(
|
|
49999
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50000
|
-
);
|
|
50001
|
-
const totalHeight = childMeasurements.reduce(
|
|
50002
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50003
|
-
0
|
|
50004
|
-
);
|
|
50005
|
-
const maxChildWidth = Math.max(...childMeasurements.map((m) => m.width), 0);
|
|
50006
|
-
return {
|
|
50007
|
-
width: Math.max(maxChildWidth + padding.left + padding.right, constraints.maxWidth),
|
|
50008
|
-
height: totalHeight + padding.top + padding.bottom
|
|
50009
|
-
};
|
|
50010
|
-
}
|
|
50011
|
-
measureHeader(node, constraints) {
|
|
50012
|
-
const padding = this.getPadding(node);
|
|
50013
|
-
const height = this.resolveSize(node.h) || 56;
|
|
50014
|
-
return {
|
|
50015
|
-
width: constraints.maxWidth,
|
|
50016
|
-
height: height + padding.top + padding.bottom
|
|
50017
|
-
};
|
|
50018
|
-
}
|
|
50019
|
-
measureFooter(node, constraints) {
|
|
50020
|
-
const padding = this.getPadding(node);
|
|
50021
|
-
const height = this.resolveSize(node.h) || 60;
|
|
50022
|
-
return {
|
|
50023
|
-
width: constraints.maxWidth,
|
|
50024
|
-
height: height + padding.top + padding.bottom
|
|
50025
|
-
};
|
|
50026
|
-
}
|
|
50027
|
-
measureMain(node, constraints) {
|
|
50028
|
-
const padding = this.getPadding(node);
|
|
50029
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50030
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50031
|
-
const childMeasurements = node.children.map(
|
|
50032
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50033
|
-
);
|
|
50034
|
-
const totalHeight = childMeasurements.reduce(
|
|
50035
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50036
|
-
0
|
|
50037
|
-
);
|
|
50038
|
-
return {
|
|
50039
|
-
width: constraints.maxWidth,
|
|
50040
|
-
height: totalHeight + padding.top + padding.bottom
|
|
50041
|
-
};
|
|
50042
|
-
}
|
|
50043
|
-
measureSidebar(node, constraints) {
|
|
50044
|
-
const width = this.resolveSize(node.w) || 200;
|
|
50045
|
-
const padding = this.getPadding(node);
|
|
50046
|
-
const gap = this.getGap(node) ?? 8;
|
|
50047
|
-
const innerWidth = width - padding.left - padding.right;
|
|
50048
|
-
const childMeasurements = node.children.map(
|
|
50049
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50050
|
-
);
|
|
50051
|
-
const contentHeight = childMeasurements.reduce(
|
|
50052
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50053
|
-
0
|
|
50054
|
-
) + padding.top + padding.bottom;
|
|
50055
|
-
const explicitHeight = this.resolveSize(node.h);
|
|
50056
|
-
const height = explicitHeight || constraints.maxHeight || contentHeight;
|
|
50057
|
-
return { width, height };
|
|
50058
|
-
}
|
|
50059
|
-
measureCard(node, constraints) {
|
|
50060
|
-
let cardWidth = this.resolveSize(node.w);
|
|
50061
|
-
if (!cardWidth) {
|
|
50062
|
-
cardWidth = Math.min(360, constraints.maxWidth);
|
|
50063
|
-
} else {
|
|
50064
|
-
cardWidth = Math.min(cardWidth, constraints.maxWidth);
|
|
50065
|
-
}
|
|
50066
|
-
const explicitHeight = this.resolveSize(node.h);
|
|
50067
|
-
if (explicitHeight) {
|
|
50068
|
-
return { width: cardWidth, height: explicitHeight };
|
|
50069
|
-
}
|
|
50070
|
-
const padding = this.getPadding(node);
|
|
50071
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50072
|
-
const innerWidth = cardWidth - padding.left - padding.right;
|
|
50073
|
-
const childMeasurements = node.children.map(
|
|
50074
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50075
|
-
);
|
|
50076
|
-
let contentHeight = 0;
|
|
50077
|
-
if (node.title) {
|
|
50078
|
-
contentHeight += 28;
|
|
50079
|
-
}
|
|
50080
|
-
contentHeight += childMeasurements.reduce(
|
|
50081
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50082
|
-
0
|
|
50083
|
-
);
|
|
50084
|
-
return {
|
|
50085
|
-
width: cardWidth,
|
|
50086
|
-
height: contentHeight + padding.top + padding.bottom
|
|
50087
|
-
};
|
|
50088
|
-
}
|
|
50089
|
-
measureModal(node, constraints) {
|
|
50090
|
-
const width = this.resolveSize(node.w) || 400;
|
|
50091
|
-
const padding = this.getPadding(node);
|
|
50092
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50093
|
-
const innerWidth = width - padding.left - padding.right;
|
|
50094
|
-
const childMeasurements = node.children.map(
|
|
50095
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50096
|
-
);
|
|
50097
|
-
let contentHeight = node.title ? 40 : 0;
|
|
50098
|
-
contentHeight += childMeasurements.reduce(
|
|
50099
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50100
|
-
0
|
|
50101
|
-
);
|
|
50102
|
-
return {
|
|
50103
|
-
width,
|
|
50104
|
-
height: contentHeight + padding.top + padding.bottom
|
|
50105
|
-
};
|
|
50106
|
-
}
|
|
50107
|
-
measureTitle(node) {
|
|
50108
|
-
const level = node.level || 1;
|
|
50109
|
-
const fontSize = this.getTitleFontSize(level);
|
|
50110
|
-
const textWidth = this.estimateTextWidth(node.content, fontSize);
|
|
50111
|
-
return { width: textWidth, height: fontSize + 8 };
|
|
50112
|
-
}
|
|
50113
|
-
measureText(node) {
|
|
50114
|
-
const fontSize = this.resolveFontSize(node.size);
|
|
50115
|
-
const textWidth = this.estimateTextWidth(node.content, fontSize);
|
|
50116
|
-
return { width: textWidth, height: fontSize + 8 };
|
|
50117
|
-
}
|
|
50118
|
-
measureButton(node, constraints) {
|
|
50119
|
-
const hasIcon = !!node.icon;
|
|
50120
|
-
const isIconOnly = hasIcon && !node.content.trim();
|
|
50121
|
-
const iconSize = 16;
|
|
50122
|
-
const padding = 16;
|
|
50123
|
-
let width;
|
|
50124
|
-
if (this.isFullWidth(node)) {
|
|
50125
|
-
width = constraints.maxWidth;
|
|
50126
|
-
} else if (isIconOnly) {
|
|
50127
|
-
width = iconSize + padding * 2;
|
|
50128
|
-
} else if (hasIcon) {
|
|
50129
|
-
width = Math.max(80, this.estimateTextWidth(node.content, 14) + iconSize + 48);
|
|
50130
|
-
} else {
|
|
50131
|
-
width = Math.max(80, this.estimateTextWidth(node.content, 14) + 32);
|
|
50132
|
-
}
|
|
50133
|
-
return { width, height: 40 };
|
|
50134
|
-
}
|
|
50135
|
-
measureInput(node, constraints) {
|
|
50136
|
-
let width;
|
|
50137
|
-
if (this.resolveSize(node.w)) {
|
|
50138
|
-
width = this.resolveSize(node.w);
|
|
50139
|
-
} else if (constraints.inHeader) {
|
|
50140
|
-
const placeholderWidth = node.placeholder ? this.estimateTextWidth(node.placeholder, 14) : 60;
|
|
50141
|
-
width = Math.max(120, placeholderWidth + 24 + 100);
|
|
50142
|
-
} else {
|
|
50143
|
-
width = constraints.maxWidth;
|
|
50144
|
-
}
|
|
50145
|
-
let height = 36;
|
|
50146
|
-
if (node.label) height += 24;
|
|
50147
|
-
return { width, height };
|
|
50148
|
-
}
|
|
50149
|
-
measureTextarea(node, constraints) {
|
|
50150
|
-
const width = this.resolveSize(node.w) || constraints.maxWidth;
|
|
50151
|
-
let height = node.rows ? node.rows * 24 : 100;
|
|
50152
|
-
if (node.label) height += 24;
|
|
50153
|
-
return { width, height };
|
|
50154
|
-
}
|
|
50155
|
-
measureSelect(node, constraints) {
|
|
50156
|
-
const width = this.resolveSize(node.w) || constraints.maxWidth;
|
|
50157
|
-
let height = 40;
|
|
50158
|
-
if (node.label) height += 24;
|
|
50159
|
-
return { width, height };
|
|
50160
|
-
}
|
|
50161
|
-
measureCheckbox(node) {
|
|
50162
|
-
const labelWidth = node.label ? this.estimateTextWidth(node.label, 14) + 8 : 0;
|
|
50163
|
-
return { width: 18 + labelWidth, height: 24 };
|
|
50164
|
-
}
|
|
50165
|
-
measureRadio(node) {
|
|
50166
|
-
const labelWidth = node.label ? this.estimateTextWidth(node.label, 14) + 8 : 0;
|
|
50167
|
-
return { width: 18 + labelWidth, height: 24 };
|
|
50168
|
-
}
|
|
50169
|
-
measureSwitch(node) {
|
|
50170
|
-
const labelWidth = node.label ? this.estimateTextWidth(node.label, 14) + 8 : 0;
|
|
50171
|
-
return { width: 44 + labelWidth, height: 28 };
|
|
50172
|
-
}
|
|
50173
|
-
measureLink(node) {
|
|
50174
|
-
const fontSize = 14;
|
|
50175
|
-
const textWidth = this.estimateTextWidth(node.content, fontSize);
|
|
50176
|
-
return { width: textWidth, height: fontSize + 8 };
|
|
50177
|
-
}
|
|
50178
|
-
measureImage(node, constraints) {
|
|
50179
|
-
let width;
|
|
50180
|
-
if (this.isFullWidth(node)) {
|
|
50181
|
-
width = constraints.maxWidth;
|
|
50182
|
-
} else {
|
|
50183
|
-
width = this.resolveSize(node.w) || 200;
|
|
50184
|
-
}
|
|
50185
|
-
const height = this.resolveSize(node.h) || 150;
|
|
50186
|
-
return { width, height };
|
|
50187
|
-
}
|
|
50188
|
-
measurePlaceholder(node, constraints) {
|
|
50189
|
-
let width;
|
|
50190
|
-
if (node.w !== void 0) {
|
|
50191
|
-
width = this.isFullWidth(node) ? constraints.maxWidth : this.resolveSize(node.w) || 200;
|
|
50192
|
-
} else {
|
|
50193
|
-
width = constraints.maxWidth || 200;
|
|
50194
|
-
}
|
|
50195
|
-
const height = this.resolveSize(node.h) || 100;
|
|
50196
|
-
return { width, height };
|
|
50197
|
-
}
|
|
50198
|
-
measureAvatar(node, constraints) {
|
|
50199
|
-
const sizes = { xs: 24, sm: 32, md: 40, lg: 48, xl: 64 };
|
|
50200
|
-
const defaultSize = constraints?.inHeader ? "sm" : "md";
|
|
50201
|
-
const size = sizes[node.size || defaultSize] || 40;
|
|
50202
|
-
return { width: size, height: size };
|
|
50203
|
-
}
|
|
50204
|
-
measureBadge(node) {
|
|
50205
|
-
const width = Math.max(24, this.estimateTextWidth(node.content, 12) + 16);
|
|
50206
|
-
return { width, height: 22 };
|
|
50207
|
-
}
|
|
50208
|
-
measureTable(node) {
|
|
50209
|
-
const columns = node.columns || [];
|
|
50210
|
-
const rows = node.rows || [];
|
|
50211
|
-
const rowCount = rows.length || 3;
|
|
50212
|
-
const colWidth = 120;
|
|
50213
|
-
const rowHeight = 40;
|
|
50214
|
-
return {
|
|
50215
|
-
width: columns.length * colWidth,
|
|
50216
|
-
height: (rowCount + 1) * rowHeight
|
|
50217
|
-
};
|
|
50218
|
-
}
|
|
50219
|
-
measureList(node) {
|
|
50220
|
-
const items = node.items || [];
|
|
50221
|
-
const maxItemWidth = Math.max(...items.map((item) => {
|
|
50222
|
-
const content = typeof item === "string" ? item : item.content;
|
|
50223
|
-
return this.estimateTextWidth(content, 14);
|
|
50224
|
-
}), 100);
|
|
50225
|
-
return { width: maxItemWidth + 24, height: items.length * 28 };
|
|
50226
|
-
}
|
|
50227
|
-
measureAlert(_node, constraints) {
|
|
50228
|
-
const width = Math.min(400, constraints.maxWidth);
|
|
50229
|
-
return { width, height: 48 };
|
|
50230
|
-
}
|
|
50231
|
-
measureProgress(node, constraints) {
|
|
50232
|
-
const width = Math.min(200, constraints.maxWidth);
|
|
50233
|
-
let height = 8;
|
|
50234
|
-
if (node.label) height += 24;
|
|
50235
|
-
return { width, height };
|
|
50236
|
-
}
|
|
50237
|
-
measureSpinner(node) {
|
|
50238
|
-
const sizes = { xs: 16, sm: 20, md: 24, lg: 32, xl: 40 };
|
|
50239
|
-
const size = sizes[node.size || "md"] || 24;
|
|
50240
|
-
return { width: size, height: size };
|
|
50241
|
-
}
|
|
50242
|
-
measureNav(node) {
|
|
50243
|
-
const items = node.items || [];
|
|
50244
|
-
if (node.vertical) {
|
|
50245
|
-
const maxWidth = Math.max(...items.map((item) => {
|
|
50246
|
-
const label = typeof item === "string" ? item : item.label;
|
|
50247
|
-
return this.estimateTextWidth(label, 14);
|
|
50248
|
-
}), 100);
|
|
50249
|
-
return { width: maxWidth, height: items.length * 32 };
|
|
50250
|
-
} else {
|
|
50251
|
-
const totalWidth = items.reduce((sum, item) => {
|
|
50252
|
-
const label = typeof item === "string" ? item : item.label;
|
|
50253
|
-
return sum + this.estimateTextWidth(label, 14) + 24;
|
|
50254
|
-
}, 0);
|
|
50255
|
-
return { width: totalWidth, height: 32 };
|
|
49483
|
+
return `<!-- Unsupported: ${node.type} -->`;
|
|
50256
49484
|
}
|
|
50257
49485
|
}
|
|
50258
|
-
measureTabs(node) {
|
|
50259
|
-
const items = node.items || [];
|
|
50260
|
-
const totalWidth = items.reduce((sum, item) => {
|
|
50261
|
-
const label = typeof item === "string" ? item : item;
|
|
50262
|
-
return sum + this.estimateTextWidth(label, 14) + 32;
|
|
50263
|
-
}, 0);
|
|
50264
|
-
return { width: totalWidth, height: 44 };
|
|
50265
|
-
}
|
|
50266
|
-
measureBreadcrumb(node) {
|
|
50267
|
-
const items = node.items || [];
|
|
50268
|
-
const totalWidth = items.reduce((sum, item, idx) => {
|
|
50269
|
-
const label = typeof item === "string" ? item : item.label;
|
|
50270
|
-
return sum + this.estimateTextWidth(label, 14) + (idx < items.length - 1 ? 24 : 0);
|
|
50271
|
-
}, 0);
|
|
50272
|
-
return { width: totalWidth, height: 28 };
|
|
50273
|
-
}
|
|
50274
|
-
measureIcon(node) {
|
|
50275
|
-
const sizes = { xs: 12, sm: 16, md: 20, lg: 24, xl: 32 };
|
|
50276
|
-
const size = sizes[node.size || "md"] || 20;
|
|
50277
|
-
return { width: size, height: size };
|
|
50278
|
-
}
|
|
50279
|
-
measureDivider(_node, constraints) {
|
|
50280
|
-
return { width: constraints.maxWidth, height: 1 };
|
|
50281
|
-
}
|
|
50282
49486
|
// ===========================================
|
|
50283
|
-
// Layout
|
|
49487
|
+
// Layout Renderers
|
|
50284
49488
|
// ===========================================
|
|
50285
|
-
|
|
50286
|
-
|
|
50287
|
-
|
|
50288
|
-
|
|
50289
|
-
|
|
50290
|
-
|
|
50291
|
-
|
|
50292
|
-
return this.layoutHeader(node, x, y, constraints);
|
|
50293
|
-
case "Footer":
|
|
50294
|
-
return this.layoutFooter(node, x, y, constraints);
|
|
50295
|
-
case "Main":
|
|
50296
|
-
return this.layoutMain(node, x, y, constraints);
|
|
50297
|
-
case "Sidebar":
|
|
50298
|
-
return this.layoutSidebar(node, x, y, constraints);
|
|
50299
|
-
case "Card":
|
|
50300
|
-
return this.layoutCard(node, x, y, constraints);
|
|
50301
|
-
default:
|
|
50302
|
-
const size = this.measureNode(node, constraints);
|
|
50303
|
-
return {
|
|
50304
|
-
x,
|
|
50305
|
-
y,
|
|
50306
|
-
width: size.width,
|
|
50307
|
-
height: size.height,
|
|
50308
|
-
node,
|
|
50309
|
-
children: []
|
|
50310
|
-
};
|
|
50311
|
-
}
|
|
50312
|
-
}
|
|
50313
|
-
layoutRow(node, x, y, constraints) {
|
|
50314
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50315
|
-
const padding = this.getPadding(node);
|
|
50316
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50317
|
-
const justify = node.justify || "start";
|
|
50318
|
-
const align = node.align || (constraints.inHeader ? "center" : "start");
|
|
50319
|
-
const childMeasurements = node.children.map(
|
|
50320
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50321
|
-
);
|
|
50322
|
-
const flexItems = node.children.map((child, i) => {
|
|
50323
|
-
const measurement = childMeasurements[i];
|
|
50324
|
-
if ("w" in child && child.w !== void 0 && child.w !== "full") {
|
|
50325
|
-
const resolved = this.resolveSize(child.w);
|
|
50326
|
-
if (resolved !== void 0) {
|
|
50327
|
-
return createFlexItemProps(measurement.height, {
|
|
50328
|
-
basis: resolved,
|
|
50329
|
-
grow: 0,
|
|
50330
|
-
shrink: 0,
|
|
50331
|
-
minSize: resolved,
|
|
50332
|
-
maxSize: resolved,
|
|
50333
|
-
contentSize: measurement.width
|
|
50334
|
-
});
|
|
50335
|
-
}
|
|
50336
|
-
}
|
|
50337
|
-
if (this.isFlexContainer(child)) {
|
|
50338
|
-
return createFlexGrowItemProps(measurement.height, {
|
|
50339
|
-
basis: 0,
|
|
50340
|
-
grow: 1,
|
|
50341
|
-
shrink: 1,
|
|
50342
|
-
minSize: 0,
|
|
50343
|
-
maxSize: Infinity,
|
|
50344
|
-
contentSize: measurement.width
|
|
50345
|
-
});
|
|
50346
|
-
}
|
|
50347
|
-
if (constraints.inHeader && child.type === "Input") {
|
|
50348
|
-
return createFlexGrowItemProps(measurement.height, {
|
|
50349
|
-
basis: measurement.width,
|
|
50350
|
-
// auto = content size
|
|
50351
|
-
grow: 1,
|
|
50352
|
-
shrink: 1,
|
|
50353
|
-
minSize: 120,
|
|
50354
|
-
// min-width: 120px
|
|
50355
|
-
maxSize: Infinity,
|
|
50356
|
-
contentSize: measurement.width
|
|
50357
|
-
});
|
|
50358
|
-
}
|
|
50359
|
-
return createFlexItemProps(measurement.height, {
|
|
50360
|
-
basis: measurement.width,
|
|
50361
|
-
// auto = content size
|
|
50362
|
-
grow: 0,
|
|
50363
|
-
shrink: 1,
|
|
50364
|
-
minSize: 0,
|
|
50365
|
-
maxSize: Infinity,
|
|
50366
|
-
contentSize: measurement.width
|
|
50367
|
-
});
|
|
50368
|
-
});
|
|
50369
|
-
const flexConfig = {
|
|
50370
|
-
mainSize: innerWidth,
|
|
50371
|
-
crossSize: void 0,
|
|
50372
|
-
// Will use max child height
|
|
50373
|
-
direction: "row",
|
|
50374
|
-
justifyContent: toJustifyContent(justify),
|
|
50375
|
-
alignItems: toAlignItems(align),
|
|
50376
|
-
gap
|
|
50377
|
-
};
|
|
50378
|
-
const flexResult = computeFlexLayout(flexItems, flexConfig);
|
|
50379
|
-
const maxChildHeight = Math.max(...childMeasurements.map((m) => m.height), 0);
|
|
50380
|
-
const innerMaxHeight = constraints.maxHeight ? constraints.maxHeight - padding.top - padding.bottom : void 0;
|
|
50381
|
-
const effectiveHeight = innerMaxHeight || maxChildHeight;
|
|
50382
|
-
const rowHeight = effectiveHeight + padding.top + padding.bottom;
|
|
50383
|
-
const children = [];
|
|
50384
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
50385
|
-
const child = node.children[i];
|
|
50386
|
-
const flexItem = flexResult.items[i];
|
|
50387
|
-
const measurement = childMeasurements[i];
|
|
50388
|
-
const childX = x + padding.left + flexItem.mainPosition;
|
|
50389
|
-
let childY = y + padding.top;
|
|
50390
|
-
switch (align) {
|
|
50391
|
-
case "center":
|
|
50392
|
-
childY = y + padding.top + (maxChildHeight - measurement.height) / 2;
|
|
50393
|
-
break;
|
|
50394
|
-
case "end":
|
|
50395
|
-
childY = y + padding.top + (maxChildHeight - measurement.height);
|
|
50396
|
-
break;
|
|
50397
|
-
}
|
|
50398
|
-
const childBox = this.layoutNode(child, childX, childY, {
|
|
50399
|
-
...constraints,
|
|
50400
|
-
maxWidth: flexItem.mainSize,
|
|
50401
|
-
maxHeight: effectiveHeight
|
|
50402
|
-
});
|
|
50403
|
-
children.push(childBox);
|
|
50404
|
-
}
|
|
50405
|
-
return {
|
|
50406
|
-
x,
|
|
50407
|
-
y,
|
|
50408
|
-
width: constraints.maxWidth,
|
|
50409
|
-
height: rowHeight,
|
|
50410
|
-
node,
|
|
50411
|
-
children,
|
|
50412
|
-
padding
|
|
50413
|
-
};
|
|
50414
|
-
}
|
|
50415
|
-
layoutCol(node, x, y, constraints) {
|
|
50416
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50417
|
-
const padding = this.getPadding(node);
|
|
50418
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50419
|
-
const innerHeight = constraints.maxHeight ? constraints.maxHeight - padding.top - padding.bottom : void 0;
|
|
50420
|
-
const align = node.align || "stretch";
|
|
50421
|
-
const childMeasurements = node.children.map(
|
|
50422
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50423
|
-
);
|
|
50424
|
-
const flexItems = node.children.map((child, i) => {
|
|
50425
|
-
const measurement = childMeasurements[i];
|
|
50426
|
-
if ("h" in child && child.h !== void 0) {
|
|
50427
|
-
const resolved = this.resolveSize(child.h);
|
|
50428
|
-
if (resolved !== void 0) {
|
|
50429
|
-
return createFlexItemProps(measurement.width, {
|
|
50430
|
-
basis: resolved,
|
|
50431
|
-
grow: 0,
|
|
50432
|
-
shrink: 0,
|
|
50433
|
-
minSize: resolved,
|
|
50434
|
-
maxSize: resolved,
|
|
50435
|
-
contentSize: measurement.height
|
|
50436
|
-
});
|
|
50437
|
-
}
|
|
49489
|
+
renderRow(node) {
|
|
49490
|
+
const savedX = this.currentX;
|
|
49491
|
+
const savedY = this.currentY;
|
|
49492
|
+
const elements = [];
|
|
49493
|
+
const totalSpan = node.children.reduce((sum, child) => {
|
|
49494
|
+
if ("span" in child && typeof child.span === "number") {
|
|
49495
|
+
return sum + child.span;
|
|
50438
49496
|
}
|
|
50439
|
-
|
|
50440
|
-
|
|
50441
|
-
|
|
50442
|
-
|
|
50443
|
-
shrink: 1,
|
|
50444
|
-
minSize: 0,
|
|
50445
|
-
maxSize: Infinity,
|
|
50446
|
-
contentSize: measurement.height
|
|
50447
|
-
});
|
|
50448
|
-
}
|
|
50449
|
-
return createFlexItemProps(measurement.width, {
|
|
50450
|
-
basis: measurement.height,
|
|
50451
|
-
// auto = content size
|
|
50452
|
-
grow: 0,
|
|
50453
|
-
shrink: 1,
|
|
50454
|
-
minSize: 0,
|
|
50455
|
-
maxSize: Infinity,
|
|
50456
|
-
contentSize: measurement.height
|
|
50457
|
-
});
|
|
50458
|
-
});
|
|
50459
|
-
const flexConfig = {
|
|
50460
|
-
mainSize: innerHeight ?? childMeasurements.reduce(
|
|
50461
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50462
|
-
0
|
|
50463
|
-
),
|
|
50464
|
-
crossSize: innerWidth,
|
|
50465
|
-
direction: "column",
|
|
50466
|
-
justifyContent: "flex-start",
|
|
50467
|
-
alignItems: toAlignItems(align),
|
|
50468
|
-
gap
|
|
50469
|
-
};
|
|
50470
|
-
const flexResult = computeFlexLayout(flexItems, flexConfig);
|
|
50471
|
-
const children = [];
|
|
50472
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
50473
|
-
const child = node.children[i];
|
|
50474
|
-
const flexItem = flexResult.items[i];
|
|
50475
|
-
const measurement = childMeasurements[i];
|
|
50476
|
-
let childX = x + padding.left;
|
|
50477
|
-
let childWidth = align === "stretch" ? innerWidth : measurement.width;
|
|
50478
|
-
switch (align) {
|
|
50479
|
-
case "center":
|
|
50480
|
-
childX = x + padding.left + (innerWidth - measurement.width) / 2;
|
|
50481
|
-
break;
|
|
50482
|
-
case "end":
|
|
50483
|
-
childX = x + padding.left + (innerWidth - measurement.width);
|
|
50484
|
-
break;
|
|
50485
|
-
}
|
|
50486
|
-
const childY = y + padding.top + flexItem.mainPosition;
|
|
50487
|
-
const childBox = this.layoutNode(child, childX, childY, {
|
|
50488
|
-
...constraints,
|
|
50489
|
-
maxWidth: childWidth,
|
|
50490
|
-
maxHeight: flexItem.mainSize
|
|
50491
|
-
});
|
|
50492
|
-
children.push(childBox);
|
|
50493
|
-
}
|
|
50494
|
-
const totalHeight = flexResult.mainSizeUsed;
|
|
50495
|
-
return {
|
|
50496
|
-
x,
|
|
50497
|
-
y,
|
|
50498
|
-
width: constraints.maxWidth,
|
|
50499
|
-
height: totalHeight + padding.top + padding.bottom,
|
|
50500
|
-
node,
|
|
50501
|
-
children,
|
|
50502
|
-
padding
|
|
50503
|
-
};
|
|
50504
|
-
}
|
|
50505
|
-
rowContainsSidebarOrMain(row) {
|
|
50506
|
-
return row.children.some(
|
|
50507
|
-
(child) => child.type === "Sidebar" || child.type === "Main"
|
|
50508
|
-
);
|
|
50509
|
-
}
|
|
50510
|
-
layoutHeader(node, x, y, constraints) {
|
|
50511
|
-
const padding = this.getPadding(node);
|
|
50512
|
-
const height = this.resolveSize(node.h) || 56;
|
|
50513
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50514
|
-
const children = [];
|
|
50515
|
-
let currentY = y + padding.top;
|
|
49497
|
+
return sum + 1;
|
|
49498
|
+
}, 0);
|
|
49499
|
+
const colWidth = this.contentWidth / Math.max(totalSpan, 1);
|
|
49500
|
+
let maxHeight = 0;
|
|
50516
49501
|
for (const child of node.children) {
|
|
50517
|
-
const
|
|
50518
|
-
|
|
50519
|
-
|
|
50520
|
-
|
|
50521
|
-
|
|
50522
|
-
|
|
50523
|
-
|
|
50524
|
-
|
|
50525
|
-
const verticalOffset = (height - childBox.height) / 2;
|
|
50526
|
-
childBox.y = y + padding.top + verticalOffset;
|
|
50527
|
-
this.adjustChildrenY(childBox, verticalOffset);
|
|
50528
|
-
children.push(childBox);
|
|
50529
|
-
currentY += childBox.height;
|
|
50530
|
-
}
|
|
50531
|
-
return {
|
|
50532
|
-
x,
|
|
50533
|
-
y,
|
|
50534
|
-
width: constraints.maxWidth,
|
|
50535
|
-
height: height + padding.top + padding.bottom,
|
|
50536
|
-
node,
|
|
50537
|
-
children,
|
|
50538
|
-
padding
|
|
50539
|
-
};
|
|
50540
|
-
}
|
|
50541
|
-
adjustChildrenY(box, offset) {
|
|
50542
|
-
for (const child of box.children) {
|
|
50543
|
-
child.y += offset;
|
|
50544
|
-
this.adjustChildrenY(child, offset);
|
|
49502
|
+
const span = "span" in child && typeof child.span === "number" ? child.span : 1;
|
|
49503
|
+
const childWidth = colWidth * span;
|
|
49504
|
+
const startY = this.currentY;
|
|
49505
|
+
elements.push(this.renderNode(child));
|
|
49506
|
+
const childHeight = this.currentY - startY;
|
|
49507
|
+
maxHeight = Math.max(maxHeight, childHeight);
|
|
49508
|
+
this.currentX += childWidth;
|
|
49509
|
+
this.currentY = savedY;
|
|
50545
49510
|
}
|
|
49511
|
+
this.currentX = savedX;
|
|
49512
|
+
this.currentY = savedY + maxHeight;
|
|
49513
|
+
return elements.join("\n");
|
|
50546
49514
|
}
|
|
50547
|
-
|
|
50548
|
-
|
|
50549
|
-
* Only layout containers without explicit width should flex
|
|
50550
|
-
*/
|
|
50551
|
-
isFlexContainer(node) {
|
|
50552
|
-
if (node.type === "Main") return true;
|
|
50553
|
-
if (node.type === "Col" && !("w" in node && node.w !== void 0)) return true;
|
|
50554
|
-
return false;
|
|
49515
|
+
renderCol(node) {
|
|
49516
|
+
return node.children.map((child) => this.renderNode(child)).join("\n");
|
|
50555
49517
|
}
|
|
50556
|
-
|
|
50557
|
-
const
|
|
50558
|
-
const
|
|
50559
|
-
const
|
|
50560
|
-
const
|
|
50561
|
-
|
|
50562
|
-
|
|
50563
|
-
|
|
50564
|
-
|
|
50565
|
-
|
|
50566
|
-
|
|
50567
|
-
|
|
50568
|
-
|
|
50569
|
-
const verticalOffset = (height - childBox.height) / 2;
|
|
50570
|
-
childBox.y = y + padding.top + verticalOffset;
|
|
50571
|
-
this.adjustChildrenY(childBox, verticalOffset);
|
|
50572
|
-
children.push(childBox);
|
|
50573
|
-
currentY += childBox.height;
|
|
50574
|
-
}
|
|
50575
|
-
return {
|
|
50576
|
-
x,
|
|
50577
|
-
y,
|
|
50578
|
-
width: constraints.maxWidth,
|
|
50579
|
-
height: height + padding.top + padding.bottom,
|
|
50580
|
-
node,
|
|
50581
|
-
children,
|
|
50582
|
-
padding
|
|
50583
|
-
};
|
|
49518
|
+
renderHeader(node) {
|
|
49519
|
+
const height = 60;
|
|
49520
|
+
const x = this.currentX;
|
|
49521
|
+
const y = this.currentY;
|
|
49522
|
+
const savedY = this.currentY;
|
|
49523
|
+
this.currentY += 16;
|
|
49524
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49525
|
+
this.currentY = savedY + height + 8;
|
|
49526
|
+
return `
|
|
49527
|
+
<g transform="translate(${x}, ${y})">
|
|
49528
|
+
<rect width="${this.contentWidth}" height="${height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49529
|
+
${children}
|
|
49530
|
+
</g>`;
|
|
50584
49531
|
}
|
|
50585
|
-
|
|
50586
|
-
|
|
50587
|
-
const gap = this.getGap(node) ?? this.DEFAULT_GAP;
|
|
50588
|
-
const innerWidth = constraints.maxWidth - padding.left - padding.right;
|
|
50589
|
-
const childMeasurements = node.children.map(
|
|
50590
|
-
(child) => this.measureNode(child, { ...constraints, maxWidth: innerWidth })
|
|
50591
|
-
);
|
|
50592
|
-
const children = [];
|
|
50593
|
-
let currentY = y + padding.top;
|
|
50594
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
50595
|
-
const child = node.children[i];
|
|
50596
|
-
const childBox = this.layoutNode(child, x + padding.left, currentY, {
|
|
50597
|
-
...constraints,
|
|
50598
|
-
maxWidth: innerWidth
|
|
50599
|
-
});
|
|
50600
|
-
children.push(childBox);
|
|
50601
|
-
currentY += childBox.height + gap;
|
|
50602
|
-
}
|
|
50603
|
-
const totalHeight = childMeasurements.reduce(
|
|
50604
|
-
(sum, m, i) => sum + m.height + (i > 0 ? gap : 0),
|
|
50605
|
-
0
|
|
50606
|
-
);
|
|
50607
|
-
return {
|
|
50608
|
-
x,
|
|
50609
|
-
y,
|
|
50610
|
-
width: constraints.maxWidth,
|
|
50611
|
-
height: totalHeight + padding.top + padding.bottom,
|
|
50612
|
-
node,
|
|
50613
|
-
children,
|
|
50614
|
-
padding
|
|
50615
|
-
};
|
|
49532
|
+
renderMain(node) {
|
|
49533
|
+
return node.children.map((c) => this.renderNode(c)).join("\n");
|
|
50616
49534
|
}
|
|
50617
|
-
|
|
50618
|
-
const
|
|
50619
|
-
const
|
|
50620
|
-
const
|
|
50621
|
-
const
|
|
50622
|
-
|
|
50623
|
-
|
|
50624
|
-
|
|
50625
|
-
|
|
50626
|
-
|
|
50627
|
-
|
|
50628
|
-
}
|
|
50629
|
-
|
|
50630
|
-
currentY += childBox.height + gap;
|
|
50631
|
-
}
|
|
50632
|
-
const contentHeight = currentY - y - padding.top - gap + padding.bottom;
|
|
50633
|
-
const height = constraints.maxHeight || Math.max(contentHeight, 200);
|
|
50634
|
-
return {
|
|
50635
|
-
x,
|
|
50636
|
-
y,
|
|
50637
|
-
width,
|
|
50638
|
-
height,
|
|
50639
|
-
node,
|
|
50640
|
-
children,
|
|
50641
|
-
padding
|
|
50642
|
-
};
|
|
49535
|
+
renderFooter(node) {
|
|
49536
|
+
const height = 60;
|
|
49537
|
+
const x = this.currentX;
|
|
49538
|
+
const y = this.currentY;
|
|
49539
|
+
const savedY = this.currentY;
|
|
49540
|
+
this.currentY += 16;
|
|
49541
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49542
|
+
this.currentY = savedY + height + 8;
|
|
49543
|
+
return `
|
|
49544
|
+
<g transform="translate(${x}, ${y})">
|
|
49545
|
+
<rect width="${this.contentWidth}" height="${height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49546
|
+
${children}
|
|
49547
|
+
</g>`;
|
|
50643
49548
|
}
|
|
50644
|
-
|
|
50645
|
-
|
|
50646
|
-
|
|
50647
|
-
|
|
50648
|
-
|
|
50649
|
-
const
|
|
50650
|
-
|
|
50651
|
-
const
|
|
50652
|
-
|
|
50653
|
-
|
|
50654
|
-
|
|
50655
|
-
|
|
50656
|
-
|
|
50657
|
-
|
|
50658
|
-
const childBox = this.layoutNode(child, x + padding.left, currentY, {
|
|
50659
|
-
...constraints,
|
|
50660
|
-
maxWidth: innerWidth
|
|
50661
|
-
});
|
|
50662
|
-
children.push(childBox);
|
|
50663
|
-
currentY += childBox.height + gap;
|
|
50664
|
-
}
|
|
50665
|
-
const totalHeight = currentY - y - gap + padding.bottom;
|
|
50666
|
-
return {
|
|
50667
|
-
x,
|
|
50668
|
-
y,
|
|
50669
|
-
width: cardWidth,
|
|
50670
|
-
height: totalHeight,
|
|
50671
|
-
node,
|
|
50672
|
-
children,
|
|
50673
|
-
padding
|
|
50674
|
-
};
|
|
49549
|
+
renderSidebar(node) {
|
|
49550
|
+
const width = 200;
|
|
49551
|
+
const height = 300;
|
|
49552
|
+
const x = this.currentX;
|
|
49553
|
+
const y = this.currentY;
|
|
49554
|
+
const savedY = this.currentY;
|
|
49555
|
+
this.currentY += 16;
|
|
49556
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49557
|
+
this.currentY = savedY + height + 8;
|
|
49558
|
+
return `
|
|
49559
|
+
<g transform="translate(${x}, ${y})">
|
|
49560
|
+
<rect width="${width}" height="${height}" fill="${this.theme.colors.background}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49561
|
+
${children}
|
|
49562
|
+
</g>`;
|
|
50675
49563
|
}
|
|
50676
49564
|
// ===========================================
|
|
50677
|
-
//
|
|
49565
|
+
// Container Renderers
|
|
50678
49566
|
// ===========================================
|
|
50679
|
-
|
|
50680
|
-
|
|
50681
|
-
|
|
50682
|
-
|
|
50683
|
-
|
|
50684
|
-
|
|
50685
|
-
|
|
50686
|
-
case "Header":
|
|
50687
|
-
return this.renderHeaderBox(box);
|
|
50688
|
-
case "Footer":
|
|
50689
|
-
return this.renderFooterBox(box);
|
|
50690
|
-
case "Main":
|
|
50691
|
-
return this.renderMainBox(box);
|
|
50692
|
-
case "Sidebar":
|
|
50693
|
-
return this.renderSidebarBox(box);
|
|
50694
|
-
case "Card":
|
|
50695
|
-
return this.renderCardBox(box);
|
|
50696
|
-
case "Modal":
|
|
50697
|
-
return this.renderModalBox(box);
|
|
50698
|
-
case "Title":
|
|
50699
|
-
return this.renderTitleBox(box);
|
|
50700
|
-
case "Text":
|
|
50701
|
-
return this.renderTextBox(box);
|
|
50702
|
-
case "Button":
|
|
50703
|
-
return this.renderButtonBox(box);
|
|
50704
|
-
case "Input":
|
|
50705
|
-
return this.renderInputBox(box);
|
|
50706
|
-
case "Textarea":
|
|
50707
|
-
return this.renderTextareaBox(box);
|
|
50708
|
-
case "Select":
|
|
50709
|
-
return this.renderSelectBox(box);
|
|
50710
|
-
case "Checkbox":
|
|
50711
|
-
return this.renderCheckboxBox(box);
|
|
50712
|
-
case "Radio":
|
|
50713
|
-
return this.renderRadioBox(box);
|
|
50714
|
-
case "Switch":
|
|
50715
|
-
return this.renderSwitchBox(box);
|
|
50716
|
-
case "Link":
|
|
50717
|
-
return this.renderLinkBox(box);
|
|
50718
|
-
case "Image":
|
|
50719
|
-
return this.renderImageBox(box);
|
|
50720
|
-
case "Placeholder":
|
|
50721
|
-
return this.renderPlaceholderBox(box);
|
|
50722
|
-
case "Avatar":
|
|
50723
|
-
return this.renderAvatarBox(box);
|
|
50724
|
-
case "Badge":
|
|
50725
|
-
return this.renderBadgeBox(box);
|
|
50726
|
-
case "Table":
|
|
50727
|
-
return this.renderTableBox(box);
|
|
50728
|
-
case "List":
|
|
50729
|
-
return this.renderListBox(box);
|
|
50730
|
-
case "Alert":
|
|
50731
|
-
return this.renderAlertBox(box);
|
|
50732
|
-
case "Progress":
|
|
50733
|
-
return this.renderProgressBox(box);
|
|
50734
|
-
case "Spinner":
|
|
50735
|
-
return this.renderSpinnerBox(box);
|
|
50736
|
-
case "Nav":
|
|
50737
|
-
return this.renderNavBox(box);
|
|
50738
|
-
case "Tabs":
|
|
50739
|
-
return this.renderTabsBox(box);
|
|
50740
|
-
case "Breadcrumb":
|
|
50741
|
-
return this.renderBreadcrumbBox(box);
|
|
50742
|
-
case "Icon":
|
|
50743
|
-
return this.renderIconBox(box);
|
|
50744
|
-
case "Divider":
|
|
50745
|
-
return this.renderDividerBox(box);
|
|
50746
|
-
default:
|
|
50747
|
-
return `<!-- Unsupported: ${box.node.type} -->`;
|
|
50748
|
-
}
|
|
50749
|
-
}
|
|
50750
|
-
renderRowBox(box) {
|
|
50751
|
-
const childrenSvg = box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50752
|
-
return childrenSvg;
|
|
50753
|
-
}
|
|
50754
|
-
renderColBox(box) {
|
|
50755
|
-
const childrenSvg = box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50756
|
-
return childrenSvg;
|
|
50757
|
-
}
|
|
50758
|
-
renderHeaderBox(box) {
|
|
50759
|
-
const node = box.node;
|
|
50760
|
-
const hasBorder = node.border !== false;
|
|
50761
|
-
let svg = `<g>
|
|
50762
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" fill="${this.theme.colors.background}"/>`;
|
|
50763
|
-
if (hasBorder) {
|
|
50764
|
-
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"/>`;
|
|
50765
|
-
}
|
|
50766
|
-
svg += box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50767
|
-
svg += `</g>`;
|
|
50768
|
-
return svg;
|
|
50769
|
-
}
|
|
50770
|
-
renderFooterBox(box) {
|
|
50771
|
-
const node = box.node;
|
|
50772
|
-
const hasBorder = node.border !== false;
|
|
50773
|
-
let svg = `<g>
|
|
50774
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" fill="${this.theme.colors.background}"`;
|
|
50775
|
-
if (hasBorder) {
|
|
50776
|
-
svg += ` stroke="${this.theme.colors.border}" stroke-width="1"`;
|
|
50777
|
-
}
|
|
50778
|
-
svg += `/>`;
|
|
50779
|
-
svg += box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50780
|
-
svg += `</g>`;
|
|
50781
|
-
return svg;
|
|
50782
|
-
}
|
|
50783
|
-
renderMainBox(box) {
|
|
50784
|
-
const childrenSvg = box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50785
|
-
return childrenSvg;
|
|
50786
|
-
}
|
|
50787
|
-
renderSidebarBox(box) {
|
|
50788
|
-
let svg = `<g>
|
|
50789
|
-
<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"/>`;
|
|
50790
|
-
svg += box.children.map((child) => this.renderBox(child)).join("\n");
|
|
50791
|
-
svg += `</g>`;
|
|
50792
|
-
return svg;
|
|
50793
|
-
}
|
|
50794
|
-
renderCardBox(box) {
|
|
50795
|
-
const node = box.node;
|
|
50796
|
-
const shadowAttr = node.shadow ? 'filter="url(#shadow)"' : "";
|
|
50797
|
-
let svg = `<g>
|
|
50798
|
-
<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}/>`;
|
|
49567
|
+
renderCard(node) {
|
|
49568
|
+
const width = Math.min(300, this.contentWidth);
|
|
49569
|
+
const x = this.currentX;
|
|
49570
|
+
const y = this.currentY;
|
|
49571
|
+
const savedY = this.currentY;
|
|
49572
|
+
this.currentY += 16;
|
|
49573
|
+
let titleSvg = "";
|
|
50799
49574
|
if (node.title) {
|
|
50800
|
-
const
|
|
50801
|
-
|
|
49575
|
+
const titleFontSize = 16;
|
|
49576
|
+
titleSvg = `<text x="16" y="${titleFontSize + 12}" font-size="${titleFontSize}" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(node.title)}</text>`;
|
|
49577
|
+
this.currentY += titleFontSize + 8;
|
|
50802
49578
|
}
|
|
50803
|
-
|
|
50804
|
-
|
|
50805
|
-
|
|
49579
|
+
const childStartY = this.currentY - savedY;
|
|
49580
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49581
|
+
const contentHeight = Math.max(this.currentY - savedY, 100);
|
|
49582
|
+
this.currentY = savedY + contentHeight + 16;
|
|
49583
|
+
return `
|
|
49584
|
+
<g transform="translate(${x}, ${y})">
|
|
49585
|
+
<rect width="${width}" height="${contentHeight}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49586
|
+
${titleSvg}
|
|
49587
|
+
<g transform="translate(16, ${childStartY})">
|
|
49588
|
+
${children}
|
|
49589
|
+
</g>
|
|
49590
|
+
</g>`;
|
|
50806
49591
|
}
|
|
50807
|
-
|
|
50808
|
-
const
|
|
50809
|
-
const
|
|
50810
|
-
const
|
|
50811
|
-
|
|
50812
|
-
|
|
50813
|
-
<rect x="${modalX}" y="${modalY}" width="${box.width}" height="${box.height}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
49592
|
+
renderModal(node) {
|
|
49593
|
+
const width = 400;
|
|
49594
|
+
const height = 300;
|
|
49595
|
+
const x = (this.options.width - width) / 2;
|
|
49596
|
+
const y = (this.options.height - height) / 2;
|
|
49597
|
+
let titleSvg = "";
|
|
50814
49598
|
if (node.title) {
|
|
50815
|
-
|
|
50816
|
-
}
|
|
50817
|
-
for (const child of box.children) {
|
|
50818
|
-
const adjustedChild = { ...child, x: modalX + (child.x - box.x), y: modalY + (child.y - box.y) };
|
|
50819
|
-
svg += this.renderBox(adjustedChild);
|
|
50820
|
-
}
|
|
50821
|
-
svg += `</g>`;
|
|
50822
|
-
return svg;
|
|
50823
|
-
}
|
|
50824
|
-
renderTitleBox(box) {
|
|
50825
|
-
const node = box.node;
|
|
50826
|
-
const level = node.level || 1;
|
|
50827
|
-
const fontSize = this.getTitleFontSize(level);
|
|
50828
|
-
const textY = box.y + fontSize;
|
|
50829
|
-
let textX = box.x;
|
|
50830
|
-
let anchor = "start";
|
|
50831
|
-
if (node.align === "center") {
|
|
50832
|
-
textX = box.x + box.width / 2;
|
|
50833
|
-
anchor = "middle";
|
|
50834
|
-
} else if (node.align === "right") {
|
|
50835
|
-
textX = box.x + box.width;
|
|
50836
|
-
anchor = "end";
|
|
49599
|
+
titleSvg = `<text x="20" y="30" font-size="18" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(node.title)}</text>`;
|
|
50837
49600
|
}
|
|
50838
|
-
|
|
49601
|
+
const savedX = this.currentX;
|
|
49602
|
+
const savedY = this.currentY;
|
|
49603
|
+
this.currentX = 20;
|
|
49604
|
+
this.currentY = 50;
|
|
49605
|
+
const children = node.children.map((c) => this.renderNode(c)).join("\n");
|
|
49606
|
+
this.currentX = savedX;
|
|
49607
|
+
this.currentY = savedY;
|
|
49608
|
+
return `
|
|
49609
|
+
<g>
|
|
49610
|
+
<rect width="100%" height="100%" fill="rgba(0,0,0,0.5)" opacity="0.5"/>
|
|
49611
|
+
<g transform="translate(${x}, ${y})">
|
|
49612
|
+
<rect width="${width}" height="${height}" rx="8" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49613
|
+
${titleSvg}
|
|
49614
|
+
${children}
|
|
49615
|
+
</g>
|
|
49616
|
+
</g>`;
|
|
50839
49617
|
}
|
|
50840
|
-
|
|
50841
|
-
|
|
49618
|
+
// ===========================================
|
|
49619
|
+
// Text Renderers
|
|
49620
|
+
// ===========================================
|
|
49621
|
+
renderText(node) {
|
|
50842
49622
|
const fontSize = this.resolveFontSize(node.size);
|
|
50843
49623
|
const fill = node.muted ? this.theme.colors.muted : this.theme.colors.foreground;
|
|
50844
49624
|
const fontWeight = node.weight || "normal";
|
|
50845
|
-
const
|
|
50846
|
-
|
|
50847
|
-
|
|
50848
|
-
if (node.align === "center") {
|
|
50849
|
-
textX = box.x + box.width / 2;
|
|
50850
|
-
anchor = "middle";
|
|
50851
|
-
} else if (node.align === "right") {
|
|
50852
|
-
textX = box.x + box.width;
|
|
50853
|
-
anchor = "end";
|
|
50854
|
-
}
|
|
50855
|
-
return `<text x="${textX}" y="${textY}" font-size="${fontSize}" font-weight="${fontWeight}" fill="${fill}" text-anchor="${anchor}">${this.escapeXml(node.content)}</text>`;
|
|
49625
|
+
const y = this.currentY + fontSize;
|
|
49626
|
+
this.currentY += fontSize + 8;
|
|
49627
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" font-weight="${fontWeight}" fill="${fill}">${this.escapeXml(node.content)}</text>`;
|
|
50856
49628
|
}
|
|
50857
|
-
|
|
50858
|
-
const
|
|
50859
|
-
const
|
|
50860
|
-
const
|
|
50861
|
-
|
|
50862
|
-
|
|
50863
|
-
let strokeAttr = "";
|
|
50864
|
-
if (node.secondary) {
|
|
50865
|
-
fill = this.theme.colors.secondary;
|
|
50866
|
-
} else if (node.outline) {
|
|
50867
|
-
fill = "white";
|
|
50868
|
-
textFill = this.theme.colors.foreground;
|
|
50869
|
-
strokeAttr = `stroke="${this.theme.colors.border}" stroke-width="1"`;
|
|
50870
|
-
} else if (node.ghost) {
|
|
50871
|
-
fill = "transparent";
|
|
50872
|
-
textFill = this.theme.colors.foreground;
|
|
50873
|
-
}
|
|
50874
|
-
let svg = `<g>
|
|
50875
|
-
<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="4" fill="${fill}" ${strokeAttr}/>`;
|
|
50876
|
-
if (hasIcon) {
|
|
50877
|
-
const iconData = getIconData(node.icon);
|
|
50878
|
-
if (iconData) {
|
|
50879
|
-
const iconSize = 16;
|
|
50880
|
-
const iconX = isIconOnly ? box.x + (box.width - iconSize) / 2 : box.x + 16;
|
|
50881
|
-
const iconY = box.y + (box.height - iconSize) / 2;
|
|
50882
|
-
svg += this.renderIconPaths(iconData, iconX, iconY, iconSize, textFill);
|
|
50883
|
-
}
|
|
50884
|
-
}
|
|
50885
|
-
if (!isIconOnly) {
|
|
50886
|
-
const textX = hasIcon ? box.x + 36 + (box.width - 52) / 2 : box.x + box.width / 2;
|
|
50887
|
-
svg += `<text x="${textX}" y="${box.y + box.height / 2 + 5}" font-size="14" fill="${textFill}" text-anchor="middle">${this.escapeXml(node.content)}</text>`;
|
|
50888
|
-
}
|
|
50889
|
-
svg += `</g>`;
|
|
50890
|
-
return svg;
|
|
49629
|
+
renderTitle(node) {
|
|
49630
|
+
const level = node.level || 1;
|
|
49631
|
+
const fontSize = this.getTitleFontSize(level);
|
|
49632
|
+
const y = this.currentY + fontSize;
|
|
49633
|
+
this.currentY += fontSize + 12;
|
|
49634
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" font-weight="600" fill="${this.theme.colors.foreground}">${this.escapeXml(node.content)}</text>`;
|
|
50891
49635
|
}
|
|
50892
|
-
|
|
50893
|
-
const
|
|
50894
|
-
|
|
50895
|
-
|
|
49636
|
+
renderLink(node) {
|
|
49637
|
+
const fontSize = 14;
|
|
49638
|
+
const y = this.currentY + fontSize;
|
|
49639
|
+
this.currentY += fontSize + 8;
|
|
49640
|
+
return `<text x="${this.currentX}" y="${y}" font-size="${fontSize}" fill="${this.theme.colors.primary}" text-decoration="underline">${this.escapeXml(node.content)}</text>`;
|
|
49641
|
+
}
|
|
49642
|
+
// ===========================================
|
|
49643
|
+
// Input Renderers
|
|
49644
|
+
// ===========================================
|
|
49645
|
+
renderInput(node) {
|
|
49646
|
+
const width = 280;
|
|
49647
|
+
const height = 40;
|
|
49648
|
+
const x = this.currentX;
|
|
49649
|
+
let y = this.currentY;
|
|
49650
|
+
let result = "";
|
|
50896
49651
|
if (node.label) {
|
|
50897
|
-
|
|
49652
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50898
49653
|
y += 24;
|
|
50899
49654
|
}
|
|
50900
|
-
const inputHeight = 36;
|
|
50901
49655
|
const placeholder = node.placeholder || "";
|
|
50902
|
-
|
|
50903
|
-
|
|
50904
|
-
|
|
50905
|
-
|
|
49656
|
+
result += `
|
|
49657
|
+
<g transform="translate(${x}, ${y})">
|
|
49658
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49659
|
+
<text x="12" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(placeholder)}</text>
|
|
49660
|
+
</g>`;
|
|
49661
|
+
this.currentY = y + height + 12;
|
|
49662
|
+
return result;
|
|
50906
49663
|
}
|
|
50907
|
-
|
|
50908
|
-
const
|
|
50909
|
-
|
|
50910
|
-
|
|
49664
|
+
renderTextarea(node) {
|
|
49665
|
+
const width = 280;
|
|
49666
|
+
const height = 100;
|
|
49667
|
+
const x = this.currentX;
|
|
49668
|
+
let y = this.currentY;
|
|
49669
|
+
let result = "";
|
|
50911
49670
|
if (node.label) {
|
|
50912
|
-
|
|
49671
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50913
49672
|
y += 24;
|
|
50914
49673
|
}
|
|
50915
|
-
const textareaHeight = box.height - (node.label ? 24 : 0);
|
|
50916
49674
|
const placeholder = node.placeholder || "";
|
|
50917
|
-
|
|
50918
|
-
|
|
50919
|
-
|
|
50920
|
-
|
|
49675
|
+
result += `
|
|
49676
|
+
<g transform="translate(${x}, ${y})">
|
|
49677
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49678
|
+
<text x="12" y="24" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(placeholder)}</text>
|
|
49679
|
+
</g>`;
|
|
49680
|
+
this.currentY = y + height + 12;
|
|
49681
|
+
return result;
|
|
50921
49682
|
}
|
|
50922
|
-
|
|
50923
|
-
const
|
|
50924
|
-
|
|
50925
|
-
|
|
49683
|
+
renderSelect(node) {
|
|
49684
|
+
const width = 280;
|
|
49685
|
+
const height = 40;
|
|
49686
|
+
const x = this.currentX;
|
|
49687
|
+
let y = this.currentY;
|
|
49688
|
+
let result = "";
|
|
50926
49689
|
if (node.label) {
|
|
50927
|
-
|
|
49690
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50928
49691
|
y += 24;
|
|
50929
49692
|
}
|
|
50930
|
-
const selectHeight = 40;
|
|
50931
49693
|
const placeholder = node.placeholder || "Select...";
|
|
50932
|
-
|
|
50933
|
-
|
|
50934
|
-
|
|
50935
|
-
|
|
50936
|
-
|
|
49694
|
+
result += `
|
|
49695
|
+
<g transform="translate(${x}, ${y})">
|
|
49696
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49697
|
+
<text x="12" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(placeholder)}</text>
|
|
49698
|
+
<path d="M${width - 24} ${height / 2 - 3} l6 6 l6 -6" fill="none" stroke="${this.theme.colors.muted}" stroke-width="1.5"/>
|
|
49699
|
+
</g>`;
|
|
49700
|
+
this.currentY = y + height + 12;
|
|
49701
|
+
return result;
|
|
50937
49702
|
}
|
|
50938
|
-
|
|
50939
|
-
const
|
|
49703
|
+
renderCheckbox(node) {
|
|
49704
|
+
const x = this.currentX;
|
|
49705
|
+
const y = this.currentY;
|
|
50940
49706
|
const size = 18;
|
|
50941
|
-
let
|
|
50942
|
-
|
|
49707
|
+
let result = `
|
|
49708
|
+
<g transform="translate(${x}, ${y})">
|
|
49709
|
+
<rect width="${size}" height="${size}" rx="3" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50943
49710
|
if (node.checked) {
|
|
50944
|
-
|
|
49711
|
+
result += `<path d="M4 9 L7 12 L14 5" fill="none" stroke="${this.theme.colors.foreground}" stroke-width="2"/>`;
|
|
50945
49712
|
}
|
|
50946
49713
|
if (node.label) {
|
|
50947
|
-
|
|
49714
|
+
result += `<text x="${size + 8}" y="${size - 3}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50948
49715
|
}
|
|
50949
|
-
|
|
50950
|
-
|
|
49716
|
+
result += "</g>";
|
|
49717
|
+
this.currentY += size + 12;
|
|
49718
|
+
return result;
|
|
50951
49719
|
}
|
|
50952
|
-
|
|
50953
|
-
const
|
|
49720
|
+
renderRadio(node) {
|
|
49721
|
+
const x = this.currentX;
|
|
49722
|
+
const y = this.currentY;
|
|
50954
49723
|
const size = 18;
|
|
50955
49724
|
const radius = size / 2;
|
|
50956
|
-
|
|
50957
|
-
|
|
50958
|
-
|
|
50959
|
-
<circle cx="${cx}" cy="${cy}" r="${radius - 1}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
49725
|
+
let result = `
|
|
49726
|
+
<g transform="translate(${x}, ${y})">
|
|
49727
|
+
<circle cx="${radius}" cy="${radius}" r="${radius - 1}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50960
49728
|
if (node.checked) {
|
|
50961
|
-
|
|
49729
|
+
result += `<circle cx="${radius}" cy="${radius}" r="${radius - 5}" fill="${this.theme.colors.foreground}"/>`;
|
|
50962
49730
|
}
|
|
50963
49731
|
if (node.label) {
|
|
50964
|
-
|
|
49732
|
+
result += `<text x="${size + 8}" y="${size - 3}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50965
49733
|
}
|
|
50966
|
-
|
|
50967
|
-
|
|
49734
|
+
result += "</g>";
|
|
49735
|
+
this.currentY += size + 12;
|
|
49736
|
+
return result;
|
|
50968
49737
|
}
|
|
50969
|
-
|
|
50970
|
-
const
|
|
49738
|
+
renderSwitch(node) {
|
|
49739
|
+
const x = this.currentX;
|
|
49740
|
+
const y = this.currentY;
|
|
50971
49741
|
const width = 44;
|
|
50972
49742
|
const height = 24;
|
|
50973
49743
|
const radius = height / 2;
|
|
50974
49744
|
const isOn = node.checked;
|
|
50975
49745
|
const bgColor = isOn ? this.theme.colors.primary : this.theme.colors.border;
|
|
50976
|
-
const knobX = isOn ?
|
|
50977
|
-
let
|
|
50978
|
-
|
|
50979
|
-
<
|
|
49746
|
+
const knobX = isOn ? width - radius : radius;
|
|
49747
|
+
let result = `
|
|
49748
|
+
<g transform="translate(${x}, ${y})">
|
|
49749
|
+
<rect width="${width}" height="${height}" rx="${radius}" fill="${bgColor}"/>
|
|
49750
|
+
<circle cx="${knobX}" cy="${radius}" r="${radius - 3}" fill="white"/>`;
|
|
50980
49751
|
if (node.label) {
|
|
50981
|
-
|
|
49752
|
+
result += `<text x="${width + 8}" y="${height - 6}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
50982
49753
|
}
|
|
50983
|
-
|
|
50984
|
-
|
|
49754
|
+
result += "</g>";
|
|
49755
|
+
this.currentY += height + 12;
|
|
49756
|
+
return result;
|
|
50985
49757
|
}
|
|
50986
|
-
|
|
50987
|
-
|
|
50988
|
-
|
|
50989
|
-
|
|
50990
|
-
|
|
49758
|
+
// ===========================================
|
|
49759
|
+
// Button Renderer
|
|
49760
|
+
// ===========================================
|
|
49761
|
+
renderButton(node) {
|
|
49762
|
+
const content = node.content;
|
|
49763
|
+
const hasIcon = !!node.icon;
|
|
49764
|
+
const isIconOnly = hasIcon && !content.trim();
|
|
49765
|
+
const iconSize = 16;
|
|
49766
|
+
const padding = isIconOnly ? 8 : 16;
|
|
49767
|
+
let width;
|
|
49768
|
+
if (isIconOnly) {
|
|
49769
|
+
width = iconSize + padding * 2;
|
|
49770
|
+
} else if (hasIcon) {
|
|
49771
|
+
width = Math.max(80, content.length * 10 + iconSize + 40);
|
|
49772
|
+
} else {
|
|
49773
|
+
width = Math.max(80, content.length * 10 + 32);
|
|
49774
|
+
}
|
|
49775
|
+
const height = 36;
|
|
49776
|
+
const x = this.currentX;
|
|
49777
|
+
const y = this.currentY;
|
|
49778
|
+
let fill = this.theme.colors.primary;
|
|
49779
|
+
let textFill = "#ffffff";
|
|
49780
|
+
let isOutline = false;
|
|
49781
|
+
if (node.secondary) {
|
|
49782
|
+
fill = this.theme.colors.secondary;
|
|
49783
|
+
} else if (node.outline) {
|
|
49784
|
+
fill = "white";
|
|
49785
|
+
textFill = this.theme.colors.foreground;
|
|
49786
|
+
isOutline = true;
|
|
49787
|
+
} else if (node.ghost) {
|
|
49788
|
+
fill = "transparent";
|
|
49789
|
+
textFill = this.theme.colors.foreground;
|
|
49790
|
+
}
|
|
49791
|
+
this.currentY += height + 8;
|
|
49792
|
+
const strokeAttr = isOutline ? `stroke="${this.theme.colors.border}" stroke-width="1"` : "";
|
|
49793
|
+
let iconSvg = "";
|
|
49794
|
+
if (hasIcon) {
|
|
49795
|
+
const iconData = getIconData(node.icon);
|
|
49796
|
+
if (iconData) {
|
|
49797
|
+
const iconX = isIconOnly ? (width - iconSize) / 2 : padding;
|
|
49798
|
+
const iconY = (height - iconSize) / 2;
|
|
49799
|
+
iconSvg = this.renderIconPaths(iconData, iconX, iconY, iconSize, textFill);
|
|
49800
|
+
}
|
|
49801
|
+
}
|
|
49802
|
+
const textX = hasIcon && !isIconOnly ? padding + iconSize + 8 + (width - padding - iconSize - 8 - padding) / 2 : width / 2;
|
|
49803
|
+
const textContent = isIconOnly ? "" : `<text x="${textX}" y="${height / 2 + 5}" font-size="14" fill="${textFill}" text-anchor="middle">${this.escapeXml(content)}</text>`;
|
|
49804
|
+
return `
|
|
49805
|
+
<g transform="translate(${x}, ${y})">
|
|
49806
|
+
<rect width="${width}" height="${height}" rx="4" fill="${fill}" ${strokeAttr}/>
|
|
49807
|
+
${iconSvg}
|
|
49808
|
+
${textContent}
|
|
49809
|
+
</g>`;
|
|
49810
|
+
}
|
|
49811
|
+
/**
|
|
49812
|
+
* Render icon paths for SVG
|
|
49813
|
+
*/
|
|
49814
|
+
renderIconPaths(data, x, y, size, color) {
|
|
49815
|
+
const scale = size / 24;
|
|
49816
|
+
const paths = data.map(([tag, attrs]) => {
|
|
49817
|
+
const attrStr = Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(" ");
|
|
49818
|
+
return `<${tag} ${attrStr} />`;
|
|
49819
|
+
}).join("");
|
|
49820
|
+
return `<g transform="translate(${x}, ${y}) scale(${scale})" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${paths}</g>`;
|
|
50991
49821
|
}
|
|
50992
|
-
|
|
50993
|
-
|
|
50994
|
-
|
|
50995
|
-
|
|
50996
|
-
|
|
50997
|
-
|
|
50998
|
-
|
|
49822
|
+
// ===========================================
|
|
49823
|
+
// Display Renderers
|
|
49824
|
+
// ===========================================
|
|
49825
|
+
renderImage(node) {
|
|
49826
|
+
const width = node.w && typeof node.w === "number" ? node.w : 200;
|
|
49827
|
+
const height = node.h && typeof node.h === "number" ? node.h : 150;
|
|
49828
|
+
const x = this.currentX;
|
|
49829
|
+
const y = this.currentY;
|
|
49830
|
+
this.currentY += height + 12;
|
|
49831
|
+
return `
|
|
49832
|
+
<g transform="translate(${x}, ${y})">
|
|
49833
|
+
<rect width="${width}" height="${height}" fill="${this.theme.colors.muted}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49834
|
+
<line x1="0" y1="0" x2="${width}" y2="${height}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49835
|
+
<line x1="${width}" y1="0" x2="0" y2="${height}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49836
|
+
<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>
|
|
50999
49837
|
</g>`;
|
|
51000
49838
|
}
|
|
51001
|
-
|
|
51002
|
-
const
|
|
51003
|
-
const
|
|
51004
|
-
const
|
|
51005
|
-
|
|
51006
|
-
|
|
51007
|
-
|
|
51008
|
-
|
|
51009
|
-
|
|
51010
|
-
<
|
|
51011
|
-
<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>
|
|
49839
|
+
renderPlaceholder(node) {
|
|
49840
|
+
const width = node.w && typeof node.w === "number" ? node.w : 200;
|
|
49841
|
+
const height = node.h && typeof node.h === "number" ? node.h : 100;
|
|
49842
|
+
const x = this.currentX;
|
|
49843
|
+
const y = this.currentY;
|
|
49844
|
+
this.currentY += height + 12;
|
|
49845
|
+
return `
|
|
49846
|
+
<g transform="translate(${x}, ${y})">
|
|
49847
|
+
<rect width="${width}" height="${height}" fill="${this.theme.colors.muted}" stroke="${this.theme.colors.border}" stroke-width="1" stroke-dasharray="4,4"/>
|
|
49848
|
+
<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>
|
|
51012
49849
|
</g>`;
|
|
51013
49850
|
}
|
|
51014
|
-
|
|
51015
|
-
const
|
|
51016
|
-
const
|
|
51017
|
-
const
|
|
51018
|
-
const
|
|
49851
|
+
renderAvatar(node) {
|
|
49852
|
+
const sizes = { xs: 24, sm: 32, md: 40, lg: 48, xl: 64 };
|
|
49853
|
+
const size = sizes[node.size || "md"] || 40;
|
|
49854
|
+
const radius = size / 2;
|
|
49855
|
+
const x = this.currentX;
|
|
49856
|
+
const y = this.currentY;
|
|
51019
49857
|
const initial = node.name ? node.name.charAt(0).toUpperCase() : "?";
|
|
51020
|
-
|
|
51021
|
-
|
|
51022
|
-
|
|
49858
|
+
this.currentY += size + 12;
|
|
49859
|
+
return `
|
|
49860
|
+
<g transform="translate(${x}, ${y})">
|
|
49861
|
+
<circle cx="${radius}" cy="${radius}" r="${radius}" fill="${this.theme.colors.muted}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49862
|
+
<text x="${radius}" y="${radius + 5}" font-size="${size / 2.5}" fill="${this.theme.colors.foreground}" text-anchor="middle">${initial}</text>
|
|
51023
49863
|
</g>`;
|
|
51024
49864
|
}
|
|
51025
|
-
|
|
51026
|
-
const
|
|
51027
|
-
|
|
51028
|
-
|
|
51029
|
-
|
|
49865
|
+
renderBadge(node) {
|
|
49866
|
+
const content = node.content;
|
|
49867
|
+
const width = Math.max(24, content.length * 8 + 16);
|
|
49868
|
+
const height = 22;
|
|
49869
|
+
const x = this.currentX;
|
|
49870
|
+
const y = this.currentY;
|
|
49871
|
+
const fill = this.theme.colors.muted;
|
|
49872
|
+
const textFill = this.theme.colors.foreground;
|
|
49873
|
+
this.currentY += height + 8;
|
|
49874
|
+
return `
|
|
49875
|
+
<g transform="translate(${x}, ${y})">
|
|
49876
|
+
<rect width="${width}" height="${height}" rx="11" fill="${fill}" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49877
|
+
<text x="${width / 2}" y="${height / 2 + 4}" font-size="12" fill="${textFill}" text-anchor="middle">${this.escapeXml(content)}</text>
|
|
51030
49878
|
</g>`;
|
|
51031
49879
|
}
|
|
51032
|
-
|
|
51033
|
-
|
|
49880
|
+
// ===========================================
|
|
49881
|
+
// Data Renderers
|
|
49882
|
+
// ===========================================
|
|
49883
|
+
renderTable(node) {
|
|
51034
49884
|
const columns = node.columns || [];
|
|
51035
49885
|
const rows = node.rows || [];
|
|
51036
49886
|
const rowCount = rows.length || 3;
|
|
51037
49887
|
const colWidth = 120;
|
|
51038
49888
|
const rowHeight = 40;
|
|
51039
|
-
|
|
51040
|
-
|
|
49889
|
+
const x = this.currentX;
|
|
49890
|
+
const y = this.currentY;
|
|
49891
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
49892
|
+
svg += `<rect width="${columns.length * colWidth}" height="${rowHeight}" fill="${this.theme.colors.muted}"/>`;
|
|
51041
49893
|
columns.forEach((col, i) => {
|
|
51042
|
-
svg += `<text x="${
|
|
49894
|
+
svg += `<text x="${i * colWidth + 12}" y="${rowHeight / 2 + 5}" font-size="14" font-weight="600">${this.escapeXml(col)}</text>`;
|
|
51043
49895
|
});
|
|
51044
|
-
const displayRowCount = rows.length > 0 ? rows.length : rowCount;
|
|
49896
|
+
const displayRowCount = rows.length > 0 ? rows.length : Math.max(rowCount, 3);
|
|
51045
49897
|
for (let rowIdx = 0; rowIdx < displayRowCount; rowIdx++) {
|
|
51046
|
-
const rowY =
|
|
51047
|
-
svg += `<rect
|
|
49898
|
+
const rowY = (rowIdx + 1) * rowHeight;
|
|
49899
|
+
svg += `<rect y="${rowY}" width="${columns.length * colWidth}" height="${rowHeight}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51048
49900
|
columns.forEach((_, colIdx) => {
|
|
51049
49901
|
const cellContent = rows[rowIdx] && rows[rowIdx][colIdx] ? String(typeof rows[rowIdx][colIdx] === "object" ? "..." : rows[rowIdx][colIdx]) : "\u2014";
|
|
51050
|
-
svg += `<text x="${
|
|
49902
|
+
svg += `<text x="${colIdx * colWidth + 12}" y="${rowY + rowHeight / 2 + 5}" font-size="14" fill="${this.theme.colors.muted}">${this.escapeXml(cellContent)}</text>`;
|
|
51051
49903
|
});
|
|
51052
49904
|
}
|
|
51053
49905
|
svg += "</g>";
|
|
49906
|
+
this.currentY += (displayRowCount + 1) * rowHeight + 16;
|
|
51054
49907
|
return svg;
|
|
51055
49908
|
}
|
|
51056
|
-
|
|
51057
|
-
const
|
|
49909
|
+
renderList(node) {
|
|
49910
|
+
const x = this.currentX;
|
|
49911
|
+
let y = this.currentY;
|
|
51058
49912
|
const items = node.items || [];
|
|
51059
49913
|
const ordered = node.ordered || false;
|
|
51060
|
-
let svg =
|
|
49914
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51061
49915
|
items.forEach((item, idx) => {
|
|
51062
49916
|
const marker = ordered ? `${idx + 1}.` : "\u2022";
|
|
51063
49917
|
const content = typeof item === "string" ? item : item.content;
|
|
51064
|
-
svg += `<text x="
|
|
49918
|
+
svg += `<text x="0" y="${idx * 24 + 16}" font-size="14" fill="${this.theme.colors.foreground}">${marker} ${this.escapeXml(content)}</text>`;
|
|
51065
49919
|
});
|
|
51066
49920
|
svg += "</g>";
|
|
49921
|
+
this.currentY += items.length * 24 + 12;
|
|
51067
49922
|
return svg;
|
|
51068
49923
|
}
|
|
51069
|
-
|
|
51070
|
-
|
|
51071
|
-
|
|
51072
|
-
|
|
51073
|
-
|
|
49924
|
+
// ===========================================
|
|
49925
|
+
// Feedback Renderers
|
|
49926
|
+
// ===========================================
|
|
49927
|
+
renderAlert(node) {
|
|
49928
|
+
const width = Math.min(400, this.contentWidth);
|
|
49929
|
+
const height = 48;
|
|
49930
|
+
const x = this.currentX;
|
|
49931
|
+
const y = this.currentY;
|
|
49932
|
+
this.currentY += height + 12;
|
|
49933
|
+
return `
|
|
49934
|
+
<g transform="translate(${x}, ${y})">
|
|
49935
|
+
<rect width="${width}" height="${height}" rx="4" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>
|
|
49936
|
+
<text x="16" y="${height / 2 + 5}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.content)}</text>
|
|
51074
49937
|
</g>`;
|
|
51075
49938
|
}
|
|
51076
|
-
|
|
51077
|
-
const
|
|
51078
|
-
|
|
51079
|
-
|
|
49939
|
+
renderProgress(node) {
|
|
49940
|
+
const width = 200;
|
|
49941
|
+
const height = 8;
|
|
49942
|
+
const x = this.currentX;
|
|
49943
|
+
let y = this.currentY;
|
|
49944
|
+
let result = "";
|
|
51080
49945
|
if (node.label) {
|
|
51081
|
-
|
|
49946
|
+
result += `<text x="${x}" y="${y + 14}" font-size="14" fill="${this.theme.colors.foreground}">${this.escapeXml(node.label)}</text>`;
|
|
51082
49947
|
y += 24;
|
|
51083
49948
|
}
|
|
51084
|
-
const barHeight = 8;
|
|
51085
49949
|
const value = node.value || 0;
|
|
51086
49950
|
const max = node.max || 100;
|
|
51087
49951
|
const percent = Math.min(100, Math.max(0, value / max * 100));
|
|
51088
|
-
|
|
51089
|
-
|
|
51090
|
-
|
|
51091
|
-
|
|
49952
|
+
result += `
|
|
49953
|
+
<g transform="translate(${x}, ${y})">
|
|
49954
|
+
<rect width="${width}" height="${height}" rx="${height / 2}" fill="${this.theme.colors.muted}"/>
|
|
49955
|
+
<rect width="${width * percent / 100}" height="${height}" rx="${height / 2}" fill="${this.theme.colors.primary}"/>
|
|
49956
|
+
</g>`;
|
|
49957
|
+
this.currentY = y + height + 12;
|
|
49958
|
+
return result;
|
|
51092
49959
|
}
|
|
51093
|
-
|
|
51094
|
-
const
|
|
51095
|
-
const
|
|
51096
|
-
const
|
|
51097
|
-
|
|
51098
|
-
|
|
51099
|
-
|
|
49960
|
+
renderSpinner(node) {
|
|
49961
|
+
const sizes = { xs: 16, sm: 20, md: 24, lg: 32, xl: 40 };
|
|
49962
|
+
const size = sizes[node.size || "md"] || 24;
|
|
49963
|
+
const x = this.currentX + size / 2;
|
|
49964
|
+
const y = this.currentY + size / 2;
|
|
49965
|
+
const radius = size / 2 - 2;
|
|
49966
|
+
this.currentY += size + 12;
|
|
49967
|
+
return `
|
|
49968
|
+
<g transform="translate(${x}, ${y})">
|
|
49969
|
+
<circle r="${radius}" fill="none" stroke="${this.theme.colors.muted}" stroke-width="2"/>
|
|
49970
|
+
<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"/>
|
|
51100
49971
|
</g>`;
|
|
51101
49972
|
}
|
|
51102
|
-
|
|
51103
|
-
|
|
51104
|
-
|
|
51105
|
-
|
|
51106
|
-
if (node.children && node.children.length > 0) {
|
|
51107
|
-
let offsetY = 0;
|
|
51108
|
-
node.children.forEach((child) => {
|
|
51109
|
-
if (child.type === "divider") {
|
|
51110
|
-
offsetY += 16;
|
|
51111
|
-
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"/>`;
|
|
51112
|
-
offsetY += 8;
|
|
51113
|
-
} else if (child.type === "group") {
|
|
51114
|
-
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>`;
|
|
51115
|
-
offsetY += 28;
|
|
51116
|
-
child.items.forEach((item) => {
|
|
51117
|
-
if (item.type === "divider") {
|
|
51118
|
-
offsetY += 8;
|
|
51119
|
-
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"/>`;
|
|
51120
|
-
offsetY += 8;
|
|
51121
|
-
} else {
|
|
51122
|
-
const fill = item.active ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51123
|
-
const fontWeight = item.active ? 'font-weight="500"' : "";
|
|
51124
|
-
svg += `<text x="${box.x}" y="${box.y + offsetY + 16}" font-size="14" ${fontWeight} fill="${fill}">${this.escapeXml(item.label)}</text>`;
|
|
51125
|
-
offsetY += 32;
|
|
51126
|
-
}
|
|
51127
|
-
});
|
|
51128
|
-
} else if (child.type === "item") {
|
|
51129
|
-
const fill = child.active ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51130
|
-
const fontWeight = child.active ? 'font-weight="500"' : "";
|
|
51131
|
-
svg += `<text x="${box.x}" y="${box.y + offsetY + 16}" font-size="14" ${fontWeight} fill="${fill}">${this.escapeXml(child.label)}</text>`;
|
|
51132
|
-
offsetY += 32;
|
|
51133
|
-
}
|
|
51134
|
-
});
|
|
51135
|
-
svg += "</g>";
|
|
51136
|
-
return svg;
|
|
51137
|
-
}
|
|
49973
|
+
// ===========================================
|
|
49974
|
+
// Navigation Renderers
|
|
49975
|
+
// ===========================================
|
|
49976
|
+
renderNav(node) {
|
|
51138
49977
|
const items = node.items || [];
|
|
49978
|
+
const x = this.currentX;
|
|
49979
|
+
const y = this.currentY;
|
|
49980
|
+
const vertical = node.vertical || false;
|
|
49981
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51139
49982
|
if (vertical) {
|
|
51140
49983
|
items.forEach((item, idx) => {
|
|
51141
49984
|
const label = typeof item === "string" ? item : item.label;
|
|
51142
49985
|
const isActive = typeof item === "object" && item.active;
|
|
51143
49986
|
const fill = isActive ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51144
|
-
svg += `<text x="
|
|
49987
|
+
svg += `<text x="0" y="${idx * 32 + 16}" font-size="14" fill="${fill}">${this.escapeXml(label)}</text>`;
|
|
51145
49988
|
});
|
|
49989
|
+
this.currentY += items.length * 32 + 12;
|
|
51146
49990
|
} else {
|
|
51147
49991
|
let offsetX = 0;
|
|
51148
49992
|
items.forEach((item) => {
|
|
51149
49993
|
const label = typeof item === "string" ? item : item.label;
|
|
51150
49994
|
const isActive = typeof item === "object" && item.active;
|
|
51151
49995
|
const fill = isActive ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51152
|
-
svg += `<text x="${
|
|
51153
|
-
offsetX +=
|
|
49996
|
+
svg += `<text x="${offsetX}" y="16" font-size="14" fill="${fill}">${this.escapeXml(label)}</text>`;
|
|
49997
|
+
offsetX += label.length * 8 + 24;
|
|
51154
49998
|
});
|
|
49999
|
+
this.currentY += 32;
|
|
51155
50000
|
}
|
|
51156
50001
|
svg += "</g>";
|
|
51157
50002
|
return svg;
|
|
51158
50003
|
}
|
|
51159
|
-
|
|
51160
|
-
const node = box.node;
|
|
50004
|
+
renderTabs(node) {
|
|
51161
50005
|
const items = node.items || [];
|
|
50006
|
+
const x = this.currentX;
|
|
50007
|
+
const y = this.currentY;
|
|
51162
50008
|
const tabHeight = 40;
|
|
51163
|
-
let svg =
|
|
50009
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51164
50010
|
let offsetX = 0;
|
|
51165
|
-
items.forEach((item
|
|
50011
|
+
items.forEach((item) => {
|
|
51166
50012
|
const label = typeof item === "string" ? item : item;
|
|
51167
|
-
const tabWidth =
|
|
51168
|
-
|
|
51169
|
-
svg += `<
|
|
51170
|
-
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>`;
|
|
50013
|
+
const tabWidth = label.length * 10 + 24;
|
|
50014
|
+
svg += `<rect x="${offsetX}" width="${tabWidth}" height="${tabHeight}" fill="white" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
50015
|
+
svg += `<text x="${offsetX + tabWidth / 2}" y="${tabHeight / 2 + 5}" font-size="14" text-anchor="middle">${this.escapeXml(label)}</text>`;
|
|
51171
50016
|
offsetX += tabWidth;
|
|
51172
50017
|
});
|
|
51173
50018
|
svg += "</g>";
|
|
50019
|
+
this.currentY += tabHeight + 12;
|
|
51174
50020
|
return svg;
|
|
51175
50021
|
}
|
|
51176
|
-
|
|
51177
|
-
const node = box.node;
|
|
50022
|
+
renderBreadcrumb(node) {
|
|
51178
50023
|
const items = node.items || [];
|
|
51179
50024
|
const separator = "/";
|
|
51180
|
-
|
|
50025
|
+
const x = this.currentX;
|
|
50026
|
+
const y = this.currentY;
|
|
50027
|
+
let svg = `<g transform="translate(${x}, ${y})">`;
|
|
51181
50028
|
let offsetX = 0;
|
|
51182
50029
|
items.forEach((item, idx) => {
|
|
51183
50030
|
const label = typeof item === "string" ? item : item.label;
|
|
51184
50031
|
const isLast = idx === items.length - 1;
|
|
51185
50032
|
const fill = isLast ? this.theme.colors.foreground : this.theme.colors.muted;
|
|
51186
|
-
svg += `<text x="${
|
|
51187
|
-
offsetX +=
|
|
50033
|
+
svg += `<text x="${offsetX}" y="16" font-size="14" fill="${fill}">${this.escapeXml(label)}</text>`;
|
|
50034
|
+
offsetX += label.length * 8 + 8;
|
|
51188
50035
|
if (!isLast) {
|
|
51189
|
-
svg += `<text x="${
|
|
50036
|
+
svg += `<text x="${offsetX}" y="16" font-size="14" fill="${this.theme.colors.muted}">${separator}</text>`;
|
|
51190
50037
|
offsetX += 16;
|
|
51191
50038
|
}
|
|
51192
50039
|
});
|
|
51193
50040
|
svg += "</g>";
|
|
50041
|
+
this.currentY += 28;
|
|
51194
50042
|
return svg;
|
|
51195
50043
|
}
|
|
51196
|
-
renderIconBox(box) {
|
|
51197
|
-
const node = box.node;
|
|
51198
|
-
const iconData = getIconData(node.name);
|
|
51199
|
-
if (!iconData) {
|
|
51200
|
-
return `<!-- Icon not found: ${node.name} -->`;
|
|
51201
|
-
}
|
|
51202
|
-
const color = this.theme.colors.foreground;
|
|
51203
|
-
return this.renderIconPaths(iconData, box.x, box.y, box.width, color);
|
|
51204
|
-
}
|
|
51205
|
-
renderDividerBox(box) {
|
|
51206
|
-
return `<line x1="${box.x}" y1="${box.y}" x2="${box.x + box.width}" y2="${box.y}" stroke="${this.theme.colors.border}" stroke-width="1"/>`;
|
|
51207
|
-
}
|
|
51208
50044
|
// ===========================================
|
|
51209
50045
|
// Utility Methods
|
|
51210
50046
|
// ===========================================
|
|
51211
|
-
|
|
51212
|
-
const
|
|
51213
|
-
|
|
51214
|
-
|
|
51215
|
-
|
|
51216
|
-
|
|
51217
|
-
|
|
51218
|
-
|
|
51219
|
-
|
|
51220
|
-
|
|
51221
|
-
|
|
51222
|
-
|
|
51223
|
-
return { top: 16, right: 16, bottom: 16, left: 16 };
|
|
51224
|
-
}
|
|
51225
|
-
return defaultPadding;
|
|
51226
|
-
}
|
|
51227
|
-
let p = 0;
|
|
51228
|
-
if ("p" in node && node.p !== void 0) {
|
|
51229
|
-
p = this.resolveSpacing(node.p);
|
|
51230
|
-
}
|
|
51231
|
-
let px = p;
|
|
51232
|
-
let py = p;
|
|
51233
|
-
if ("px" in node && node.px !== void 0) {
|
|
51234
|
-
px = this.resolveSpacing(node.px);
|
|
51235
|
-
}
|
|
51236
|
-
if ("py" in node && node.py !== void 0) {
|
|
51237
|
-
py = this.resolveSpacing(node.py);
|
|
51238
|
-
}
|
|
51239
|
-
if (node.type === "Header") {
|
|
51240
|
-
return { top: 0, right: px, bottom: 0, left: px };
|
|
51241
|
-
}
|
|
51242
|
-
return { top: py, right: px, bottom: py, left: px };
|
|
51243
|
-
}
|
|
51244
|
-
getGap(node) {
|
|
51245
|
-
if ("gap" in node && node.gap !== void 0) {
|
|
51246
|
-
return this.resolveSpacing(node.gap);
|
|
51247
|
-
}
|
|
51248
|
-
return void 0;
|
|
51249
|
-
}
|
|
51250
|
-
resolveSpacing(value) {
|
|
51251
|
-
if (typeof value === "number") {
|
|
51252
|
-
return value * 4;
|
|
51253
|
-
}
|
|
51254
|
-
if (typeof value === "object" && value && "value" in value) {
|
|
51255
|
-
return value.value;
|
|
51256
|
-
}
|
|
51257
|
-
return 0;
|
|
51258
|
-
}
|
|
51259
|
-
resolveSize(value) {
|
|
51260
|
-
if (value === void 0 || value === null) return void 0;
|
|
51261
|
-
if (typeof value === "number") return value;
|
|
51262
|
-
if (typeof value === "string") {
|
|
51263
|
-
if (value === "full") return void 0;
|
|
51264
|
-
const num = parseFloat(value);
|
|
51265
|
-
if (!isNaN(num)) return num;
|
|
51266
|
-
}
|
|
51267
|
-
if (typeof value === "object" && value && "value" in value) {
|
|
51268
|
-
return value.value;
|
|
51269
|
-
}
|
|
51270
|
-
return void 0;
|
|
51271
|
-
}
|
|
51272
|
-
isFullWidth(node) {
|
|
51273
|
-
if ("w" in node) {
|
|
51274
|
-
return node.w === "full";
|
|
51275
|
-
}
|
|
51276
|
-
return false;
|
|
51277
|
-
}
|
|
51278
|
-
estimateTextWidth(text, fontSize) {
|
|
51279
|
-
return text.length * fontSize * 0.6;
|
|
50047
|
+
getFontSize(size) {
|
|
50048
|
+
const sizes = {
|
|
50049
|
+
xs: 12,
|
|
50050
|
+
sm: 14,
|
|
50051
|
+
base: 16,
|
|
50052
|
+
md: 16,
|
|
50053
|
+
lg: 18,
|
|
50054
|
+
xl: 20,
|
|
50055
|
+
"2xl": 24,
|
|
50056
|
+
"3xl": 30
|
|
50057
|
+
};
|
|
50058
|
+
return sizes[size] || 16;
|
|
51280
50059
|
}
|
|
51281
50060
|
resolveFontSize(size) {
|
|
51282
50061
|
if (!size) return 16;
|
|
51283
50062
|
if (typeof size === "string") {
|
|
51284
|
-
|
|
51285
|
-
xs: 12,
|
|
51286
|
-
sm: 14,
|
|
51287
|
-
base: 16,
|
|
51288
|
-
md: 16,
|
|
51289
|
-
lg: 18,
|
|
51290
|
-
xl: 20,
|
|
51291
|
-
"2xl": 24,
|
|
51292
|
-
"3xl": 30
|
|
51293
|
-
};
|
|
51294
|
-
return sizes[size] || 16;
|
|
50063
|
+
return this.getFontSize(size);
|
|
51295
50064
|
}
|
|
51296
50065
|
if (typeof size === "object" && "value" in size) {
|
|
51297
50066
|
if (size.unit === "px") return size.value;
|
|
@@ -51302,8 +50071,15 @@ var SvgRenderer = class {
|
|
|
51302
50071
|
return 16;
|
|
51303
50072
|
}
|
|
51304
50073
|
getTitleFontSize(level) {
|
|
51305
|
-
const sizes = {
|
|
51306
|
-
|
|
50074
|
+
const sizes = {
|
|
50075
|
+
1: 32,
|
|
50076
|
+
2: 28,
|
|
50077
|
+
3: 24,
|
|
50078
|
+
4: 20,
|
|
50079
|
+
5: 18,
|
|
50080
|
+
6: 16
|
|
50081
|
+
};
|
|
50082
|
+
return sizes[level] || 24;
|
|
51307
50083
|
}
|
|
51308
50084
|
escapeXml(str) {
|
|
51309
50085
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -51364,22 +50140,15 @@ function renderToSvg2(document, options = {}) {
|
|
|
51364
50140
|
height = viewport.height;
|
|
51365
50141
|
}
|
|
51366
50142
|
}
|
|
50143
|
+
const padding = options.padding ?? 20;
|
|
51367
50144
|
const background = options.background ?? "#ffffff";
|
|
51368
50145
|
const { html, css } = render(document, { theme: "light" });
|
|
51369
50146
|
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
51370
50147
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
51371
50148
|
viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
51372
50149
|
<rect width="100%" height="100%" fill="${background}"/>
|
|
51373
|
-
<foreignObject x="
|
|
51374
|
-
<div xmlns="http://www.w3.org/1999/xhtml" style="
|
|
51375
|
-
width: ${width}px;
|
|
51376
|
-
height: ${height}px;
|
|
51377
|
-
overflow: hidden;
|
|
51378
|
-
display: flex;
|
|
51379
|
-
justify-content: center;
|
|
51380
|
-
align-items: center;
|
|
51381
|
-
box-sizing: border-box;
|
|
51382
|
-
">
|
|
50150
|
+
<foreignObject x="${padding}" y="${padding}" width="${width - padding * 2}" height="${height - padding * 2}">
|
|
50151
|
+
<div xmlns="http://www.w3.org/1999/xhtml" style="width: 100%; height: 100%; overflow: hidden;">
|
|
51383
50152
|
<style type="text/css">
|
|
51384
50153
|
${css}
|
|
51385
50154
|
</style>
|