@wire-dsl/engine 0.6.0 → 0.7.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/README.md +1 -1
- package/dist/index.cjs +923 -138
- package/dist/index.d.cts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +923 -138
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2589,13 +2589,13 @@ ${messages}`);
|
|
|
2589
2589
|
"Heading",
|
|
2590
2590
|
"Text",
|
|
2591
2591
|
"Label",
|
|
2592
|
+
"Paragraph",
|
|
2592
2593
|
"Image",
|
|
2593
2594
|
"Card",
|
|
2594
2595
|
"Stat",
|
|
2595
2596
|
"Topbar",
|
|
2596
2597
|
"Table",
|
|
2597
2598
|
"Chart",
|
|
2598
|
-
"ChartPlaceholder",
|
|
2599
2599
|
"Textarea",
|
|
2600
2600
|
"Select",
|
|
2601
2601
|
"Checkbox",
|
|
@@ -2930,19 +2930,19 @@ var ICON_SIZES_BY_DENSITY = {
|
|
|
2930
2930
|
comfortable: { xs: 14, sm: 16, md: 20, lg: 28, xl: 36 }
|
|
2931
2931
|
};
|
|
2932
2932
|
var ICON_BUTTON_SIZES_BY_DENSITY = {
|
|
2933
|
-
compact: { sm: 20, md: 24, lg: 32 },
|
|
2934
|
-
normal: { sm: 24, md: 32, lg: 40 },
|
|
2935
|
-
comfortable: { sm: 28, md: 40, lg: 48 }
|
|
2933
|
+
compact: { xs: 16, sm: 20, md: 24, lg: 32, xl: 40 },
|
|
2934
|
+
normal: { xs: 20, sm: 24, md: 32, lg: 40, xl: 48 },
|
|
2935
|
+
comfortable: { xs: 24, sm: 28, md: 40, lg: 48, xl: 56 }
|
|
2936
2936
|
};
|
|
2937
2937
|
var CONTROL_HEIGHTS_BY_DENSITY = {
|
|
2938
|
-
compact: { sm: 28, md: 32, lg: 36 },
|
|
2939
|
-
normal: { sm: 36, md: 40, lg: 48 },
|
|
2940
|
-
comfortable: { sm: 40, md: 48, lg: 56 }
|
|
2938
|
+
compact: { xs: 24, sm: 28, md: 32, lg: 36, xl: 44 },
|
|
2939
|
+
normal: { xs: 28, sm: 36, md: 40, lg: 48, xl: 56 },
|
|
2940
|
+
comfortable: { xs: 32, sm: 40, md: 48, lg: 56, xl: 64 }
|
|
2941
2941
|
};
|
|
2942
2942
|
var ACTION_CONTROL_HEIGHTS_BY_DENSITY = {
|
|
2943
|
-
compact: { sm:
|
|
2944
|
-
normal: { sm:
|
|
2945
|
-
comfortable: { sm:
|
|
2943
|
+
compact: { xs: 24, sm: 28, md: 32, lg: 36, xl: 44 },
|
|
2944
|
+
normal: { xs: 28, sm: 36, md: 40, lg: 48, xl: 56 },
|
|
2945
|
+
comfortable: { xs: 32, sm: 40, md: 48, lg: 56, xl: 64 }
|
|
2946
2946
|
};
|
|
2947
2947
|
var CONTROL_PADDING_BY_DENSITY = {
|
|
2948
2948
|
compact: { none: 0, xs: 4, sm: 8, md: 10, lg: 14, xl: 18 },
|
|
@@ -3615,7 +3615,7 @@ var LayoutEngine = class {
|
|
|
3615
3615
|
wrapTextToLines(text, maxWidth, fontSize) {
|
|
3616
3616
|
const normalized = text.replace(/\r\n/g, "\n");
|
|
3617
3617
|
const paragraphs = normalized.split("\n");
|
|
3618
|
-
const charWidth = fontSize * 0.
|
|
3618
|
+
const charWidth = fontSize * 0.5;
|
|
3619
3619
|
const safeWidth = Math.max(maxWidth, charWidth);
|
|
3620
3620
|
const maxCharsPerLine = Math.max(1, Math.floor(safeWidth / charWidth));
|
|
3621
3621
|
const lines = [];
|
|
@@ -3653,12 +3653,14 @@ var LayoutEngine = class {
|
|
|
3653
3653
|
getIntrinsicComponentHeight(node, availableWidth) {
|
|
3654
3654
|
if (node.kind !== "component") return this.getComponentHeight();
|
|
3655
3655
|
const controlSize = String(node.props.size || "md");
|
|
3656
|
+
const actionControlSize = String(node.props.size || "sm");
|
|
3656
3657
|
const density = this.style.density || "normal";
|
|
3657
3658
|
const inputControlHeight = resolveControlHeight(controlSize, density);
|
|
3658
|
-
const actionControlHeight = resolveActionControlHeight(
|
|
3659
|
+
const actionControlHeight = resolveActionControlHeight(actionControlSize, density);
|
|
3659
3660
|
const controlLabelOffset = node.componentType === "Input" || node.componentType === "Textarea" || node.componentType === "Select" ? this.getControlLabelOffset(String(node.props.label || "")) : (node.componentType === "Button" || node.componentType === "IconButton") && this.parseBooleanProp(node.props.labelSpace, false) ? 18 : 0;
|
|
3660
3661
|
if (node.componentType === "Image") {
|
|
3661
3662
|
const placeholder = String(node.props.placeholder || "landscape");
|
|
3663
|
+
const isCircle = this.parseBooleanProp(node.props.circle, false);
|
|
3662
3664
|
const aspectRatios = {
|
|
3663
3665
|
landscape: 16 / 9,
|
|
3664
3666
|
portrait: 2 / 3,
|
|
@@ -3666,7 +3668,7 @@ var LayoutEngine = class {
|
|
|
3666
3668
|
icon: 1,
|
|
3667
3669
|
avatar: 1
|
|
3668
3670
|
};
|
|
3669
|
-
const ratio = aspectRatios[placeholder] || 16 / 9;
|
|
3671
|
+
const ratio = isCircle ? 1 : aspectRatios[placeholder] || 16 / 9;
|
|
3670
3672
|
const explicitHeight = Number(node.props.height);
|
|
3671
3673
|
if (!isNaN(explicitHeight) && explicitHeight > 0) {
|
|
3672
3674
|
return explicitHeight;
|
|
@@ -3718,13 +3720,19 @@ var LayoutEngine = class {
|
|
|
3718
3720
|
}
|
|
3719
3721
|
return Math.max(1, Math.ceil(wrappedHeight + verticalPadding * 2));
|
|
3720
3722
|
}
|
|
3721
|
-
if (node.componentType === "Text") {
|
|
3723
|
+
if (node.componentType === "Text" || node.componentType === "Paragraph") {
|
|
3722
3724
|
const content = String(node.props.text || "");
|
|
3723
|
-
const { fontSize, lineHeight } = this.getTextMetricsForDensity();
|
|
3725
|
+
const { fontSize: defaultFontSize, lineHeight } = this.getTextMetricsForDensity();
|
|
3726
|
+
const sizeProp = String(node.props.size || "");
|
|
3727
|
+
const textFontSizeMap = { xs: 10, sm: 12, lg: 16, xl: 20 };
|
|
3728
|
+
const fontSize = textFontSizeMap[sizeProp] ?? defaultFontSize;
|
|
3724
3729
|
const lineHeightPx = Math.ceil(fontSize * lineHeight);
|
|
3725
3730
|
const maxWidth = availableWidth && availableWidth > 0 ? availableWidth : 200;
|
|
3726
3731
|
const lines = this.wrapTextToLines(content, maxWidth, fontSize);
|
|
3727
3732
|
const wrappedHeight = Math.max(1, lines.length) * lineHeightPx;
|
|
3733
|
+
if (sizeProp) {
|
|
3734
|
+
return wrappedHeight;
|
|
3735
|
+
}
|
|
3728
3736
|
return Math.max(this.getComponentHeight(), wrappedHeight);
|
|
3729
3737
|
}
|
|
3730
3738
|
if (node.componentType === "Alert") {
|
|
@@ -3753,7 +3761,7 @@ var LayoutEngine = class {
|
|
|
3753
3761
|
if (node.componentType === "Modal") return 300;
|
|
3754
3762
|
if (node.componentType === "Card") return 120;
|
|
3755
3763
|
if (node.componentType === "Stat") return 120;
|
|
3756
|
-
if (node.componentType === "Chart"
|
|
3764
|
+
if (node.componentType === "Chart") return 250;
|
|
3757
3765
|
if (node.componentType === "List") {
|
|
3758
3766
|
const itemsFromProps = String(node.props.items || "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
3759
3767
|
const parsedItemsMock = Number(node.props.itemsMock ?? 4);
|
|
@@ -3764,7 +3772,14 @@ var LayoutEngine = class {
|
|
|
3764
3772
|
const contentHeight = titleHeight + itemCount * itemHeight;
|
|
3765
3773
|
return Math.max(this.getComponentHeight(), contentHeight);
|
|
3766
3774
|
}
|
|
3767
|
-
if (node.componentType === "Topbar")
|
|
3775
|
+
if (node.componentType === "Topbar") {
|
|
3776
|
+
const TOPBAR_HEIGHTS = { sm: 44, md: 56, lg: 72 };
|
|
3777
|
+
return TOPBAR_HEIGHTS[String(node.props.size || "md")] ?? 56;
|
|
3778
|
+
}
|
|
3779
|
+
if (node.componentType === "Tabs") {
|
|
3780
|
+
const TABS_HEIGHTS = { sm: 32, md: 44, lg: 52 };
|
|
3781
|
+
return TABS_HEIGHTS[String(node.props.size || "md")] ?? 44;
|
|
3782
|
+
}
|
|
3768
3783
|
if (node.componentType === "Divider") return 1;
|
|
3769
3784
|
if (node.componentType === "Separate") return this.getSeparateSize(node);
|
|
3770
3785
|
if (node.componentType === "Input" || node.componentType === "Select") {
|
|
@@ -3773,6 +3788,11 @@ var LayoutEngine = class {
|
|
|
3773
3788
|
if (node.componentType === "Button" || node.componentType === "IconButton" || node.componentType === "Link") {
|
|
3774
3789
|
return actionControlHeight + controlLabelOffset;
|
|
3775
3790
|
}
|
|
3791
|
+
if (node.componentType === "Badge" || node.componentType === "Chip") {
|
|
3792
|
+
const BADGE_HEIGHTS = { xs: 28, sm: 36, md: 40, lg: 48, xl: 56 };
|
|
3793
|
+
const badgeSize = String(node.props.size || "md");
|
|
3794
|
+
return BADGE_HEIGHTS[badgeSize] ?? 40;
|
|
3795
|
+
}
|
|
3776
3796
|
return this.getComponentHeight();
|
|
3777
3797
|
}
|
|
3778
3798
|
getControlLabelOffset(label) {
|
|
@@ -3828,7 +3848,7 @@ var LayoutEngine = class {
|
|
|
3828
3848
|
return resolveIconSize(size, this.style.density || "normal");
|
|
3829
3849
|
}
|
|
3830
3850
|
if (node.componentType === "IconButton") {
|
|
3831
|
-
const size = String(node.props.size || "
|
|
3851
|
+
const size = String(node.props.size || "sm");
|
|
3832
3852
|
const density = this.style.density || "normal";
|
|
3833
3853
|
const baseSize = resolveIconButtonSize(size, density);
|
|
3834
3854
|
const extraPadding = resolveControlHorizontalPadding(String(node.props.padding || "none"), density);
|
|
@@ -3886,7 +3906,13 @@ var LayoutEngine = class {
|
|
|
3886
3906
|
}
|
|
3887
3907
|
if (node.componentType === "Badge" || node.componentType === "Chip") {
|
|
3888
3908
|
const text = String(node.props.text || "");
|
|
3889
|
-
|
|
3909
|
+
const size = String(node.props.size || "md");
|
|
3910
|
+
const BADGE_CHAR_W = { xs: 6, sm: 6.5, md: 7, lg: 7.5, xl: 8.5 };
|
|
3911
|
+
const BADGE_PAD_X = { xs: 5, sm: 6, md: 8, lg: 10, xl: 14 };
|
|
3912
|
+
const customPadding = node.props.padding !== void 0 ? Number(node.props.padding) : void 0;
|
|
3913
|
+
const padX = customPadding !== void 0 && !isNaN(customPadding) ? customPadding : BADGE_PAD_X[size] ?? 8;
|
|
3914
|
+
const charW = BADGE_CHAR_W[size] ?? 7;
|
|
3915
|
+
return Math.max(padX * 4, text.length * charW + padX * 2);
|
|
3890
3916
|
}
|
|
3891
3917
|
return 120;
|
|
3892
3918
|
}
|
|
@@ -4170,34 +4196,358 @@ MockDataGenerator.HEADER_TO_MOCK = {
|
|
|
4170
4196
|
var ColorResolver = class {
|
|
4171
4197
|
constructor() {
|
|
4172
4198
|
this.customColors = {};
|
|
4173
|
-
// Named colors palette
|
|
4199
|
+
// Named colors palette — Full Material Design + utility aliases
|
|
4174
4200
|
this.namedColors = {
|
|
4175
|
-
//
|
|
4201
|
+
// ── Utility ──────────────────────────────────────────────────────────────
|
|
4176
4202
|
white: "#FFFFFF",
|
|
4177
4203
|
black: "#000000",
|
|
4178
|
-
gray: "#
|
|
4179
|
-
|
|
4204
|
+
gray: "#9E9E9E",
|
|
4205
|
+
// alias for grey 500
|
|
4206
|
+
grey: "#9E9E9E",
|
|
4207
|
+
slate: "#607D8B",
|
|
4208
|
+
// alias for blue_grey 500
|
|
4180
4209
|
zinc: "#71717A",
|
|
4181
|
-
//
|
|
4182
|
-
red: "#EF4444",
|
|
4183
|
-
orange: "#F97316",
|
|
4184
|
-
yellow: "#EAB308",
|
|
4185
|
-
lime: "#84CC16",
|
|
4186
|
-
green: "#22C55E",
|
|
4210
|
+
// Extra well-known non-Material names (kept for backward compat)
|
|
4187
4211
|
emerald: "#10B981",
|
|
4188
|
-
teal: "#14B8A6",
|
|
4189
|
-
cyan: "#06B6D4",
|
|
4190
|
-
blue: "#3B82F6",
|
|
4191
|
-
indigo: "#6366F1",
|
|
4192
4212
|
violet: "#8B5CF6",
|
|
4193
|
-
purple: "#A855F7",
|
|
4194
4213
|
fuchsia: "#D946EF",
|
|
4195
|
-
pink: "#EC4899",
|
|
4196
4214
|
rose: "#F43F5E",
|
|
4197
|
-
// Light variants
|
|
4198
|
-
"red-light": "#
|
|
4199
|
-
"blue-light": "#
|
|
4200
|
-
"green-light": "#
|
|
4215
|
+
// Light utility variants
|
|
4216
|
+
"red-light": "#FFCDD2",
|
|
4217
|
+
"blue-light": "#BBDEFB",
|
|
4218
|
+
"green-light": "#C8E6C9",
|
|
4219
|
+
// ── Red ──────────────────────────────────────────────────────────────────
|
|
4220
|
+
red: "#F44336",
|
|
4221
|
+
// 500
|
|
4222
|
+
red_50: "#FFEBEE",
|
|
4223
|
+
red_100: "#FFCDD2",
|
|
4224
|
+
red_200: "#EF9A9A",
|
|
4225
|
+
red_300: "#E57373",
|
|
4226
|
+
red_400: "#EF5350",
|
|
4227
|
+
red_500: "#F44336",
|
|
4228
|
+
red_600: "#E53935",
|
|
4229
|
+
red_700: "#D32F2F",
|
|
4230
|
+
red_800: "#C62828",
|
|
4231
|
+
red_900: "#B71C1C",
|
|
4232
|
+
red_A100: "#FF8A80",
|
|
4233
|
+
red_A200: "#FF5252",
|
|
4234
|
+
red_A400: "#FF1744",
|
|
4235
|
+
red_A700: "#D50000",
|
|
4236
|
+
// ── Pink ─────────────────────────────────────────────────────────────────
|
|
4237
|
+
pink: "#E91E63",
|
|
4238
|
+
// 500
|
|
4239
|
+
pink_50: "#FCE4EC",
|
|
4240
|
+
pink_100: "#F8BBD0",
|
|
4241
|
+
pink_200: "#F48FB1",
|
|
4242
|
+
pink_300: "#F06292",
|
|
4243
|
+
pink_400: "#EC407A",
|
|
4244
|
+
pink_500: "#E91E63",
|
|
4245
|
+
pink_600: "#D81B60",
|
|
4246
|
+
pink_700: "#C2185B",
|
|
4247
|
+
pink_800: "#AD1457",
|
|
4248
|
+
pink_900: "#880E4F",
|
|
4249
|
+
pink_A100: "#FF80AB",
|
|
4250
|
+
pink_A200: "#FF4081",
|
|
4251
|
+
pink_A400: "#F50057",
|
|
4252
|
+
pink_A700: "#C51162",
|
|
4253
|
+
// ── Purple ───────────────────────────────────────────────────────────────
|
|
4254
|
+
purple: "#9C27B0",
|
|
4255
|
+
// 500
|
|
4256
|
+
purple_50: "#F3E5F5",
|
|
4257
|
+
purple_100: "#E1BEE7",
|
|
4258
|
+
purple_200: "#CE93D8",
|
|
4259
|
+
purple_300: "#BA68C8",
|
|
4260
|
+
purple_400: "#AB47BC",
|
|
4261
|
+
purple_500: "#9C27B0",
|
|
4262
|
+
purple_600: "#8E24AA",
|
|
4263
|
+
purple_700: "#7B1FA2",
|
|
4264
|
+
purple_800: "#6A1B9A",
|
|
4265
|
+
purple_900: "#4A148C",
|
|
4266
|
+
purple_A100: "#EA80FC",
|
|
4267
|
+
purple_A200: "#E040FB",
|
|
4268
|
+
purple_A400: "#D500F9",
|
|
4269
|
+
purple_A700: "#AA00FF",
|
|
4270
|
+
// ── Deep Purple ──────────────────────────────────────────────────────────
|
|
4271
|
+
deep_purple: "#673AB7",
|
|
4272
|
+
// 500
|
|
4273
|
+
deep_purple_50: "#EDE7F6",
|
|
4274
|
+
deep_purple_100: "#D1C4E9",
|
|
4275
|
+
deep_purple_200: "#B39DDB",
|
|
4276
|
+
deep_purple_300: "#9575CD",
|
|
4277
|
+
deep_purple_400: "#7E57C2",
|
|
4278
|
+
deep_purple_500: "#673AB7",
|
|
4279
|
+
deep_purple_600: "#5E35B1",
|
|
4280
|
+
deep_purple_700: "#512DA8",
|
|
4281
|
+
deep_purple_800: "#4527A0",
|
|
4282
|
+
deep_purple_900: "#311B92",
|
|
4283
|
+
deep_purple_A100: "#B388FF",
|
|
4284
|
+
deep_purple_A200: "#7C4DFF",
|
|
4285
|
+
deep_purple_A400: "#651FFF",
|
|
4286
|
+
deep_purple_A700: "#6200EA",
|
|
4287
|
+
// ── Indigo ───────────────────────────────────────────────────────────────
|
|
4288
|
+
indigo: "#3F51B5",
|
|
4289
|
+
// 500
|
|
4290
|
+
indigo_50: "#E8EAF6",
|
|
4291
|
+
indigo_100: "#C5CAE9",
|
|
4292
|
+
indigo_200: "#9FA8DA",
|
|
4293
|
+
indigo_300: "#7986CB",
|
|
4294
|
+
indigo_400: "#5C6BC0",
|
|
4295
|
+
indigo_500: "#3F51B5",
|
|
4296
|
+
indigo_600: "#3949AB",
|
|
4297
|
+
indigo_700: "#303F9F",
|
|
4298
|
+
indigo_800: "#283593",
|
|
4299
|
+
indigo_900: "#1A237E",
|
|
4300
|
+
indigo_A100: "#8C9EFF",
|
|
4301
|
+
indigo_A200: "#536DFE",
|
|
4302
|
+
indigo_A400: "#3D5AFE",
|
|
4303
|
+
indigo_A700: "#304FFE",
|
|
4304
|
+
// ── Blue ─────────────────────────────────────────────────────────────────
|
|
4305
|
+
blue: "#2196F3",
|
|
4306
|
+
// 500
|
|
4307
|
+
blue_50: "#E3F2FD",
|
|
4308
|
+
blue_100: "#BBDEFB",
|
|
4309
|
+
blue_200: "#90CAF9",
|
|
4310
|
+
blue_300: "#64B5F6",
|
|
4311
|
+
blue_400: "#42A5F5",
|
|
4312
|
+
blue_500: "#2196F3",
|
|
4313
|
+
blue_600: "#1E88E5",
|
|
4314
|
+
blue_700: "#1976D2",
|
|
4315
|
+
blue_800: "#1565C0",
|
|
4316
|
+
blue_900: "#0D47A1",
|
|
4317
|
+
blue_A100: "#82B1FF",
|
|
4318
|
+
blue_A200: "#448AFF",
|
|
4319
|
+
blue_A400: "#2979FF",
|
|
4320
|
+
blue_A700: "#2962FF",
|
|
4321
|
+
// ── Light Blue ───────────────────────────────────────────────────────────
|
|
4322
|
+
light_blue: "#03A9F4",
|
|
4323
|
+
// 500
|
|
4324
|
+
light_blue_50: "#E1F5FE",
|
|
4325
|
+
light_blue_100: "#B3E5FC",
|
|
4326
|
+
light_blue_200: "#81D4FA",
|
|
4327
|
+
light_blue_300: "#4FC3F7",
|
|
4328
|
+
light_blue_400: "#29B6F6",
|
|
4329
|
+
light_blue_500: "#03A9F4",
|
|
4330
|
+
light_blue_600: "#039BE5",
|
|
4331
|
+
light_blue_700: "#0288D1",
|
|
4332
|
+
light_blue_800: "#0277BD",
|
|
4333
|
+
light_blue_900: "#01579B",
|
|
4334
|
+
light_blue_A100: "#80D8FF",
|
|
4335
|
+
light_blue_A200: "#40C4FF",
|
|
4336
|
+
light_blue_A400: "#00B0FF",
|
|
4337
|
+
light_blue_A700: "#0091EA",
|
|
4338
|
+
// ── Cyan ─────────────────────────────────────────────────────────────────
|
|
4339
|
+
cyan: "#00BCD4",
|
|
4340
|
+
// 500
|
|
4341
|
+
cyan_50: "#E0F7FA",
|
|
4342
|
+
cyan_100: "#B2EBF2",
|
|
4343
|
+
cyan_200: "#80DEEA",
|
|
4344
|
+
cyan_300: "#4DD0E1",
|
|
4345
|
+
cyan_400: "#26C6DA",
|
|
4346
|
+
cyan_500: "#00BCD4",
|
|
4347
|
+
cyan_600: "#00ACC1",
|
|
4348
|
+
cyan_700: "#0097A7",
|
|
4349
|
+
cyan_800: "#00838F",
|
|
4350
|
+
cyan_900: "#006064",
|
|
4351
|
+
cyan_A100: "#84FFFF",
|
|
4352
|
+
cyan_A200: "#18FFFF",
|
|
4353
|
+
cyan_A400: "#00E5FF",
|
|
4354
|
+
cyan_A700: "#00B8D4",
|
|
4355
|
+
// ── Teal ─────────────────────────────────────────────────────────────────
|
|
4356
|
+
teal: "#009688",
|
|
4357
|
+
// 500
|
|
4358
|
+
teal_50: "#E0F2F1",
|
|
4359
|
+
teal_100: "#B2DFDB",
|
|
4360
|
+
teal_200: "#80CBC4",
|
|
4361
|
+
teal_300: "#4DB6AC",
|
|
4362
|
+
teal_400: "#26A69A",
|
|
4363
|
+
teal_500: "#009688",
|
|
4364
|
+
teal_600: "#00897B",
|
|
4365
|
+
teal_700: "#00796B",
|
|
4366
|
+
teal_800: "#00695C",
|
|
4367
|
+
teal_900: "#004D40",
|
|
4368
|
+
teal_A100: "#A7FFEB",
|
|
4369
|
+
teal_A200: "#64FFDA",
|
|
4370
|
+
teal_A400: "#1DE9B6",
|
|
4371
|
+
teal_A700: "#00BFA5",
|
|
4372
|
+
// ── Green ────────────────────────────────────────────────────────────────
|
|
4373
|
+
green: "#4CAF50",
|
|
4374
|
+
// 500
|
|
4375
|
+
green_50: "#E8F5E9",
|
|
4376
|
+
green_100: "#C8E6C9",
|
|
4377
|
+
green_200: "#A5D6A7",
|
|
4378
|
+
green_300: "#81C784",
|
|
4379
|
+
green_400: "#66BB6A",
|
|
4380
|
+
green_500: "#4CAF50",
|
|
4381
|
+
green_600: "#43A047",
|
|
4382
|
+
green_700: "#388E3C",
|
|
4383
|
+
green_800: "#2E7D32",
|
|
4384
|
+
green_900: "#1B5E20",
|
|
4385
|
+
green_A100: "#B9F6CA",
|
|
4386
|
+
green_A200: "#69F0AE",
|
|
4387
|
+
green_A400: "#00E676",
|
|
4388
|
+
green_A700: "#00C853",
|
|
4389
|
+
// ── Light Green ──────────────────────────────────────────────────────────
|
|
4390
|
+
light_green: "#8BC34A",
|
|
4391
|
+
// 500
|
|
4392
|
+
light_green_50: "#F1F8E9",
|
|
4393
|
+
light_green_100: "#DCEDC8",
|
|
4394
|
+
light_green_200: "#C5E1A5",
|
|
4395
|
+
light_green_300: "#AED581",
|
|
4396
|
+
light_green_400: "#9CCC65",
|
|
4397
|
+
light_green_500: "#8BC34A",
|
|
4398
|
+
light_green_600: "#7CB342",
|
|
4399
|
+
light_green_700: "#689F38",
|
|
4400
|
+
light_green_800: "#558B2F",
|
|
4401
|
+
light_green_900: "#33691E",
|
|
4402
|
+
light_green_A100: "#CCFF90",
|
|
4403
|
+
light_green_A200: "#B2FF59",
|
|
4404
|
+
light_green_A400: "#76FF03",
|
|
4405
|
+
light_green_A700: "#64DD17",
|
|
4406
|
+
// ── Lime ─────────────────────────────────────────────────────────────────
|
|
4407
|
+
lime: "#CDDC39",
|
|
4408
|
+
// 500
|
|
4409
|
+
lime_50: "#F9FBE7",
|
|
4410
|
+
lime_100: "#F0F4C3",
|
|
4411
|
+
lime_200: "#E6EE9C",
|
|
4412
|
+
lime_300: "#DCE775",
|
|
4413
|
+
lime_400: "#D4E157",
|
|
4414
|
+
lime_500: "#CDDC39",
|
|
4415
|
+
lime_600: "#C0CA33",
|
|
4416
|
+
lime_700: "#AFB42B",
|
|
4417
|
+
lime_800: "#9E9D24",
|
|
4418
|
+
lime_900: "#827717",
|
|
4419
|
+
lime_A100: "#F4FF81",
|
|
4420
|
+
lime_A200: "#EEFF41",
|
|
4421
|
+
lime_A400: "#C6FF00",
|
|
4422
|
+
lime_A700: "#AEEA00",
|
|
4423
|
+
// ── Yellow ───────────────────────────────────────────────────────────────
|
|
4424
|
+
yellow: "#FFEB3B",
|
|
4425
|
+
// 500
|
|
4426
|
+
yellow_50: "#FFFDE7",
|
|
4427
|
+
yellow_100: "#FFF9C4",
|
|
4428
|
+
yellow_200: "#FFF59D",
|
|
4429
|
+
yellow_300: "#FFF176",
|
|
4430
|
+
yellow_400: "#FFEE58",
|
|
4431
|
+
yellow_500: "#FFEB3B",
|
|
4432
|
+
yellow_600: "#FDD835",
|
|
4433
|
+
yellow_700: "#F9A825",
|
|
4434
|
+
yellow_800: "#F57F17",
|
|
4435
|
+
yellow_900: "#F57F17",
|
|
4436
|
+
yellow_A100: "#FFFF8D",
|
|
4437
|
+
yellow_A200: "#FFFF00",
|
|
4438
|
+
yellow_A400: "#FFEA00",
|
|
4439
|
+
yellow_A700: "#FFD600",
|
|
4440
|
+
// ── Amber ────────────────────────────────────────────────────────────────
|
|
4441
|
+
amber: "#FFC107",
|
|
4442
|
+
// 500
|
|
4443
|
+
amber_50: "#FFF8E1",
|
|
4444
|
+
amber_100: "#FFECB3",
|
|
4445
|
+
amber_200: "#FFE082",
|
|
4446
|
+
amber_300: "#FFD54F",
|
|
4447
|
+
amber_400: "#FFCA28",
|
|
4448
|
+
amber_500: "#FFC107",
|
|
4449
|
+
amber_600: "#FFB300",
|
|
4450
|
+
amber_700: "#FFA000",
|
|
4451
|
+
amber_800: "#FF8F00",
|
|
4452
|
+
amber_900: "#FF6F00",
|
|
4453
|
+
amber_A100: "#FFE57F",
|
|
4454
|
+
amber_A200: "#FFD740",
|
|
4455
|
+
amber_A400: "#FFC400",
|
|
4456
|
+
amber_A700: "#FFAB00",
|
|
4457
|
+
// ── Orange ───────────────────────────────────────────────────────────────
|
|
4458
|
+
orange: "#FF9800",
|
|
4459
|
+
// 500
|
|
4460
|
+
orange_50: "#FFF3E0",
|
|
4461
|
+
orange_100: "#FFE0B2",
|
|
4462
|
+
orange_200: "#FFCC80",
|
|
4463
|
+
orange_300: "#FFB74D",
|
|
4464
|
+
orange_400: "#FFA726",
|
|
4465
|
+
orange_500: "#FF9800",
|
|
4466
|
+
orange_600: "#FB8C00",
|
|
4467
|
+
orange_700: "#F57C00",
|
|
4468
|
+
orange_800: "#EF6C00",
|
|
4469
|
+
orange_900: "#E65100",
|
|
4470
|
+
orange_A100: "#FFD180",
|
|
4471
|
+
orange_A200: "#FFAB40",
|
|
4472
|
+
orange_A400: "#FF9100",
|
|
4473
|
+
orange_A700: "#FF6D00",
|
|
4474
|
+
// ── Deep Orange ──────────────────────────────────────────────────────────
|
|
4475
|
+
deep_orange: "#FF5722",
|
|
4476
|
+
// 500
|
|
4477
|
+
deep_orange_50: "#FBE9E7",
|
|
4478
|
+
deep_orange_100: "#FFCCBC",
|
|
4479
|
+
deep_orange_200: "#FFAB91",
|
|
4480
|
+
deep_orange_300: "#FF8A65",
|
|
4481
|
+
deep_orange_400: "#FF7043",
|
|
4482
|
+
deep_orange_500: "#FF5722",
|
|
4483
|
+
deep_orange_600: "#F4511E",
|
|
4484
|
+
deep_orange_700: "#E64A19",
|
|
4485
|
+
deep_orange_800: "#D84315",
|
|
4486
|
+
deep_orange_900: "#BF360C",
|
|
4487
|
+
deep_orange_A100: "#FF9E80",
|
|
4488
|
+
deep_orange_A200: "#FF6E40",
|
|
4489
|
+
deep_orange_A400: "#FF3D00",
|
|
4490
|
+
deep_orange_A700: "#DD2C00",
|
|
4491
|
+
// ── Brown ────────────────────────────────────────────────────────────────
|
|
4492
|
+
brown: "#795548",
|
|
4493
|
+
// 500
|
|
4494
|
+
brown_50: "#EFEBE9",
|
|
4495
|
+
brown_100: "#D7CCC8",
|
|
4496
|
+
brown_200: "#BCAAA4",
|
|
4497
|
+
brown_300: "#A1887F",
|
|
4498
|
+
brown_400: "#8D6E63",
|
|
4499
|
+
brown_500: "#795548",
|
|
4500
|
+
brown_600: "#6D4C41",
|
|
4501
|
+
brown_700: "#5D4037",
|
|
4502
|
+
brown_800: "#4E342E",
|
|
4503
|
+
brown_900: "#3E2723",
|
|
4504
|
+
// ── Grey ─────────────────────────────────────────────────────────────────
|
|
4505
|
+
grey_50: "#FAFAFA",
|
|
4506
|
+
grey_100: "#F5F5F5",
|
|
4507
|
+
grey_200: "#EEEEEE",
|
|
4508
|
+
grey_300: "#E0E0E0",
|
|
4509
|
+
grey_400: "#BDBDBD",
|
|
4510
|
+
grey_500: "#9E9E9E",
|
|
4511
|
+
grey_600: "#757575",
|
|
4512
|
+
grey_700: "#616161",
|
|
4513
|
+
grey_800: "#424242",
|
|
4514
|
+
grey_900: "#212121",
|
|
4515
|
+
// aliases
|
|
4516
|
+
gray_50: "#FAFAFA",
|
|
4517
|
+
gray_100: "#F5F5F5",
|
|
4518
|
+
gray_200: "#EEEEEE",
|
|
4519
|
+
gray_300: "#E0E0E0",
|
|
4520
|
+
gray_400: "#BDBDBD",
|
|
4521
|
+
gray_500: "#9E9E9E",
|
|
4522
|
+
gray_600: "#757575",
|
|
4523
|
+
gray_700: "#616161",
|
|
4524
|
+
gray_800: "#424242",
|
|
4525
|
+
gray_900: "#212121",
|
|
4526
|
+
// ── Blue Grey ────────────────────────────────────────────────────────────
|
|
4527
|
+
blue_grey: "#607D8B",
|
|
4528
|
+
// 500
|
|
4529
|
+
blue_grey_50: "#ECEFF1",
|
|
4530
|
+
blue_grey_100: "#CFD8DC",
|
|
4531
|
+
blue_grey_200: "#B0BEC5",
|
|
4532
|
+
blue_grey_300: "#90A4AE",
|
|
4533
|
+
blue_grey_400: "#78909C",
|
|
4534
|
+
blue_grey_500: "#607D8B",
|
|
4535
|
+
blue_grey_600: "#546E7A",
|
|
4536
|
+
blue_grey_700: "#455A64",
|
|
4537
|
+
blue_grey_800: "#37474F",
|
|
4538
|
+
blue_grey_900: "#263238",
|
|
4539
|
+
// aliases
|
|
4540
|
+
blue_gray: "#607D8B",
|
|
4541
|
+
blue_gray_50: "#ECEFF1",
|
|
4542
|
+
blue_gray_100: "#CFD8DC",
|
|
4543
|
+
blue_gray_200: "#B0BEC5",
|
|
4544
|
+
blue_gray_300: "#90A4AE",
|
|
4545
|
+
blue_gray_400: "#78909C",
|
|
4546
|
+
blue_gray_500: "#607D8B",
|
|
4547
|
+
blue_gray_600: "#546E7A",
|
|
4548
|
+
blue_gray_700: "#455A64",
|
|
4549
|
+
blue_gray_800: "#37474F",
|
|
4550
|
+
blue_gray_900: "#263238"
|
|
4201
4551
|
};
|
|
4202
4552
|
}
|
|
4203
4553
|
/**
|
|
@@ -4845,7 +5195,8 @@ var SVGRenderer = class {
|
|
|
4845
5195
|
if (node.containerType === "split") {
|
|
4846
5196
|
this.renderSplitDecoration(node, pos, containerGroup);
|
|
4847
5197
|
}
|
|
4848
|
-
|
|
5198
|
+
const isCellContainer = node.meta?.source === "cell";
|
|
5199
|
+
if (node.children.length === 0 && this.options.showDiagnostics && !isCellContainer) {
|
|
4849
5200
|
containerGroup.push(this.renderEmptyContainerDiagnostic(pos, node.containerType));
|
|
4850
5201
|
} else {
|
|
4851
5202
|
node.children.forEach((childRef) => {
|
|
@@ -4892,7 +5243,6 @@ var SVGRenderer = class {
|
|
|
4892
5243
|
case "Table":
|
|
4893
5244
|
return this.renderTable(node, pos);
|
|
4894
5245
|
case "Chart":
|
|
4895
|
-
case "ChartPlaceholder":
|
|
4896
5246
|
return this.renderChartPlaceholder(node, pos);
|
|
4897
5247
|
case "Breadcrumbs":
|
|
4898
5248
|
return this.renderBreadcrumbs(node, pos);
|
|
@@ -4901,6 +5251,8 @@ var SVGRenderer = class {
|
|
|
4901
5251
|
// Text/Content components
|
|
4902
5252
|
case "Text":
|
|
4903
5253
|
return this.renderText(node, pos);
|
|
5254
|
+
case "Paragraph":
|
|
5255
|
+
return this.renderParagraph(node, pos);
|
|
4904
5256
|
case "Label":
|
|
4905
5257
|
return this.renderLabel(node, pos);
|
|
4906
5258
|
case "Code":
|
|
@@ -4980,7 +5332,7 @@ var SVGRenderer = class {
|
|
|
4980
5332
|
renderButton(node, pos) {
|
|
4981
5333
|
const text = String(node.props.text || "Button");
|
|
4982
5334
|
const variant = String(node.props.variant || "default");
|
|
4983
|
-
const size = String(node.props.size || "
|
|
5335
|
+
const size = String(node.props.size || "sm");
|
|
4984
5336
|
const disabled = this.parseBooleanProp(node.props.disabled, false);
|
|
4985
5337
|
const density = this.ir.project.style.density || "normal";
|
|
4986
5338
|
const extraPadding = resolveControlHorizontalPadding(String(node.props.padding || "none"), density);
|
|
@@ -5055,7 +5407,7 @@ var SVGRenderer = class {
|
|
|
5055
5407
|
renderLink(node, pos) {
|
|
5056
5408
|
const text = String(node.props.text || "Link");
|
|
5057
5409
|
const variant = String(node.props.variant || "primary");
|
|
5058
|
-
const size = String(node.props.size || "
|
|
5410
|
+
const size = String(node.props.size || "sm");
|
|
5059
5411
|
const density = this.ir.project.style.density || "normal";
|
|
5060
5412
|
const fontSize = this.tokens.button.fontSize;
|
|
5061
5413
|
const fontWeight = this.tokens.button.fontWeight;
|
|
@@ -5161,7 +5513,33 @@ var SVGRenderer = class {
|
|
|
5161
5513
|
const variant = String(node.props.variant || "default");
|
|
5162
5514
|
const accentColor = variant === "default" ? this.resolveAccentColor() : this.resolveVariantColor(variant, this.resolveAccentColor());
|
|
5163
5515
|
const showBorder = this.parseBooleanProp(node.props.border, false);
|
|
5164
|
-
const
|
|
5516
|
+
const bgPropStr = String(node.props.background ?? "");
|
|
5517
|
+
let resolvedBg = null;
|
|
5518
|
+
if (bgPropStr === "true") {
|
|
5519
|
+
resolvedBg = this.renderTheme.cardBg;
|
|
5520
|
+
} else if (bgPropStr && bgPropStr !== "false") {
|
|
5521
|
+
if (bgPropStr.startsWith("#") || bgPropStr.startsWith("rgb")) {
|
|
5522
|
+
resolvedBg = bgPropStr;
|
|
5523
|
+
} else if (this.colorResolver.hasColor(bgPropStr)) {
|
|
5524
|
+
resolvedBg = this.colorResolver.resolveColor(bgPropStr, this.renderTheme.cardBg);
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
const showBackground = resolvedBg !== null;
|
|
5528
|
+
const colorPropStr = String(node.props.color ?? "");
|
|
5529
|
+
let titleColor = this.renderTheme.text;
|
|
5530
|
+
let subtitleColor = this.renderTheme.textMuted;
|
|
5531
|
+
if (colorPropStr && colorPropStr !== "false") {
|
|
5532
|
+
let resolvedTitleColor = null;
|
|
5533
|
+
if (colorPropStr.startsWith("#") || colorPropStr.startsWith("rgb")) {
|
|
5534
|
+
resolvedTitleColor = colorPropStr;
|
|
5535
|
+
} else if (this.colorResolver.hasColor(colorPropStr)) {
|
|
5536
|
+
resolvedTitleColor = this.colorResolver.resolveColor(colorPropStr, this.renderTheme.text);
|
|
5537
|
+
}
|
|
5538
|
+
if (resolvedTitleColor) {
|
|
5539
|
+
titleColor = resolvedTitleColor;
|
|
5540
|
+
subtitleColor = this.hexToRgba(resolvedTitleColor, 0.65);
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5165
5543
|
const radiusMap = {
|
|
5166
5544
|
none: 0,
|
|
5167
5545
|
sm: 4,
|
|
@@ -5173,7 +5551,7 @@ var SVGRenderer = class {
|
|
|
5173
5551
|
const topbar = this.calculateTopbarLayout(node, pos, title, subtitle, actions, user);
|
|
5174
5552
|
let svg = `<g${this.getDataNodeId(node)}>`;
|
|
5175
5553
|
if (showBorder || showBackground) {
|
|
5176
|
-
const bg =
|
|
5554
|
+
const bg = resolvedBg ?? "none";
|
|
5177
5555
|
const stroke = showBorder ? this.renderTheme.border : "none";
|
|
5178
5556
|
svg += `
|
|
5179
5557
|
<rect x="${pos.x}" y="${pos.y}"
|
|
@@ -5189,13 +5567,13 @@ var SVGRenderer = class {
|
|
|
5189
5567
|
font-family="Arial, Helvetica, sans-serif"
|
|
5190
5568
|
font-size="18"
|
|
5191
5569
|
font-weight="600"
|
|
5192
|
-
fill="${
|
|
5570
|
+
fill="${titleColor}">${this.escapeXml(topbar.visibleTitle)}</text>`;
|
|
5193
5571
|
if (topbar.hasSubtitle) {
|
|
5194
5572
|
svg += `
|
|
5195
5573
|
<text x="${topbar.textX}" y="${topbar.subtitleY}"
|
|
5196
5574
|
font-family="Arial, Helvetica, sans-serif"
|
|
5197
5575
|
font-size="13"
|
|
5198
|
-
fill="${
|
|
5576
|
+
fill="${subtitleColor}">${this.escapeXml(topbar.visibleSubtitle)}</text>`;
|
|
5199
5577
|
}
|
|
5200
5578
|
if (topbar.leftIcon) {
|
|
5201
5579
|
svg += `
|
|
@@ -5676,8 +6054,13 @@ var SVGRenderer = class {
|
|
|
5676
6054
|
// ============================================================================
|
|
5677
6055
|
renderText(node, pos) {
|
|
5678
6056
|
const text = String(node.props.text || "Text content");
|
|
5679
|
-
const
|
|
6057
|
+
const sizeProp = String(node.props.size || "");
|
|
6058
|
+
const defaultFontSize = this.tokens.text.fontSize;
|
|
6059
|
+
const textFontSizeMap = { xs: 10, sm: 12, lg: 16, xl: 20 };
|
|
6060
|
+
const fontSize = textFontSizeMap[sizeProp] ?? defaultFontSize;
|
|
5680
6061
|
const lineHeightPx = Math.ceil(fontSize * this.tokens.text.lineHeight);
|
|
6062
|
+
const bold = this.parseBooleanProp(node.props.bold, false);
|
|
6063
|
+
const italic = this.parseBooleanProp(node.props.italic, false);
|
|
5681
6064
|
const lines = this.wrapTextToLines(text, pos.width, fontSize);
|
|
5682
6065
|
const totalTextHeight = lines.length * lineHeightPx;
|
|
5683
6066
|
const firstLineY = pos.y + Math.round(Math.max(0, (pos.height - totalTextHeight) / 2)) + fontSize;
|
|
@@ -5688,9 +6071,49 @@ var SVGRenderer = class {
|
|
|
5688
6071
|
<text x="${pos.x}" y="${firstLineY}"
|
|
5689
6072
|
font-family="Arial, Helvetica, sans-serif"
|
|
5690
6073
|
font-size="${fontSize}"
|
|
6074
|
+
font-weight="${bold ? "700" : "400"}"
|
|
6075
|
+
font-style="${italic ? "italic" : "normal"}"
|
|
5691
6076
|
fill="${this.renderTheme.text}">${tspans}</text>
|
|
5692
6077
|
</g>`;
|
|
5693
6078
|
}
|
|
6079
|
+
renderParagraph(node, pos) {
|
|
6080
|
+
const text = String(node.props.text || "");
|
|
6081
|
+
const sizeProp = String(node.props.size || "");
|
|
6082
|
+
const defaultFontSize = this.tokens.text.fontSize;
|
|
6083
|
+
const textFontSizeMap = { xs: 10, sm: 12, lg: 16, xl: 20 };
|
|
6084
|
+
const fontSize = textFontSizeMap[sizeProp] ?? defaultFontSize;
|
|
6085
|
+
const lineHeightPx = Math.ceil(fontSize * this.tokens.text.lineHeight);
|
|
6086
|
+
const bold = this.parseBooleanProp(node.props.bold, false);
|
|
6087
|
+
const italic = this.parseBooleanProp(node.props.italic, false);
|
|
6088
|
+
const align = String(node.props.align || "left");
|
|
6089
|
+
const lines = this.wrapTextToLines(text, pos.width, fontSize);
|
|
6090
|
+
const totalTextHeight = lines.length * lineHeightPx;
|
|
6091
|
+
const firstLineY = pos.y + Math.round(Math.max(0, (pos.height - totalTextHeight) / 2)) + fontSize;
|
|
6092
|
+
let textX;
|
|
6093
|
+
let textAnchor;
|
|
6094
|
+
if (align === "center") {
|
|
6095
|
+
textX = pos.x + pos.width / 2;
|
|
6096
|
+
textAnchor = "middle";
|
|
6097
|
+
} else if (align === "right") {
|
|
6098
|
+
textX = pos.x + pos.width;
|
|
6099
|
+
textAnchor = "end";
|
|
6100
|
+
} else {
|
|
6101
|
+
textX = pos.x;
|
|
6102
|
+
textAnchor = "start";
|
|
6103
|
+
}
|
|
6104
|
+
const tspans = lines.map(
|
|
6105
|
+
(line, index) => `<tspan x="${textX}" dy="${index === 0 ? 0 : lineHeightPx}">${this.escapeXml(line)}</tspan>`
|
|
6106
|
+
).join("");
|
|
6107
|
+
return `<g${this.getDataNodeId(node)}>
|
|
6108
|
+
<text x="${textX}" y="${firstLineY}"
|
|
6109
|
+
font-family="Arial, Helvetica, sans-serif"
|
|
6110
|
+
font-size="${fontSize}"
|
|
6111
|
+
font-weight="${bold ? "700" : "400"}"
|
|
6112
|
+
font-style="${italic ? "italic" : "normal"}"
|
|
6113
|
+
fill="${this.renderTheme.text}"
|
|
6114
|
+
text-anchor="${textAnchor}">${tspans}</text>
|
|
6115
|
+
</g>`;
|
|
6116
|
+
}
|
|
5694
6117
|
renderLabel(node, pos) {
|
|
5695
6118
|
const text = String(node.props.text || "Label");
|
|
5696
6119
|
const textY = pos.y + Math.round(pos.height / 2) + 4;
|
|
@@ -5933,34 +6356,145 @@ var SVGRenderer = class {
|
|
|
5933
6356
|
const tabs = itemsStr ? itemsStr.split(",").map((t) => t.trim()) : ["Tab 1", "Tab 2", "Tab 3"];
|
|
5934
6357
|
const activeProp = node.props.active ?? 0;
|
|
5935
6358
|
const activeIndex = Number.isFinite(Number(activeProp)) ? Math.max(0, Math.floor(Number(activeProp))) : 0;
|
|
5936
|
-
const
|
|
6359
|
+
const variant = String(node.props.variant || "default");
|
|
6360
|
+
const accentColor = variant === "default" ? this.resolveAccentColor() : this.resolveVariantColor(variant, this.resolveAccentColor());
|
|
6361
|
+
const radiusMap = { none: 0, sm: 4, md: 6, lg: 10, full: 20 };
|
|
6362
|
+
const tabRadius = radiusMap[String(node.props.radius || "md")] ?? 6;
|
|
6363
|
+
const sizeMap = { sm: 32, md: 44, lg: 52 };
|
|
6364
|
+
const tabHeight = pos.height > 0 ? pos.height : sizeMap[String(node.props.size || "md")] ?? 44;
|
|
6365
|
+
const fontSize = 13;
|
|
6366
|
+
const textY = pos.y + Math.round(tabHeight / 2) + Math.round(fontSize * 0.4);
|
|
6367
|
+
const iconsStr = String(node.props.icons || "");
|
|
6368
|
+
const iconList = iconsStr ? iconsStr.split(",").map((s) => s.trim()) : [];
|
|
6369
|
+
const isFlat = this.parseBooleanProp(node.props.flat, false);
|
|
6370
|
+
const showBorder = this.parseBooleanProp(node.props.border, true);
|
|
5937
6371
|
const tabWidth = pos.width / tabs.length;
|
|
5938
|
-
|
|
5939
|
-
|
|
6372
|
+
const colorPropStr = String(node.props.color ?? "");
|
|
6373
|
+
let textColorOverride = null;
|
|
6374
|
+
if (colorPropStr && colorPropStr !== "false") {
|
|
6375
|
+
if (colorPropStr.startsWith("#") || colorPropStr.startsWith("rgb")) {
|
|
6376
|
+
textColorOverride = colorPropStr;
|
|
6377
|
+
} else if (this.colorResolver.hasColor(colorPropStr)) {
|
|
6378
|
+
textColorOverride = this.colorResolver.resolveColor(colorPropStr, this.renderTheme.text);
|
|
6379
|
+
}
|
|
6380
|
+
}
|
|
6381
|
+
const activeTextColor = textColorOverride ?? (isFlat ? accentColor : "white");
|
|
6382
|
+
const inactiveTextColor = textColorOverride ? this.hexToRgba(textColorOverride, 0.55) : this.renderTheme.textMuted;
|
|
6383
|
+
const hasRadius = tabRadius > 0;
|
|
6384
|
+
const clipId = hasRadius ? `tc${String(node.meta?.nodeId ?? "").replace(/\W/g, "").slice(0, 12) || `${Math.round(Math.abs(pos.x))}x${Math.round(Math.abs(pos.y))}`}` : "";
|
|
6385
|
+
let svg = "";
|
|
6386
|
+
if (hasRadius) {
|
|
6387
|
+
svg += `<defs><clipPath id="${clipId}"><rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" rx="${tabRadius}"/></clipPath></defs>`;
|
|
6388
|
+
}
|
|
6389
|
+
svg += `<g${this.getDataNodeId(node)}>`;
|
|
6390
|
+
if (hasRadius) {
|
|
6391
|
+
svg += `<g clip-path="url(#${clipId})">`;
|
|
6392
|
+
}
|
|
6393
|
+
if (!isFlat) {
|
|
6394
|
+
svg += `
|
|
6395
|
+
<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${tabHeight}"
|
|
6396
|
+
fill="${this.renderTheme.bg}"/>`;
|
|
6397
|
+
}
|
|
5940
6398
|
tabs.forEach((tab, i) => {
|
|
5941
6399
|
const tabX = pos.x + i * tabWidth;
|
|
5942
6400
|
const isActive = i === activeIndex;
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
6401
|
+
const iconName = iconList[i] || "";
|
|
6402
|
+
const tabIconSvg = iconName ? getIcon(iconName) : null;
|
|
6403
|
+
const iconSize = 14;
|
|
6404
|
+
const iconGap = 4;
|
|
6405
|
+
const charW = fontSize * 0.58;
|
|
6406
|
+
const textEst = tab.length * charW;
|
|
6407
|
+
const totalW = tabIconSvg ? iconSize + iconGap + textEst : textEst;
|
|
6408
|
+
const groupX = tabX + Math.round((tabWidth - totalW) / 2);
|
|
6409
|
+
const iconOffY = pos.y + Math.round((tabHeight - iconSize) / 2);
|
|
6410
|
+
if (isFlat) {
|
|
6411
|
+
if (isActive) {
|
|
6412
|
+
svg += `
|
|
6413
|
+
<rect x="${tabX + 6}" y="${pos.y + tabHeight - 3}"
|
|
6414
|
+
width="${tabWidth - 12}" height="3"
|
|
6415
|
+
rx="1.5"
|
|
6416
|
+
fill="${accentColor}"/>`;
|
|
6417
|
+
}
|
|
6418
|
+
if (tabIconSvg) {
|
|
6419
|
+
svg += `
|
|
6420
|
+
<g transform="translate(${groupX}, ${iconOffY})">
|
|
6421
|
+
<svg width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none"
|
|
6422
|
+
stroke="${isActive ? accentColor : this.renderTheme.textMuted}"
|
|
6423
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
6424
|
+
${this.extractSvgContent(tabIconSvg)}
|
|
6425
|
+
</svg>
|
|
6426
|
+
</g>
|
|
6427
|
+
<text x="${groupX + iconSize + iconGap}" y="${textY}"
|
|
6428
|
+
font-family="Arial, Helvetica, sans-serif"
|
|
6429
|
+
font-size="${fontSize}"
|
|
6430
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
6431
|
+
fill="${isActive ? activeTextColor : inactiveTextColor}">${this.escapeXml(tab)}</text>`;
|
|
6432
|
+
} else {
|
|
6433
|
+
svg += `
|
|
6434
|
+
<text x="${tabX + tabWidth / 2}" y="${textY}"
|
|
6435
|
+
font-family="Arial, Helvetica, sans-serif"
|
|
6436
|
+
font-size="${fontSize}"
|
|
6437
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
6438
|
+
fill="${isActive ? activeTextColor : inactiveTextColor}"
|
|
6439
|
+
text-anchor="middle">${this.escapeXml(tab)}</text>`;
|
|
6440
|
+
}
|
|
6441
|
+
} else {
|
|
6442
|
+
svg += `
|
|
6443
|
+
<rect x="${tabX}" y="${pos.y}"
|
|
6444
|
+
width="${tabWidth}" height="${tabHeight}"
|
|
6445
|
+
rx="${!showBorder && hasRadius && isActive ? tabRadius : 0}"
|
|
6446
|
+
fill="${isActive ? accentColor : "transparent"}"
|
|
6447
|
+
${!isActive && showBorder ? `stroke="${this.renderTheme.border}" stroke-width="0.5"` : ""}/>`;
|
|
6448
|
+
if (tabIconSvg) {
|
|
6449
|
+
svg += `
|
|
6450
|
+
<g transform="translate(${groupX}, ${iconOffY})">
|
|
6451
|
+
<svg width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none"
|
|
6452
|
+
stroke="${isActive ? activeTextColor : this.renderTheme.textMuted}"
|
|
6453
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
6454
|
+
${this.extractSvgContent(tabIconSvg)}
|
|
6455
|
+
</svg>
|
|
6456
|
+
</g>
|
|
6457
|
+
<text x="${groupX + iconSize + iconGap}" y="${textY}"
|
|
6458
|
+
font-family="Arial, Helvetica, sans-serif"
|
|
6459
|
+
font-size="${fontSize}"
|
|
6460
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
6461
|
+
fill="${isActive ? activeTextColor : this.renderTheme.text}">${this.escapeXml(tab)}</text>`;
|
|
6462
|
+
} else {
|
|
6463
|
+
svg += `
|
|
6464
|
+
<text x="${tabX + tabWidth / 2}" y="${textY}"
|
|
6465
|
+
font-family="Arial, Helvetica, sans-serif"
|
|
6466
|
+
font-size="${fontSize}"
|
|
6467
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
6468
|
+
fill="${isActive ? activeTextColor : this.renderTheme.text}"
|
|
5954
6469
|
text-anchor="middle">${this.escapeXml(tab)}</text>`;
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
5955
6472
|
});
|
|
5956
|
-
|
|
6473
|
+
const contentY = pos.y + tabHeight;
|
|
6474
|
+
const contentH = pos.height - tabHeight;
|
|
6475
|
+
if (contentH >= 20 && !isFlat) {
|
|
6476
|
+
svg += `
|
|
5957
6477
|
<!-- Tab content area -->
|
|
5958
|
-
<rect x="${pos.x}" y="${
|
|
5959
|
-
width="${pos.width}" height="${
|
|
5960
|
-
fill="${this.renderTheme.cardBg}"
|
|
5961
|
-
stroke="${this.renderTheme.border}"
|
|
5962
|
-
|
|
6478
|
+
<rect x="${pos.x}" y="${contentY}"
|
|
6479
|
+
width="${pos.width}" height="${contentH}"
|
|
6480
|
+
fill="${this.renderTheme.cardBg}"
|
|
6481
|
+
${showBorder ? `stroke="${this.renderTheme.border}" stroke-width="1"` : ""}/>`;
|
|
6482
|
+
} else if (isFlat && showBorder) {
|
|
6483
|
+
svg += `
|
|
6484
|
+
<line x1="${pos.x}" y1="${contentY}" x2="${pos.x + pos.width}" y2="${contentY}"
|
|
6485
|
+
stroke="${this.renderTheme.border}" stroke-width="1"/>`;
|
|
6486
|
+
}
|
|
6487
|
+
if (hasRadius) {
|
|
6488
|
+
svg += `
|
|
5963
6489
|
</g>`;
|
|
6490
|
+
if (!isFlat && showBorder) {
|
|
6491
|
+
svg += `
|
|
6492
|
+
<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}"
|
|
6493
|
+
rx="${tabRadius}" fill="none"
|
|
6494
|
+
stroke="${this.renderTheme.border}" stroke-width="1"/>`;
|
|
6495
|
+
}
|
|
6496
|
+
}
|
|
6497
|
+
svg += "\n </g>";
|
|
5964
6498
|
return svg;
|
|
5965
6499
|
}
|
|
5966
6500
|
renderDivider(node, pos) {
|
|
@@ -6027,15 +6561,20 @@ var SVGRenderer = class {
|
|
|
6027
6561
|
const hasExplicitVariantColor = semanticBase !== void 0 || this.colorResolver.hasColor(variant);
|
|
6028
6562
|
const bgColor = hasExplicitVariantColor ? this.resolveVariantColor(variant, this.renderTheme.primary) : this.renderTheme.border;
|
|
6029
6563
|
const textColor = hasExplicitVariantColor ? "white" : this.renderTheme.text;
|
|
6564
|
+
const size = String(node.props.size || "md");
|
|
6565
|
+
const BADGE_FONT_SIZES = { xs: 9, sm: 11, md: 12, lg: 13, xl: 15 };
|
|
6566
|
+
const fontSize = BADGE_FONT_SIZES[size] ?? this.tokens.badge.fontSize;
|
|
6567
|
+
const customPadding = node.props.padding !== void 0 ? Number(node.props.padding) : void 0;
|
|
6568
|
+
const BADGE_PAD_X = { xs: 5, sm: 6, md: 8, lg: 10, xl: 14 };
|
|
6569
|
+
const paddingX = customPadding !== void 0 && !isNaN(customPadding) ? customPadding : BADGE_PAD_X[size] ?? this.tokens.badge.paddingX;
|
|
6030
6570
|
const badgeRadius = this.tokens.badge.radius === "pill" ? pos.height / 2 : this.tokens.badge.radius;
|
|
6031
|
-
const fontSize = this.tokens.badge.fontSize;
|
|
6032
6571
|
return `<g${this.getDataNodeId(node)}>
|
|
6033
6572
|
<rect x="${pos.x}" y="${pos.y}"
|
|
6034
6573
|
width="${pos.width}" height="${pos.height}"
|
|
6035
6574
|
rx="${badgeRadius}"
|
|
6036
6575
|
fill="${bgColor}"
|
|
6037
6576
|
stroke="none"/>
|
|
6038
|
-
<text x="${pos.x + pos.width / 2}" y="${pos.y + pos.height / 2 +
|
|
6577
|
+
<text x="${pos.x + paddingX + (pos.width - paddingX * 2) / 2}" y="${pos.y + pos.height / 2 + fontSize * 0.35}"
|
|
6039
6578
|
font-family="Arial, Helvetica, sans-serif"
|
|
6040
6579
|
font-size="${fontSize}"
|
|
6041
6580
|
font-weight="600"
|
|
@@ -6244,11 +6783,20 @@ var SVGRenderer = class {
|
|
|
6244
6783
|
return svg;
|
|
6245
6784
|
}
|
|
6246
6785
|
renderImage(node, pos) {
|
|
6247
|
-
const placeholder = String(node.props.
|
|
6786
|
+
const placeholder = String(node.props.type || "landscape").toLowerCase();
|
|
6248
6787
|
const placeholderIcon = String(node.props.icon || "").trim();
|
|
6249
6788
|
const variant = String(node.props.variant || "").trim();
|
|
6250
6789
|
const placeholderIconSvg = placeholder === "icon" && placeholderIcon ? getIcon(placeholderIcon) : null;
|
|
6251
6790
|
const imageBg = this.options.theme === "dark" ? "#2A2A2A" : "#E8E8E8";
|
|
6791
|
+
const hasExplicitHeight = node.props.height !== void 0 && !isNaN(Number(node.props.height)) && Number(node.props.height) > 0;
|
|
6792
|
+
const isCircle = this.parseBooleanProp(node.props.circle, false);
|
|
6793
|
+
const useClip = isCircle || hasExplicitHeight;
|
|
6794
|
+
const clipId = useClip ? `iclip${String(node.meta?.nodeId ?? "").replace(/\W/g, "").slice(0, 16) || `${Math.round(Math.abs(pos.x))}x${Math.round(Math.abs(pos.y))}`}` : "";
|
|
6795
|
+
const imgCx = pos.x + pos.width / 2;
|
|
6796
|
+
const imgCy = pos.y + pos.height / 2;
|
|
6797
|
+
const imgR = Math.min(pos.width, pos.height) / 2;
|
|
6798
|
+
const defsHtml = useClip ? `<defs><clipPath id="${clipId}">${isCircle ? `<circle cx="${imgCx}" cy="${imgCy}" r="${imgR}"/>` : `<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" rx="4"/>`}</clipPath></defs>` : "";
|
|
6799
|
+
const clipAttr = useClip ? ` clip-path="url(#${clipId})"` : "";
|
|
6252
6800
|
const aspectRatios = {
|
|
6253
6801
|
landscape: 16 / 9,
|
|
6254
6802
|
portrait: 2 / 3,
|
|
@@ -6257,12 +6805,24 @@ var SVGRenderer = class {
|
|
|
6257
6805
|
avatar: 1
|
|
6258
6806
|
};
|
|
6259
6807
|
const ratio = aspectRatios[placeholder] || 16 / 9;
|
|
6260
|
-
|
|
6261
|
-
let
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6808
|
+
let iconWidth;
|
|
6809
|
+
let iconHeight;
|
|
6810
|
+
if (isCircle) {
|
|
6811
|
+
const diameter = 2 * imgR;
|
|
6812
|
+
iconWidth = diameter;
|
|
6813
|
+
iconHeight = diameter / ratio;
|
|
6814
|
+
if (iconHeight < diameter) {
|
|
6815
|
+
iconHeight = diameter;
|
|
6816
|
+
iconWidth = diameter * ratio;
|
|
6817
|
+
}
|
|
6818
|
+
} else {
|
|
6819
|
+
const maxSize = Math.min(pos.width, pos.height) * 0.8;
|
|
6820
|
+
iconWidth = maxSize;
|
|
6821
|
+
iconHeight = maxSize / ratio;
|
|
6822
|
+
if (iconHeight > pos.height * 0.8) {
|
|
6823
|
+
iconHeight = pos.height * 0.8;
|
|
6824
|
+
iconWidth = iconHeight * ratio;
|
|
6825
|
+
}
|
|
6266
6826
|
}
|
|
6267
6827
|
const offsetX = pos.x + (pos.width - iconWidth) / 2;
|
|
6268
6828
|
const offsetY = pos.y + (pos.height - iconHeight) / 2;
|
|
@@ -6275,17 +6835,18 @@ var SVGRenderer = class {
|
|
|
6275
6835
|
const iconSize = Math.max(16, Math.min(pos.width, pos.height) * 0.6);
|
|
6276
6836
|
const iconOffsetX = pos.x + (pos.width - iconSize) / 2;
|
|
6277
6837
|
const iconOffsetY = pos.y + (pos.height - iconSize) / 2;
|
|
6278
|
-
|
|
6838
|
+
const iconBorderShape = isCircle ? `<circle cx="${imgCx}" cy="${imgCy}" r="${imgR}" fill="none" stroke="${this.renderTheme.border}" stroke-width="1"/>` : `<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" fill="none" stroke="${this.renderTheme.border}" stroke-width="1" rx="4"/>`;
|
|
6839
|
+
return `${defsHtml}<g${this.getDataNodeId(node)}${clipAttr}>
|
|
6279
6840
|
<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" fill="${bgColor}" rx="4"/>
|
|
6280
6841
|
<g transform="translate(${iconOffsetX}, ${iconOffsetY})">
|
|
6281
6842
|
<svg width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
6282
6843
|
${this.extractSvgContent(placeholderIconSvg)}
|
|
6283
6844
|
</svg>
|
|
6284
6845
|
</g>
|
|
6285
|
-
|
|
6846
|
+
${iconBorderShape}
|
|
6286
6847
|
</g>`;
|
|
6287
6848
|
}
|
|
6288
|
-
let svg =
|
|
6849
|
+
let svg = `${defsHtml}<g${this.getDataNodeId(node)}${clipAttr}>
|
|
6289
6850
|
<!-- Image Background -->
|
|
6290
6851
|
<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" fill="${imageBg}"/>`;
|
|
6291
6852
|
if (["landscape", "portrait", "square"].includes(placeholder)) {
|
|
@@ -6343,10 +6904,10 @@ var SVGRenderer = class {
|
|
|
6343
6904
|
width="${personWidth * 0.6}" height="${personHeight * 0.5}"
|
|
6344
6905
|
fill="#666" rx="3"/>`;
|
|
6345
6906
|
}
|
|
6907
|
+
const borderShape = isCircle ? `<circle cx="${imgCx}" cy="${imgCy}" r="${imgR}" fill="none" stroke="${this.renderTheme.border}" stroke-width="1"/>` : `<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" fill="none" stroke="${this.renderTheme.border}" stroke-width="1" rx="4"/>`;
|
|
6346
6908
|
svg += `
|
|
6347
6909
|
<!-- Border -->
|
|
6348
|
-
|
|
6349
|
-
fill="none" stroke="${this.renderTheme.border}" stroke-width="1" rx="4"/>
|
|
6910
|
+
${borderShape}
|
|
6350
6911
|
</g>`;
|
|
6351
6912
|
return svg;
|
|
6352
6913
|
}
|
|
@@ -6450,10 +7011,29 @@ var SVGRenderer = class {
|
|
|
6450
7011
|
</g>`;
|
|
6451
7012
|
}
|
|
6452
7013
|
const iconSize = this.getIconSize(size);
|
|
6453
|
-
const
|
|
6454
|
-
const
|
|
7014
|
+
const paddingPx = Math.max(0, Number(node.props.padding || 0));
|
|
7015
|
+
const renderedIconSize = Math.max(4, iconSize - paddingPx * 2);
|
|
7016
|
+
const offsetX = pos.x + (pos.width - renderedIconSize) / 2;
|
|
7017
|
+
const offsetY = pos.y + (pos.height - renderedIconSize) / 2;
|
|
7018
|
+
const isIconCircle = this.parseBooleanProp(node.props.circle, false);
|
|
7019
|
+
if (isIconCircle) {
|
|
7020
|
+
const cx = pos.x + pos.width / 2;
|
|
7021
|
+
const cy = pos.y + pos.height / 2;
|
|
7022
|
+
const r = Math.min(pos.width, pos.height) / 2;
|
|
7023
|
+
const iconClipId = `iconclip${String(node.meta?.nodeId ?? "").replace(/\W/g, "").slice(0, 16) || `${Math.round(Math.abs(pos.x))}x${Math.round(Math.abs(pos.y))}`}`;
|
|
7024
|
+
const bgColor = this.hexToRgba(iconColor, 0.12);
|
|
7025
|
+
return `<defs><clipPath id="${iconClipId}"><circle cx="${cx}" cy="${cy}" r="${r}"/></clipPath></defs><g${this.getDataNodeId(node)} clip-path="url(#${iconClipId})">
|
|
7026
|
+
<circle cx="${cx}" cy="${cy}" r="${r}" fill="${bgColor}"/>
|
|
7027
|
+
<g transform="translate(${offsetX}, ${offsetY})">
|
|
7028
|
+
<svg width="${renderedIconSize}" height="${renderedIconSize}" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
7029
|
+
${this.extractSvgContent(iconSvg)}
|
|
7030
|
+
</svg>
|
|
7031
|
+
</g>
|
|
7032
|
+
</g>
|
|
7033
|
+
<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${this.hexToRgba(iconColor, 0.35)}" stroke-width="1"/>`;
|
|
7034
|
+
}
|
|
6455
7035
|
const wrappedSvg = `<g${this.getDataNodeId(node)} transform="translate(${offsetX}, ${offsetY})">
|
|
6456
|
-
<svg width="${
|
|
7036
|
+
<svg width="${renderedIconSize}" height="${renderedIconSize}" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
6457
7037
|
${this.extractSvgContent(iconSvg)}
|
|
6458
7038
|
</svg>
|
|
6459
7039
|
</g>`;
|
|
@@ -6462,7 +7042,7 @@ var SVGRenderer = class {
|
|
|
6462
7042
|
renderIconButton(node, pos) {
|
|
6463
7043
|
const iconName = String(node.props.icon || "help-circle");
|
|
6464
7044
|
const variant = String(node.props.variant || "default");
|
|
6465
|
-
const size = String(node.props.size || "
|
|
7045
|
+
const size = String(node.props.size || "sm");
|
|
6466
7046
|
const disabled = String(node.props.disabled || "false") === "true";
|
|
6467
7047
|
const density = this.ir.project.style.density || "normal";
|
|
6468
7048
|
const labelOffset = this.parseBooleanProp(node.props.labelSpace, false) ? 18 : 0;
|
|
@@ -6590,7 +7170,7 @@ var SVGRenderer = class {
|
|
|
6590
7170
|
wrapTextToLines(text, maxWidth, fontSize) {
|
|
6591
7171
|
const normalized = text.replace(/\r\n/g, "\n");
|
|
6592
7172
|
const paragraphs = normalized.split("\n");
|
|
6593
|
-
const charWidth = fontSize * 0.
|
|
7173
|
+
const charWidth = fontSize * 0.5;
|
|
6594
7174
|
const safeWidth = Math.max(maxWidth || 0, charWidth);
|
|
6595
7175
|
const maxCharsPerLine = Math.max(1, Math.floor(safeWidth / charWidth));
|
|
6596
7176
|
const lines = [];
|
|
@@ -7705,7 +8285,7 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
7705
8285
|
renderButton(node, pos) {
|
|
7706
8286
|
const text = String(node.props.text || "Button");
|
|
7707
8287
|
const variant = String(node.props.variant || "default");
|
|
7708
|
-
const size = String(node.props.size || "
|
|
8288
|
+
const size = String(node.props.size || "sm");
|
|
7709
8289
|
const density = this.ir.project.style.density || "normal";
|
|
7710
8290
|
const extraPadding = resolveControlHorizontalPadding(String(node.props.padding || "none"), density);
|
|
7711
8291
|
const labelOffset = this.parseBooleanProp(node.props.labelSpace, false) ? 18 : 0;
|
|
@@ -7812,7 +8392,7 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
7812
8392
|
renderIconButton(node, pos) {
|
|
7813
8393
|
const iconName = String(node.props.icon || "help-circle");
|
|
7814
8394
|
const variant = String(node.props.variant || "default");
|
|
7815
|
-
const size = String(node.props.size || "
|
|
8395
|
+
const size = String(node.props.size || "sm");
|
|
7816
8396
|
const density = this.ir.project.style.density || "normal";
|
|
7817
8397
|
const labelOffset = this.parseBooleanProp(node.props.labelSpace, false) ? 18 : 0;
|
|
7818
8398
|
const extraPadding = resolveControlHorizontalPadding(String(node.props.padding || "none"), density);
|
|
@@ -8065,26 +8645,58 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8065
8645
|
const variant = String(node.props.variant || "default");
|
|
8066
8646
|
const accentColor = variant === "default" ? this.resolveAccentColor() : this.resolveVariantColor(variant, this.resolveAccentColor());
|
|
8067
8647
|
const topbar = this.calculateTopbarLayout(node, pos, title, subtitle, actions, user);
|
|
8068
|
-
|
|
8648
|
+
const bgPropStr = String(node.props.background ?? "");
|
|
8649
|
+
let sketchTopbarBg = this.renderTheme.cardBg;
|
|
8650
|
+
if (bgPropStr && bgPropStr !== "false" && bgPropStr !== "true") {
|
|
8651
|
+
if (bgPropStr.startsWith("#") || bgPropStr.startsWith("rgb")) {
|
|
8652
|
+
sketchTopbarBg = bgPropStr;
|
|
8653
|
+
} else if (this.colorResolver.hasColor(bgPropStr)) {
|
|
8654
|
+
sketchTopbarBg = this.colorResolver.resolveColor(bgPropStr, this.renderTheme.cardBg);
|
|
8655
|
+
}
|
|
8656
|
+
}
|
|
8657
|
+
const colorPropStr = String(node.props.color ?? "");
|
|
8658
|
+
let titleColor = this.renderTheme.text;
|
|
8659
|
+
let subtitleColor = this.renderTheme.textMuted;
|
|
8660
|
+
if (colorPropStr && colorPropStr !== "false") {
|
|
8661
|
+
let resolvedTitleColor = null;
|
|
8662
|
+
if (colorPropStr.startsWith("#") || colorPropStr.startsWith("rgb")) {
|
|
8663
|
+
resolvedTitleColor = colorPropStr;
|
|
8664
|
+
} else if (this.colorResolver.hasColor(colorPropStr)) {
|
|
8665
|
+
resolvedTitleColor = this.colorResolver.resolveColor(colorPropStr, this.renderTheme.text);
|
|
8666
|
+
}
|
|
8667
|
+
if (resolvedTitleColor) {
|
|
8668
|
+
titleColor = resolvedTitleColor;
|
|
8669
|
+
subtitleColor = this.hexToRgba(resolvedTitleColor, 0.65);
|
|
8670
|
+
}
|
|
8671
|
+
}
|
|
8672
|
+
const showBorder = this.parseBooleanProp(node.props.border, false);
|
|
8673
|
+
const hasBgProp = bgPropStr === "true" || bgPropStr && bgPropStr !== "false" && bgPropStr !== "";
|
|
8674
|
+
const showBackground = hasBgProp;
|
|
8675
|
+
let svg = `<g${this.getDataNodeId(node)}>`;
|
|
8676
|
+
if (showBorder || showBackground) {
|
|
8677
|
+
const stroke = showBorder ? "#2D3748" : "none";
|
|
8678
|
+
svg += `
|
|
8069
8679
|
<rect x="${pos.x}" y="${pos.y}"
|
|
8070
8680
|
width="${pos.width}" height="${pos.height}"
|
|
8071
|
-
fill="${
|
|
8072
|
-
stroke="
|
|
8681
|
+
fill="${sketchTopbarBg}"
|
|
8682
|
+
stroke="${stroke}"
|
|
8073
8683
|
stroke-width="0.5"
|
|
8074
|
-
filter="url(#sketch-rough)"
|
|
8075
|
-
|
|
8076
|
-
|
|
8684
|
+
filter="url(#sketch-rough)"/>`;
|
|
8685
|
+
}
|
|
8686
|
+
svg += `
|
|
8687
|
+
<!-- Title -->`;
|
|
8688
|
+
svg += `
|
|
8077
8689
|
<text x="${topbar.textX}" y="${topbar.titleY}"
|
|
8078
8690
|
font-family="${this.fontFamily}"
|
|
8079
8691
|
font-size="18"
|
|
8080
8692
|
font-weight="600"
|
|
8081
|
-
fill="${
|
|
8693
|
+
fill="${titleColor}">${this.escapeXml(topbar.visibleTitle)}</text>`;
|
|
8082
8694
|
if (topbar.hasSubtitle) {
|
|
8083
8695
|
svg += `
|
|
8084
8696
|
<text x="${topbar.textX}" y="${topbar.subtitleY}"
|
|
8085
8697
|
font-family="${this.fontFamily}"
|
|
8086
8698
|
font-size="13"
|
|
8087
|
-
fill="${
|
|
8699
|
+
fill="${subtitleColor}">${this.escapeXml(topbar.visibleSubtitle)}</text>`;
|
|
8088
8700
|
}
|
|
8089
8701
|
if (topbar.leftIcon) {
|
|
8090
8702
|
svg += `
|
|
@@ -8164,8 +8776,13 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8164
8776
|
*/
|
|
8165
8777
|
renderText(node, pos) {
|
|
8166
8778
|
const text = String(node.props.text || "Text content");
|
|
8167
|
-
const
|
|
8779
|
+
const sizeProp = String(node.props.size || "");
|
|
8780
|
+
const defaultFontSize = this.tokens.text.fontSize;
|
|
8781
|
+
const textFontSizeMap = { xs: 10, sm: 12, lg: 16, xl: 20 };
|
|
8782
|
+
const fontSize = textFontSizeMap[sizeProp] ?? defaultFontSize;
|
|
8168
8783
|
const lineHeightPx = Math.ceil(fontSize * this.tokens.text.lineHeight);
|
|
8784
|
+
const bold = this.parseBooleanProp(node.props.bold, false);
|
|
8785
|
+
const italic = this.parseBooleanProp(node.props.italic, false);
|
|
8169
8786
|
const lines = this.wrapTextToLines(text, pos.width, fontSize);
|
|
8170
8787
|
const firstLineY = pos.y + fontSize;
|
|
8171
8788
|
const tspans = lines.map(
|
|
@@ -8175,9 +8792,48 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8175
8792
|
<text x="${pos.x}" y="${firstLineY}"
|
|
8176
8793
|
font-family="${this.fontFamily}"
|
|
8177
8794
|
font-size="${fontSize}"
|
|
8795
|
+
font-weight="${bold ? "700" : "400"}"
|
|
8796
|
+
font-style="${italic ? "italic" : "normal"}"
|
|
8178
8797
|
fill="${this.renderTheme.text}">${tspans}</text>
|
|
8179
8798
|
</g>`;
|
|
8180
8799
|
}
|
|
8800
|
+
renderParagraph(node, pos) {
|
|
8801
|
+
const text = String(node.props.text || "");
|
|
8802
|
+
const sizeProp = String(node.props.size || "");
|
|
8803
|
+
const defaultFontSize = this.tokens.text.fontSize;
|
|
8804
|
+
const textFontSizeMap = { xs: 10, sm: 12, lg: 16, xl: 20 };
|
|
8805
|
+
const fontSize = textFontSizeMap[sizeProp] ?? defaultFontSize;
|
|
8806
|
+
const lineHeightPx = Math.ceil(fontSize * this.tokens.text.lineHeight);
|
|
8807
|
+
const bold = this.parseBooleanProp(node.props.bold, false);
|
|
8808
|
+
const italic = this.parseBooleanProp(node.props.italic, false);
|
|
8809
|
+
const align = String(node.props.align || "left");
|
|
8810
|
+
const lines = this.wrapTextToLines(text, pos.width, fontSize);
|
|
8811
|
+
const firstLineY = pos.y + fontSize;
|
|
8812
|
+
let textX;
|
|
8813
|
+
let textAnchor;
|
|
8814
|
+
if (align === "center") {
|
|
8815
|
+
textX = pos.x + pos.width / 2;
|
|
8816
|
+
textAnchor = "middle";
|
|
8817
|
+
} else if (align === "right") {
|
|
8818
|
+
textX = pos.x + pos.width;
|
|
8819
|
+
textAnchor = "end";
|
|
8820
|
+
} else {
|
|
8821
|
+
textX = pos.x;
|
|
8822
|
+
textAnchor = "start";
|
|
8823
|
+
}
|
|
8824
|
+
const tspans = lines.map(
|
|
8825
|
+
(line, index) => `<tspan x="${textX}" dy="${index === 0 ? 0 : lineHeightPx}">${this.escapeXml(line)}</tspan>`
|
|
8826
|
+
).join("");
|
|
8827
|
+
return `<g${this.getDataNodeId(node)}>
|
|
8828
|
+
<text x="${textX}" y="${firstLineY}"
|
|
8829
|
+
font-family="${this.fontFamily}"
|
|
8830
|
+
font-size="${fontSize}"
|
|
8831
|
+
font-weight="${bold ? "700" : "400"}"
|
|
8832
|
+
font-style="${italic ? "italic" : "normal"}"
|
|
8833
|
+
fill="${this.renderTheme.text}"
|
|
8834
|
+
text-anchor="${textAnchor}">${tspans}</text>
|
|
8835
|
+
</g>`;
|
|
8836
|
+
}
|
|
8181
8837
|
/**
|
|
8182
8838
|
* Render label with Comic Sans
|
|
8183
8839
|
*/
|
|
@@ -8408,36 +9064,150 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8408
9064
|
renderTabs(node, pos) {
|
|
8409
9065
|
const itemsStr = String(node.props.items || "");
|
|
8410
9066
|
const tabs = itemsStr ? itemsStr.split(",").map((t) => t.trim()) : ["Tab 1", "Tab 2", "Tab 3"];
|
|
8411
|
-
const
|
|
9067
|
+
const activeProp = node.props.active ?? 0;
|
|
9068
|
+
const activeIndex = Number.isFinite(Number(activeProp)) ? Math.max(0, Math.floor(Number(activeProp))) : 0;
|
|
9069
|
+
const variant = String(node.props.variant || "default");
|
|
9070
|
+
const accentColor = variant === "default" ? this.resolveAccentColor() : this.resolveVariantColor(variant, this.resolveAccentColor());
|
|
9071
|
+
const radiusMap = { none: 0, sm: 4, md: 6, lg: 10, full: 20 };
|
|
9072
|
+
const tabRadius = radiusMap[String(node.props.radius || "md")] ?? 6;
|
|
9073
|
+
const sizeMap = { sm: 32, md: 44, lg: 52 };
|
|
9074
|
+
const tabHeight = pos.height > 0 ? pos.height : sizeMap[String(node.props.size || "md")] ?? 44;
|
|
9075
|
+
const fontSize = 13;
|
|
9076
|
+
const textY = pos.y + Math.round(tabHeight / 2) + Math.round(fontSize * 0.4);
|
|
9077
|
+
const iconsStr = String(node.props.icons || "");
|
|
9078
|
+
const iconList = iconsStr ? iconsStr.split(",").map((s) => s.trim()) : [];
|
|
9079
|
+
const isFlat = this.parseBooleanProp(node.props.flat, false);
|
|
9080
|
+
const showBorder = this.parseBooleanProp(node.props.border, true);
|
|
8412
9081
|
const tabWidth = pos.width / tabs.length;
|
|
8413
|
-
|
|
8414
|
-
|
|
9082
|
+
const colorPropStr = String(node.props.color ?? "");
|
|
9083
|
+
let textColorOverride = null;
|
|
9084
|
+
if (colorPropStr && colorPropStr !== "false") {
|
|
9085
|
+
if (colorPropStr.startsWith("#") || colorPropStr.startsWith("rgb")) {
|
|
9086
|
+
textColorOverride = colorPropStr;
|
|
9087
|
+
} else if (this.colorResolver.hasColor(colorPropStr)) {
|
|
9088
|
+
textColorOverride = this.colorResolver.resolveColor(colorPropStr, this.renderTheme.text);
|
|
9089
|
+
}
|
|
9090
|
+
}
|
|
9091
|
+
const activeTextColor = textColorOverride ?? (isFlat ? accentColor : "white");
|
|
9092
|
+
const inactiveTextColor = textColorOverride ? this.hexToRgba(textColorOverride, 0.55) : this.renderTheme.textMuted;
|
|
9093
|
+
const hasRadius = tabRadius > 0;
|
|
9094
|
+
const clipId = hasRadius ? `stc${String(node.meta?.nodeId ?? "").replace(/\W/g, "").slice(0, 12) || `${Math.round(Math.abs(pos.x))}x${Math.round(Math.abs(pos.y))}`}` : "";
|
|
9095
|
+
let svg = "";
|
|
9096
|
+
if (hasRadius) {
|
|
9097
|
+
svg += `<defs><clipPath id="${clipId}"><rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" rx="${tabRadius}"/></clipPath></defs>`;
|
|
9098
|
+
}
|
|
9099
|
+
svg += `<g${this.getDataNodeId(node)}>`;
|
|
9100
|
+
if (hasRadius) {
|
|
9101
|
+
svg += `<g clip-path="url(#${clipId})">`;
|
|
9102
|
+
}
|
|
9103
|
+
if (!isFlat) {
|
|
9104
|
+
svg += `
|
|
9105
|
+
<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${tabHeight}"
|
|
9106
|
+
fill="${this.renderTheme.bg}"/>`;
|
|
9107
|
+
}
|
|
8415
9108
|
tabs.forEach((tab, i) => {
|
|
8416
9109
|
const tabX = pos.x + i * tabWidth;
|
|
8417
|
-
const isActive = i ===
|
|
8418
|
-
|
|
9110
|
+
const isActive = i === activeIndex;
|
|
9111
|
+
const iconName = iconList[i] || "";
|
|
9112
|
+
const tabIconSvg = iconName ? getIcon(iconName) : null;
|
|
9113
|
+
const iconSize = 14;
|
|
9114
|
+
const iconGap = 4;
|
|
9115
|
+
const charW = fontSize * 0.58;
|
|
9116
|
+
const textEst = tab.length * charW;
|
|
9117
|
+
const totalW = tabIconSvg ? iconSize + iconGap + textEst : textEst;
|
|
9118
|
+
const groupX = tabX + Math.round((tabWidth - totalW) / 2);
|
|
9119
|
+
const iconOffY = pos.y + Math.round((tabHeight - iconSize) / 2);
|
|
9120
|
+
if (isFlat) {
|
|
9121
|
+
if (isActive) {
|
|
9122
|
+
svg += `
|
|
9123
|
+
<rect x="${tabX + 6}" y="${pos.y + tabHeight - 3}"
|
|
9124
|
+
width="${tabWidth - 12}" height="3"
|
|
9125
|
+
rx="1.5"
|
|
9126
|
+
fill="${accentColor}"
|
|
9127
|
+
filter="url(#sketch-rough)"/>`;
|
|
9128
|
+
}
|
|
9129
|
+
if (tabIconSvg) {
|
|
9130
|
+
svg += `
|
|
9131
|
+
<g transform="translate(${groupX}, ${iconOffY})">
|
|
9132
|
+
<svg width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none"
|
|
9133
|
+
stroke="${isActive ? accentColor : this.renderTheme.textMuted}"
|
|
9134
|
+
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
9135
|
+
${this.extractSvgContent(tabIconSvg)}
|
|
9136
|
+
</svg>
|
|
9137
|
+
</g>
|
|
9138
|
+
<text x="${groupX + iconSize + iconGap}" y="${textY}"
|
|
9139
|
+
font-family="${this.fontFamily}"
|
|
9140
|
+
font-size="${fontSize}"
|
|
9141
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
9142
|
+
fill="${isActive ? activeTextColor : inactiveTextColor}">${this.escapeXml(tab)}</text>`;
|
|
9143
|
+
} else {
|
|
9144
|
+
svg += `
|
|
9145
|
+
<text x="${tabX + tabWidth / 2}" y="${textY}"
|
|
9146
|
+
font-family="${this.fontFamily}"
|
|
9147
|
+
font-size="${fontSize}"
|
|
9148
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
9149
|
+
fill="${isActive ? activeTextColor : inactiveTextColor}"
|
|
9150
|
+
text-anchor="middle">${this.escapeXml(tab)}</text>`;
|
|
9151
|
+
}
|
|
9152
|
+
} else {
|
|
9153
|
+
svg += `
|
|
8419
9154
|
<rect x="${tabX}" y="${pos.y}"
|
|
8420
|
-
width="${tabWidth}" height="
|
|
9155
|
+
width="${tabWidth}" height="${tabHeight}"
|
|
9156
|
+
rx="${!showBorder && hasRadius && isActive ? tabRadius : 0}"
|
|
8421
9157
|
fill="${isActive ? accentColor : "transparent"}"
|
|
8422
|
-
stroke="${isActive ? accentColor : "#2D3748"}"
|
|
9158
|
+
stroke="${isActive ? accentColor : showBorder ? "#2D3748" : "none"}"
|
|
8423
9159
|
stroke-width="0.5"
|
|
8424
|
-
filter="url(#sketch-rough)"
|
|
8425
|
-
|
|
9160
|
+
filter="url(#sketch-rough)"/>`;
|
|
9161
|
+
if (tabIconSvg) {
|
|
9162
|
+
svg += `
|
|
9163
|
+
<g transform="translate(${groupX}, ${iconOffY})">
|
|
9164
|
+
<svg width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none"
|
|
9165
|
+
stroke="${isActive ? activeTextColor : this.renderTheme.textMuted}"
|
|
9166
|
+
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
9167
|
+
${this.extractSvgContent(tabIconSvg)}
|
|
9168
|
+
</svg>
|
|
9169
|
+
</g>
|
|
9170
|
+
<text x="${groupX + iconSize + iconGap}" y="${textY}"
|
|
8426
9171
|
font-family="${this.fontFamily}"
|
|
8427
|
-
font-size="
|
|
9172
|
+
font-size="${fontSize}"
|
|
9173
|
+
font-weight="${isActive ? "600" : "500"}"
|
|
9174
|
+
fill="${isActive ? activeTextColor : this.renderTheme.text}">${this.escapeXml(tab)}</text>`;
|
|
9175
|
+
} else {
|
|
9176
|
+
svg += `
|
|
9177
|
+
<text x="${tabX + tabWidth / 2}" y="${textY}"
|
|
9178
|
+
font-family="${this.fontFamily}"
|
|
9179
|
+
font-size="${fontSize}"
|
|
8428
9180
|
font-weight="${isActive ? "600" : "500"}"
|
|
8429
|
-
fill="${isActive ?
|
|
9181
|
+
fill="${isActive ? activeTextColor : this.renderTheme.text}"
|
|
8430
9182
|
text-anchor="middle">${this.escapeXml(tab)}</text>`;
|
|
9183
|
+
}
|
|
9184
|
+
}
|
|
8431
9185
|
});
|
|
8432
|
-
|
|
9186
|
+
const contentY = pos.y + tabHeight;
|
|
9187
|
+
const contentH = pos.height - tabHeight;
|
|
9188
|
+
if (contentH >= 20 && !isFlat) {
|
|
9189
|
+
svg += `
|
|
8433
9190
|
<!-- Tab content area -->
|
|
8434
|
-
<rect x="${pos.x}" y="${
|
|
8435
|
-
width="${pos.width}" height="${
|
|
9191
|
+
<rect x="${pos.x}" y="${contentY}"
|
|
9192
|
+
width="${pos.width}" height="${contentH}"
|
|
8436
9193
|
fill="${this.renderTheme.cardBg}"
|
|
8437
|
-
stroke="#2D3748"
|
|
8438
|
-
|
|
8439
|
-
|
|
9194
|
+
${showBorder ? 'stroke="#2D3748" stroke-width="0.5" filter="url(#sketch-rough)"' : ""}/>`;
|
|
9195
|
+
} else if (isFlat && showBorder) {
|
|
9196
|
+
svg += `
|
|
9197
|
+
<line x1="${pos.x}" y1="${contentY}" x2="${pos.x + pos.width}" y2="${contentY}"
|
|
9198
|
+
stroke="#2D3748" stroke-width="0.5" filter="url(#sketch-rough)"/>`;
|
|
9199
|
+
}
|
|
9200
|
+
if (hasRadius) {
|
|
9201
|
+
svg += `
|
|
8440
9202
|
</g>`;
|
|
9203
|
+
if (!isFlat && showBorder) {
|
|
9204
|
+
svg += `
|
|
9205
|
+
<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}"
|
|
9206
|
+
rx="${tabRadius}" fill="none" stroke="#2D3748" stroke-width="0.5"
|
|
9207
|
+
filter="url(#sketch-rough)"/>`;
|
|
9208
|
+
}
|
|
9209
|
+
}
|
|
9210
|
+
svg += "\n </g>";
|
|
8441
9211
|
return svg;
|
|
8442
9212
|
}
|
|
8443
9213
|
/**
|
|
@@ -8674,11 +9444,20 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8674
9444
|
* Render image with sketch filter
|
|
8675
9445
|
*/
|
|
8676
9446
|
renderImage(node, pos) {
|
|
8677
|
-
const placeholder = String(node.props.
|
|
9447
|
+
const placeholder = String(node.props.type || "landscape").toLowerCase();
|
|
8678
9448
|
const iconType = String(node.props.icon || "").trim();
|
|
8679
9449
|
const variant = String(node.props.variant || "").trim();
|
|
8680
9450
|
const iconSvg = placeholder === "icon" && iconType.length > 0 ? getIcon(iconType) : null;
|
|
8681
9451
|
const imageBg = this.options.theme === "dark" ? "#2A2A2A" : "#E8E8E8";
|
|
9452
|
+
const hasExplicitHeight = node.props.height !== void 0 && !isNaN(Number(node.props.height)) && Number(node.props.height) > 0;
|
|
9453
|
+
const isCircle = this.parseBooleanProp(node.props.circle, false);
|
|
9454
|
+
const useClip = isCircle || hasExplicitHeight;
|
|
9455
|
+
const clipId = useClip ? `sclip${String(node.meta?.nodeId ?? "").replace(/\W/g, "").slice(0, 16) || `${Math.round(Math.abs(pos.x))}x${Math.round(Math.abs(pos.y))}`}` : "";
|
|
9456
|
+
const imgCx = pos.x + pos.width / 2;
|
|
9457
|
+
const imgCy = pos.y + pos.height / 2;
|
|
9458
|
+
const imgR = Math.min(pos.width, pos.height) / 2;
|
|
9459
|
+
const defsHtml = useClip ? `<defs><clipPath id="${clipId}">${isCircle ? `<circle cx="${imgCx}" cy="${imgCy}" r="${imgR}"/>` : `<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" rx="4"/>`}</clipPath></defs>` : "";
|
|
9460
|
+
const clipAttr = useClip ? ` clip-path="url(#${clipId})"` : "";
|
|
8682
9461
|
if (iconSvg) {
|
|
8683
9462
|
const semanticBase = variant ? this.getSemanticVariantColor(variant) : void 0;
|
|
8684
9463
|
const hasVariant = variant.length > 0 && (semanticBase !== void 0 || this.colorResolver.hasColor(variant));
|
|
@@ -8688,7 +9467,8 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8688
9467
|
const iconSize = Math.max(16, Math.min(pos.width, pos.height) * 0.6);
|
|
8689
9468
|
const iconOffsetX = pos.x + (pos.width - iconSize) / 2;
|
|
8690
9469
|
const iconOffsetY = pos.y + (pos.height - iconSize) / 2;
|
|
8691
|
-
|
|
9470
|
+
const sketchIconBorder = isCircle ? `<circle cx="${imgCx}" cy="${imgCy}" r="${imgR}" fill="none" stroke="#2D3748" stroke-width="0.5" filter="url(#sketch-rough)"/>` : `<rect x="${pos.x}" y="${pos.y}" width="${pos.width}" height="${pos.height}" fill="none" stroke="#2D3748" stroke-width="0.5" rx="4" filter="url(#sketch-rough)"/>`;
|
|
9471
|
+
return `${defsHtml}<g${this.getDataNodeId(node)}${clipAttr}>
|
|
8692
9472
|
<rect x="${pos.x}" y="${pos.y}"
|
|
8693
9473
|
width="${pos.width}" height="${pos.height}"
|
|
8694
9474
|
fill="${bgColor}"
|
|
@@ -8699,17 +9479,11 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8699
9479
|
${this.extractSvgContent(iconSvg)}
|
|
8700
9480
|
</svg>
|
|
8701
9481
|
</g>
|
|
8702
|
-
|
|
8703
|
-
width="${pos.width}" height="${pos.height}"
|
|
8704
|
-
fill="none"
|
|
8705
|
-
stroke="#2D3748"
|
|
8706
|
-
stroke-width="0.5"
|
|
8707
|
-
rx="4"
|
|
8708
|
-
filter="url(#sketch-rough)"/>
|
|
9482
|
+
${sketchIconBorder}
|
|
8709
9483
|
</g>`;
|
|
8710
9484
|
}
|
|
8711
|
-
|
|
8712
|
-
|
|
9485
|
+
const sketchCircleBorder = isCircle ? `<circle cx="${imgCx}" cy="${imgCy}" r="${imgR}" fill="none" stroke="#2D3748" stroke-width="0.5"/>` : "";
|
|
9486
|
+
return `${defsHtml}<g${this.getDataNodeId(node)}${clipAttr}>
|
|
8713
9487
|
<rect x="${pos.x}" y="${pos.y}"
|
|
8714
9488
|
width="${pos.width}" height="${pos.height}"
|
|
8715
9489
|
fill="${imageBg}"
|
|
@@ -8717,14 +9491,12 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8717
9491
|
stroke-width="0.5"
|
|
8718
9492
|
rx="4"
|
|
8719
9493
|
filter="url(#sketch-rough)"/>
|
|
8720
|
-
|
|
8721
|
-
<!-- Placeholder icon -->
|
|
8722
9494
|
<text x="${pos.x + pos.width / 2}" y="${pos.y + pos.height / 2}"
|
|
8723
9495
|
font-family="${this.fontFamily}"
|
|
8724
9496
|
font-size="24"
|
|
8725
9497
|
fill="#666"
|
|
8726
9498
|
text-anchor="middle">\u{1F5BC}</text>
|
|
8727
|
-
</g
|
|
9499
|
+
</g>${sketchCircleBorder}`;
|
|
8728
9500
|
}
|
|
8729
9501
|
/**
|
|
8730
9502
|
* Render breadcrumbs with Comic Sans
|
|
@@ -8840,20 +9612,33 @@ var SketchSVGRenderer = class extends SVGRenderer {
|
|
|
8840
9612
|
}
|
|
8841
9613
|
const iconSize = this.getIconSize(size);
|
|
8842
9614
|
const iconColor = variant === "default" ? this.resolveTextColor() : this.resolveVariantColor(variant, this.resolveTextColor());
|
|
8843
|
-
const
|
|
8844
|
-
const
|
|
9615
|
+
const paddingPx = Math.max(0, Number(node.props.padding || 0));
|
|
9616
|
+
const renderedIconSize = Math.max(4, iconSize - paddingPx * 2);
|
|
9617
|
+
const offsetX = pos.x + (pos.width - renderedIconSize) / 2;
|
|
9618
|
+
const offsetY = pos.y + (pos.height - renderedIconSize) / 2;
|
|
9619
|
+
const isIconCircle = this.parseBooleanProp(node.props.circle, false);
|
|
9620
|
+
if (isIconCircle) {
|
|
9621
|
+
const cx = pos.x + pos.width / 2;
|
|
9622
|
+
const cy = pos.y + pos.height / 2;
|
|
9623
|
+
const r = Math.min(pos.width, pos.height) / 2;
|
|
9624
|
+
const iconClipId = `sconclip${String(node.meta?.nodeId ?? "").replace(/\W/g, "").slice(0, 16) || `${Math.round(Math.abs(pos.x))}x${Math.round(Math.abs(pos.y))}`}`;
|
|
9625
|
+
const bgColor = this.hexToRgba(iconColor, 0.1);
|
|
9626
|
+
return `<defs><clipPath id="${iconClipId}"><circle cx="${cx}" cy="${cy}" r="${r}"/></clipPath></defs><g${this.getDataNodeId(node)} clip-path="url(#${iconClipId})">
|
|
9627
|
+
<circle cx="${cx}" cy="${cy}" r="${r}" fill="${bgColor}"/>
|
|
9628
|
+
<g transform="translate(${offsetX}, ${offsetY})">
|
|
9629
|
+
<svg width="${renderedIconSize}" height="${renderedIconSize}" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round">
|
|
9630
|
+
${this.extractSvgContent(iconSvg)}
|
|
9631
|
+
</svg>
|
|
9632
|
+
</g>
|
|
9633
|
+
</g>
|
|
9634
|
+
<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${this.hexToRgba(iconColor, 0.35)}" stroke-width="0.5"/>`;
|
|
9635
|
+
}
|
|
8845
9636
|
return `<g${this.getDataNodeId(node)} transform="translate(${offsetX}, ${offsetY})">
|
|
8846
|
-
<svg width="${
|
|
9637
|
+
<svg width="${renderedIconSize}" height="${renderedIconSize}" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round">
|
|
8847
9638
|
${this.extractSvgContent(iconSvg)}
|
|
8848
9639
|
</svg>
|
|
8849
9640
|
</g>`;
|
|
8850
9641
|
}
|
|
8851
|
-
/**
|
|
8852
|
-
* Render chart placeholder with sketch filter and Comic Sans
|
|
8853
|
-
*/
|
|
8854
|
-
renderChartPlaceholder(node, pos) {
|
|
8855
|
-
return super.renderChartPlaceholder(node, pos);
|
|
8856
|
-
}
|
|
8857
9642
|
/**
|
|
8858
9643
|
* Helper method to get icon SVG
|
|
8859
9644
|
*/
|