@spectratools/graphic-designer-cli 0.11.0 → 0.12.1
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 +42 -1
- package/dist/cli.js +104 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +104 -8
- package/dist/qa.d.ts +1 -1
- package/dist/qa.js +21 -0
- package/dist/renderer.d.ts +1 -1
- package/dist/renderer.js +104 -8
- package/dist/{spec.schema-CYlOLxmK.d.ts → spec.schema-BkbcnVcm.d.ts} +466 -117
- package/dist/spec.schema.d.ts +1 -1
- package/dist/spec.schema.js +21 -0
- package/package.json +2 -2
package/dist/renderer.js
CHANGED
|
@@ -1005,6 +1005,35 @@ async function computeElkLayout(elements, config, safeFrame) {
|
|
|
1005
1005
|
};
|
|
1006
1006
|
}
|
|
1007
1007
|
|
|
1008
|
+
// src/layout/ellipse.ts
|
|
1009
|
+
function clampDimension(estimated, max) {
|
|
1010
|
+
return Math.max(1, Math.min(max, Math.floor(estimated)));
|
|
1011
|
+
}
|
|
1012
|
+
function computeEllipseLayout(elements, config, safeFrame) {
|
|
1013
|
+
const placeable = elements.filter((element) => element.type !== "connection");
|
|
1014
|
+
const positions = /* @__PURE__ */ new Map();
|
|
1015
|
+
if (placeable.length === 0) {
|
|
1016
|
+
return { positions };
|
|
1017
|
+
}
|
|
1018
|
+
const cx = config.cx ?? safeFrame.x + safeFrame.width / 2;
|
|
1019
|
+
const cy = config.cy ?? safeFrame.y + safeFrame.height / 2;
|
|
1020
|
+
const stepDegrees = 360 / placeable.length;
|
|
1021
|
+
for (const [index, element] of placeable.entries()) {
|
|
1022
|
+
const angleRadians = (config.startAngle + index * stepDegrees) * Math.PI / 180;
|
|
1023
|
+
const centerX = cx + config.rx * Math.cos(angleRadians);
|
|
1024
|
+
const centerY = cy + config.ry * Math.sin(angleRadians);
|
|
1025
|
+
const width = clampDimension(estimateElementWidth(element), safeFrame.width);
|
|
1026
|
+
const height = clampDimension(estimateElementHeight(element), safeFrame.height);
|
|
1027
|
+
positions.set(element.id, {
|
|
1028
|
+
x: Math.round(centerX - width / 2),
|
|
1029
|
+
y: Math.round(centerY - height / 2),
|
|
1030
|
+
width,
|
|
1031
|
+
height
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
return { positions };
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1008
1037
|
// src/layout/grid.ts
|
|
1009
1038
|
function computeGridLayout(elements, config, safeFrame) {
|
|
1010
1039
|
const placeable = elements.filter((element) => element.type !== "connection");
|
|
@@ -1100,6 +1129,8 @@ async function computeLayout(elements, layout, safeFrame) {
|
|
|
1100
1129
|
return computeGridLayout(elements, layout, safeFrame);
|
|
1101
1130
|
case "stack":
|
|
1102
1131
|
return computeStackLayout(elements, layout, safeFrame);
|
|
1132
|
+
case "ellipse":
|
|
1133
|
+
return computeEllipseLayout(elements, layout, safeFrame);
|
|
1103
1134
|
case "manual":
|
|
1104
1135
|
return computeManualLayout(elements, layout, safeFrame);
|
|
1105
1136
|
default:
|
|
@@ -2692,6 +2723,24 @@ function fromPoints(points) {
|
|
|
2692
2723
|
function resolveDrawFont(theme, family) {
|
|
2693
2724
|
return resolveFont(theme.fonts[family], family);
|
|
2694
2725
|
}
|
|
2726
|
+
function createDrawStrokeGradient(ctx, start, end, strokeGradient) {
|
|
2727
|
+
const gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
|
|
2728
|
+
gradient.addColorStop(0, strokeGradient.from);
|
|
2729
|
+
gradient.addColorStop(1, strokeGradient.to);
|
|
2730
|
+
return gradient;
|
|
2731
|
+
}
|
|
2732
|
+
function resolveDrawStroke(ctx, start, end, color, strokeGradient) {
|
|
2733
|
+
if (!strokeGradient) {
|
|
2734
|
+
return color;
|
|
2735
|
+
}
|
|
2736
|
+
return createDrawStrokeGradient(ctx, start, end, strokeGradient);
|
|
2737
|
+
}
|
|
2738
|
+
function resolveArrowFill(color, strokeGradient, position) {
|
|
2739
|
+
if (!strokeGradient) {
|
|
2740
|
+
return color;
|
|
2741
|
+
}
|
|
2742
|
+
return position === "start" ? strokeGradient.from : strokeGradient.to;
|
|
2743
|
+
}
|
|
2695
2744
|
function measureSpacedTextWidth(ctx, text, letterSpacing) {
|
|
2696
2745
|
const chars = [...text];
|
|
2697
2746
|
if (chars.length === 0) {
|
|
@@ -2970,18 +3019,31 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2970
3019
|
const from = { x: command.x1, y: command.y1 };
|
|
2971
3020
|
const to = { x: command.x2, y: command.y2 };
|
|
2972
3021
|
const lineAngle = angleBetween(from, to);
|
|
3022
|
+
const stroke = resolveDrawStroke(ctx, from, to, command.color, command.strokeGradient);
|
|
2973
3023
|
withOpacity(ctx, command.opacity, () => {
|
|
2974
3024
|
applyDrawShadow(ctx, command.shadow);
|
|
2975
3025
|
drawLine(ctx, from, to, {
|
|
2976
|
-
color:
|
|
3026
|
+
color: stroke,
|
|
2977
3027
|
width: command.width,
|
|
2978
3028
|
...command.dash ? { dash: command.dash } : {}
|
|
2979
3029
|
});
|
|
2980
3030
|
if (command.arrow === "end" || command.arrow === "both") {
|
|
2981
|
-
drawArrowhead(
|
|
3031
|
+
drawArrowhead(
|
|
3032
|
+
ctx,
|
|
3033
|
+
to,
|
|
3034
|
+
lineAngle,
|
|
3035
|
+
command.arrowSize,
|
|
3036
|
+
resolveArrowFill(command.color, command.strokeGradient, "end")
|
|
3037
|
+
);
|
|
2982
3038
|
}
|
|
2983
3039
|
if (command.arrow === "start" || command.arrow === "both") {
|
|
2984
|
-
drawArrowhead(
|
|
3040
|
+
drawArrowhead(
|
|
3041
|
+
ctx,
|
|
3042
|
+
from,
|
|
3043
|
+
lineAngle + Math.PI,
|
|
3044
|
+
command.arrowSize,
|
|
3045
|
+
resolveArrowFill(command.color, command.strokeGradient, "start")
|
|
3046
|
+
);
|
|
2985
3047
|
}
|
|
2986
3048
|
});
|
|
2987
3049
|
const arrowPadding = command.arrow === "none" ? 0 : command.arrowSize;
|
|
@@ -2989,7 +3051,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2989
3051
|
id,
|
|
2990
3052
|
kind: "draw",
|
|
2991
3053
|
bounds: expandRect(fromPoints([from, to]), Math.max(command.width / 2, arrowPadding)),
|
|
2992
|
-
foregroundColor: command.color
|
|
3054
|
+
foregroundColor: command.strokeGradient?.from ?? command.color
|
|
2993
3055
|
});
|
|
2994
3056
|
break;
|
|
2995
3057
|
}
|
|
@@ -3023,10 +3085,17 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
3023
3085
|
}
|
|
3024
3086
|
case "bezier": {
|
|
3025
3087
|
const points = command.points;
|
|
3088
|
+
const stroke = resolveDrawStroke(
|
|
3089
|
+
ctx,
|
|
3090
|
+
points[0],
|
|
3091
|
+
points[points.length - 1],
|
|
3092
|
+
command.color,
|
|
3093
|
+
command.strokeGradient
|
|
3094
|
+
);
|
|
3026
3095
|
withOpacity(ctx, command.opacity, () => {
|
|
3027
3096
|
applyDrawShadow(ctx, command.shadow);
|
|
3028
3097
|
drawBezier(ctx, points, {
|
|
3029
|
-
color:
|
|
3098
|
+
color: stroke,
|
|
3030
3099
|
width: command.width,
|
|
3031
3100
|
...command.dash ? { dash: command.dash } : {}
|
|
3032
3101
|
});
|
|
@@ -3038,11 +3107,17 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
3038
3107
|
points[points.length - 1],
|
|
3039
3108
|
endAngle,
|
|
3040
3109
|
command.arrowSize,
|
|
3041
|
-
command.color
|
|
3110
|
+
resolveArrowFill(command.color, command.strokeGradient, "end")
|
|
3042
3111
|
);
|
|
3043
3112
|
}
|
|
3044
3113
|
if (command.arrow === "start" || command.arrow === "both") {
|
|
3045
|
-
drawArrowhead(
|
|
3114
|
+
drawArrowhead(
|
|
3115
|
+
ctx,
|
|
3116
|
+
points[0],
|
|
3117
|
+
startAngle + Math.PI,
|
|
3118
|
+
command.arrowSize,
|
|
3119
|
+
resolveArrowFill(command.color, command.strokeGradient, "start")
|
|
3120
|
+
);
|
|
3046
3121
|
}
|
|
3047
3122
|
});
|
|
3048
3123
|
const arrowPadding = command.arrow === "none" ? 0 : command.arrowSize;
|
|
@@ -3050,7 +3125,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
3050
3125
|
id,
|
|
3051
3126
|
kind: "draw",
|
|
3052
3127
|
bounds: expandRect(fromPoints(points), Math.max(command.width / 2, arrowPadding)),
|
|
3053
|
-
foregroundColor: command.color
|
|
3128
|
+
foregroundColor: command.strokeGradient?.from ?? command.color
|
|
3054
3129
|
});
|
|
3055
3130
|
break;
|
|
3056
3131
|
}
|
|
@@ -3550,6 +3625,10 @@ var drawShadowSchema = z2.object({
|
|
|
3550
3625
|
offsetY: z2.number().default(4)
|
|
3551
3626
|
}).strict();
|
|
3552
3627
|
var drawFontFamilySchema = z2.enum(["heading", "body", "mono"]);
|
|
3628
|
+
var strokeGradientSchema = z2.object({
|
|
3629
|
+
from: colorHexSchema2,
|
|
3630
|
+
to: colorHexSchema2
|
|
3631
|
+
}).strict();
|
|
3553
3632
|
var drawRectSchema = z2.object({
|
|
3554
3633
|
type: z2.literal("rect"),
|
|
3555
3634
|
x: z2.number(),
|
|
@@ -3597,6 +3676,7 @@ var drawLineSchema = z2.object({
|
|
|
3597
3676
|
x2: z2.number(),
|
|
3598
3677
|
y2: z2.number(),
|
|
3599
3678
|
color: colorHexSchema2.default("#FFFFFF"),
|
|
3679
|
+
strokeGradient: strokeGradientSchema.optional(),
|
|
3600
3680
|
width: z2.number().min(0.5).max(32).default(2),
|
|
3601
3681
|
dash: z2.array(z2.number()).max(6).optional(),
|
|
3602
3682
|
arrow: z2.enum(["none", "end", "start", "both"]).default("none"),
|
|
@@ -3627,6 +3707,7 @@ var drawBezierSchema = z2.object({
|
|
|
3627
3707
|
type: z2.literal("bezier"),
|
|
3628
3708
|
points: z2.array(drawPointSchema).min(2).max(20),
|
|
3629
3709
|
color: colorHexSchema2.default("#FFFFFF"),
|
|
3710
|
+
strokeGradient: strokeGradientSchema.optional(),
|
|
3630
3711
|
width: z2.number().min(0.5).max(32).default(2),
|
|
3631
3712
|
dash: z2.array(z2.number()).max(6).optional(),
|
|
3632
3713
|
arrow: z2.enum(["none", "end", "start", "both"]).default("none"),
|
|
@@ -3973,6 +4054,20 @@ var stackLayoutConfigSchema = z2.object({
|
|
|
3973
4054
|
/** Vertical radius for shared ellipse used by curveMode: 'ellipse'. */
|
|
3974
4055
|
ellipseRy: z2.number().positive().optional()
|
|
3975
4056
|
}).strict();
|
|
4057
|
+
var ellipseLayoutConfigSchema = z2.object({
|
|
4058
|
+
mode: z2.literal("ellipse"),
|
|
4059
|
+
cx: z2.number().optional(),
|
|
4060
|
+
cy: z2.number().optional(),
|
|
4061
|
+
rx: z2.number().positive(),
|
|
4062
|
+
ry: z2.number().positive(),
|
|
4063
|
+
startAngle: z2.number().default(-90),
|
|
4064
|
+
/** Explicit center used by curve/arc connection routing. */
|
|
4065
|
+
diagramCenter: diagramCenterSchema.optional(),
|
|
4066
|
+
/** Horizontal radius for shared ellipse used by curveMode: 'ellipse'. */
|
|
4067
|
+
ellipseRx: z2.number().positive().optional(),
|
|
4068
|
+
/** Vertical radius for shared ellipse used by curveMode: 'ellipse'. */
|
|
4069
|
+
ellipseRy: z2.number().positive().optional()
|
|
4070
|
+
}).strict();
|
|
3976
4071
|
var manualPositionSchema = z2.object({
|
|
3977
4072
|
x: z2.number().int(),
|
|
3978
4073
|
y: z2.number().int(),
|
|
@@ -3993,6 +4088,7 @@ var layoutConfigSchema = z2.discriminatedUnion("mode", [
|
|
|
3993
4088
|
autoLayoutConfigSchema,
|
|
3994
4089
|
gridLayoutConfigSchema,
|
|
3995
4090
|
stackLayoutConfigSchema,
|
|
4091
|
+
ellipseLayoutConfigSchema,
|
|
3996
4092
|
manualLayoutConfigSchema
|
|
3997
4093
|
]);
|
|
3998
4094
|
var constraintsSchema = z2.object({
|