@retikz/core 0.1.0-alpha.1 → 0.1.0-alpha.2

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.
Files changed (43) hide show
  1. package/dist/es/compile/node.d.ts +32 -6
  2. package/dist/es/compile/node.d.ts.map +1 -1
  3. package/dist/es/compile/node.js +112 -28
  4. package/dist/es/compile/text-metrics.d.ts +2 -2
  5. package/dist/es/compile/text-metrics.d.ts.map +1 -1
  6. package/dist/es/index.d.ts +4 -4
  7. package/dist/es/index.d.ts.map +1 -1
  8. package/dist/es/index.js +2 -2
  9. package/dist/es/ir/node.d.ts +286 -6
  10. package/dist/es/ir/node.d.ts.map +1 -1
  11. package/dist/es/ir/node.js +71 -5
  12. package/dist/es/ir/scene.d.ts +376 -16
  13. package/dist/es/ir/scene.d.ts.map +1 -1
  14. package/dist/es/primitive/ellipse.d.ts +2 -0
  15. package/dist/es/primitive/ellipse.d.ts.map +1 -1
  16. package/dist/es/primitive/path.d.ts +4 -0
  17. package/dist/es/primitive/path.d.ts.map +1 -1
  18. package/dist/es/primitive/rect.d.ts +2 -0
  19. package/dist/es/primitive/rect.d.ts.map +1 -1
  20. package/dist/es/primitive/text.d.ts +43 -13
  21. package/dist/es/primitive/text.d.ts.map +1 -1
  22. package/dist/lib/compile/node.cjs +112 -28
  23. package/dist/lib/compile/node.d.ts +32 -6
  24. package/dist/lib/compile/node.d.ts.map +1 -1
  25. package/dist/lib/compile/text-metrics.d.ts +2 -2
  26. package/dist/lib/compile/text-metrics.d.ts.map +1 -1
  27. package/dist/lib/index.cjs +4 -0
  28. package/dist/lib/index.d.ts +4 -4
  29. package/dist/lib/index.d.ts.map +1 -1
  30. package/dist/lib/ir/node.cjs +74 -4
  31. package/dist/lib/ir/node.d.ts +286 -6
  32. package/dist/lib/ir/node.d.ts.map +1 -1
  33. package/dist/lib/ir/scene.d.ts +376 -16
  34. package/dist/lib/ir/scene.d.ts.map +1 -1
  35. package/dist/lib/primitive/ellipse.d.ts +2 -0
  36. package/dist/lib/primitive/ellipse.d.ts.map +1 -1
  37. package/dist/lib/primitive/path.d.ts +4 -0
  38. package/dist/lib/primitive/path.d.ts.map +1 -1
  39. package/dist/lib/primitive/rect.d.ts +2 -0
  40. package/dist/lib/primitive/rect.d.ts.map +1 -1
  41. package/dist/lib/primitive/text.d.ts +43 -13
  42. package/dist/lib/primitive/text.d.ts.map +1 -1
  43. package/package.json +1 -1
@@ -1,32 +1,62 @@
1
- /** 文本原语;measuredWidth/Height 由 Scene 编译阶段算好,下游直接信任 */
1
+ /**
2
+ * 行级字段——`<tspan>` 上可独立指定的属性。
3
+ * 块级(TextPrim 顶层)属性是默认值;行级未填字段走块级默认。
4
+ */
5
+ export type TextLine = {
6
+ /** 行内容(必填) */
7
+ text: string;
8
+ /** 行字号;未填走 TextPrim.fontSize */
9
+ fontSize?: number;
10
+ /** 行字体族;未填走 TextPrim.fontFamily */
11
+ fontFamily?: string;
12
+ /** 行字重;未填走 TextPrim.fontWeight */
13
+ fontWeight?: string | number;
14
+ /** 行字形;未填走 TextPrim.fontStyle */
15
+ fontStyle?: 'normal' | 'italic' | 'oblique';
16
+ /** 行颜色;未填走 TextPrim.fill */
17
+ fill?: string;
18
+ /** 行透明度 0~1;未填走 TextPrim.opacity */
19
+ opacity?: number;
20
+ };
21
+ /**
22
+ * 文本原语;measuredWidth / Height 由 Scene 编译阶段算好,下游直接信任。
23
+ *
24
+ * 多行:`lines` 至少 1 行;renderer 把每行画为 `<tspan>`,按 `lineHeight` 堆叠,
25
+ * 整块根据 `baseline` 在 (x, y) 锚点上下居中 / 顶 / 底对齐。
26
+ *
27
+ * 顶层 `fontSize` / `fontFamily` / `fontWeight` / `fontStyle` / `fill` / `opacity` 是默认值;
28
+ * 单行可在 `TextLine` 上覆盖(仅生效于该行 `<tspan>`)。
29
+ */
2
30
  export type TextPrim = {
3
31
  /** 类型判别符 */
4
32
  type: 'text';
5
- /** 锚点横坐标(具体含义由 align 决定) */
33
+ /** 锚点横坐标(具体含义由 align 决定);多行下作为每行 `<tspan>` 的 x */
6
34
  x: number;
7
35
  /** 锚点纵坐标(具体含义由 baseline 决定) */
8
36
  y: number;
9
- /** 文本内容 */
10
- content: string;
11
- /** 字号 */
37
+ /** 文本行(至少 1 行);单行节点也用 `[{ text: 'Hello' }]` 形式 */
38
+ lines: Array<TextLine>;
39
+ /** 块级默认字号 */
12
40
  fontSize: number;
13
- /** 字体族 */
41
+ /** 块级默认字体族 */
14
42
  fontFamily?: string;
15
- /** 字重 */
43
+ /** 块级默认字重 */
16
44
  fontWeight?: string | number;
17
- /** 字形 */
18
- fontStyle?: 'normal' | 'italic';
45
+ /** 块级默认字形 */
46
+ fontStyle?: 'normal' | 'italic' | 'oblique';
19
47
  /** 水平对齐:start / middle / end 锚点位置 */
20
48
  align: 'start' | 'middle' | 'end';
21
49
  /** 垂直基线对齐方式 */
22
50
  baseline: 'top' | 'middle' | 'bottom' | 'alphabetic';
23
- /** 编译期算好的文字宽度(user units */
51
+ /** 行高(user units);多行下相邻 `<tspan>` 的垂直距离 */
52
+ lineHeight: number;
53
+ /** 编译期算好的整块文字宽度(user units,= max line width) */
24
54
  measuredWidth: number;
25
- /** 编译期算好的文字高度(user units) */
55
+ /** 编译期算好的整块文字高度(user units,≈ lines × lineHeight) */
26
56
  measuredHeight: number;
27
- /** 文字颜色 */
57
+ /** 块级默认文字颜色 */
28
58
  fill?: string;
29
- /** 整体透明度 0~1 */
59
+ /** 块级默认透明度 0~1 */
30
60
  opacity?: number;
31
61
  };
32
62
  //# sourceMappingURL=text.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/primitive/text.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,MAAM,MAAM,QAAQ,GAAG;IACrB,YAAY;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,+BAA+B;IAC/B,CAAC,EAAE,MAAM,CAAC;IACV,WAAW;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS;IACT,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,SAAS;IACT,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAChC,qCAAqC;IACrC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClC,eAAe;IACf,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAAC;IACrD,6BAA6B;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/primitive/text.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,cAAc;IACd,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,iCAAiC;IACjC,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,YAAY;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,CAAC,EAAE,MAAM,CAAC;IACV,+BAA+B;IAC/B,CAAC,EAAE,MAAM,CAAC;IACV,kDAAkD;IAClD,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvB,aAAa;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,aAAa;IACb,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,qCAAqC;IACrC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClC,eAAe;IACf,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAAC;IACrD,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC"}
@@ -6,8 +6,21 @@ const require_position = require("./position.cjs");
6
6
  //#region src/compile/node.ts
7
7
  var DEFAULT_FONT_SIZE = 14;
8
8
  var DEFAULT_PADDING = 8;
9
+ var DEFAULT_LINE_HEIGHT_FACTOR = 1.2;
9
10
  var DEG_TO_RAD = Math.PI / 180;
10
11
  var SQRT2 = Math.SQRT2;
12
+ /** dashed 预设:SVG stroke-dasharray "4 2"——4 px 实线 + 2 px 间隙循环 */
13
+ var DASHED_PATTERN = "4 2";
14
+ /** dotted 预设:SVG stroke-dasharray "1 2"——1 px 圆点 + 2 px 间隙 */
15
+ var DOTTED_PATTERN = "1 2";
16
+ /** 解析 dashed / dotted / dashArray 优先级:dashArray > dashed > dotted */
17
+ var resolveDashArray = (dashArray, dashed, dotted) => {
18
+ if (dashArray !== void 0) return dashArray;
19
+ if (dashed) return DASHED_PATTERN;
20
+ if (dotted) return DOTTED_PATTERN;
21
+ };
22
+ /** IR `align` ('left' | 'center' | 'right') → SVG textAnchor ('start' | 'middle' | 'end') */
23
+ var alignToTextAnchor = (a) => a === "left" ? "start" : a === "right" ? "end" : "middle";
11
24
  /** 由 layout 构造的 Rect(带 margin 扩张) */
12
25
  var rectOf = (layout, marginAdd) => ({
13
26
  x: layout.rect.x,
@@ -90,14 +103,52 @@ var angleBoundaryOf = (layout, angleDeg) => {
90
103
  * - 透传 margin / 样式属性
91
104
  */
92
105
  var layoutNode = (node, measureText, nodeIndex) => {
93
- const fontSize = node.fontSize ?? DEFAULT_FONT_SIZE;
94
- const padding = node.padding ?? DEFAULT_PADDING;
95
- const metrics = node.text ? measureText(node.text, { size: fontSize }) : {
96
- width: 0,
97
- height: 0
98
- };
99
- const innerHalfW = Math.max(metrics.width / 2 + padding, padding);
100
- const innerHalfH = Math.max(metrics.height / 2 + padding, padding);
106
+ const sx = node.xScale ?? node.scale ?? 1;
107
+ const sy = node.yScale ?? node.scale ?? 1;
108
+ const fontScale = Math.min(sx, sy);
109
+ const baseFontSize = node.font?.size ?? DEFAULT_FONT_SIZE;
110
+ const fontSize = baseFontSize * fontScale;
111
+ const fontFamily = node.font?.family;
112
+ const fontWeight = node.font?.weight;
113
+ const fontStyle = node.font?.style;
114
+ const xSep = (node.innerXSep ?? node.padding ?? DEFAULT_PADDING) * sx;
115
+ const ySep = (node.innerYSep ?? node.padding ?? DEFAULT_PADDING) * sy;
116
+ const outerSep = (node.outerSep ?? node.margin ?? 0) * Math.max(sx, sy);
117
+ const lineHeight = (node.lineHeight ?? baseFontSize * DEFAULT_LINE_HEIGHT_FACTOR) * sy;
118
+ const align = alignToTextAnchor(node.align ?? "center");
119
+ const rawLines = node.text === void 0 ? void 0 : typeof node.text === "string" ? [node.text] : node.text;
120
+ let textWidth = 0;
121
+ let textHeight = 0;
122
+ let lines;
123
+ if (rawLines) {
124
+ lines = rawLines.map((spec) => {
125
+ const isObj = typeof spec !== "string";
126
+ const text = isObj ? spec.text : spec;
127
+ const lineFont = isObj ? spec.font : void 0;
128
+ const m = measureText(text, {
129
+ size: lineFont?.size ?? fontSize,
130
+ family: lineFont?.family ?? fontFamily,
131
+ weight: lineFont?.weight ?? fontWeight,
132
+ style: lineFont?.style ?? fontStyle
133
+ });
134
+ if (m.width > textWidth) textWidth = m.width;
135
+ const out = { text };
136
+ if (isObj) {
137
+ if (spec.fill !== void 0) out.fill = spec.fill;
138
+ if (spec.opacity !== void 0) out.opacity = spec.opacity;
139
+ if (lineFont?.size !== void 0) out.fontSize = lineFont.size;
140
+ if (lineFont?.family !== void 0) out.fontFamily = lineFont.family;
141
+ if (lineFont?.weight !== void 0) out.fontWeight = lineFont.weight;
142
+ if (lineFont?.style !== void 0) out.fontStyle = lineFont.style;
143
+ }
144
+ return out;
145
+ });
146
+ textHeight = lines.length * lineHeight;
147
+ }
148
+ const minW = node.minimumWidth ?? node.minimumSize ?? 0;
149
+ const minH = node.minimumHeight ?? node.minimumSize ?? 0;
150
+ const innerHalfW = Math.max(textWidth / 2 + xSep, xSep, minW / 2);
151
+ const innerHalfH = Math.max(textHeight / 2 + ySep, ySep, minH / 2);
101
152
  const shape = node.shape ?? "rectangle";
102
153
  let boundsHalfW;
103
154
  let boundsHalfH;
@@ -135,14 +186,25 @@ var layoutNode = (node, measureText, nodeIndex) => {
135
186
  rotate: rotateDeg * DEG_TO_RAD
136
187
  },
137
188
  rotateDeg,
138
- margin: node.margin ?? 0,
139
- text: node.text,
140
- textWidth: metrics.width,
141
- textHeight: metrics.height,
189
+ margin: outerSep,
190
+ lines,
191
+ textWidth,
192
+ textHeight,
193
+ align,
194
+ lineHeight,
142
195
  fontSize,
196
+ fontFamily,
197
+ fontWeight,
198
+ fontStyle,
143
199
  fill: node.fill,
200
+ fillOpacity: node.fillOpacity,
144
201
  stroke: node.stroke,
145
- strokeWidth: node.strokeWidth
202
+ strokeOpacity: node.drawOpacity,
203
+ strokeWidth: node.strokeWidth,
204
+ strokeDasharray: resolveDashArray(node.dashArray, node.dashed, node.dotted),
205
+ roundedCorners: node.roundedCorners,
206
+ textColor: node.textColor,
207
+ opacity: node.opacity
146
208
  };
147
209
  };
148
210
  /** rectangle shape 的 RectPrim */
@@ -156,8 +218,13 @@ var emitRectShape = (layout, round) => {
156
218
  width: round(layout.rect.width),
157
219
  height: round(layout.rect.height),
158
220
  fill: layout.fill ?? "transparent",
221
+ fillOpacity: layout.fillOpacity,
159
222
  stroke: layout.stroke ?? "currentColor",
160
- strokeWidth: layout.strokeWidth ?? 1
223
+ strokeOpacity: layout.strokeOpacity,
224
+ strokeWidth: layout.strokeWidth ?? 1,
225
+ strokeDasharray: layout.strokeDasharray,
226
+ cornerRadius: layout.roundedCorners,
227
+ opacity: layout.opacity
161
228
  };
162
229
  };
163
230
  /** circle / ellipse shape 的 EllipsePrim(圆形 rx=ry) */
@@ -168,8 +235,12 @@ var emitEllipseShape = (layout, round) => ({
168
235
  rx: round(layout.rect.width / 2),
169
236
  ry: round(layout.rect.height / 2),
170
237
  fill: layout.fill ?? "transparent",
238
+ fillOpacity: layout.fillOpacity,
171
239
  stroke: layout.stroke ?? "currentColor",
172
- strokeWidth: layout.strokeWidth ?? 1
240
+ strokeOpacity: layout.strokeOpacity,
241
+ strokeWidth: layout.strokeWidth ?? 1,
242
+ strokeDasharray: layout.strokeDasharray,
243
+ opacity: layout.opacity
173
244
  });
174
245
  /** diamond shape 的 PathPrim(4 顶点 + Z 闭合) */
175
246
  var emitDiamondShape = (layout, round) => {
@@ -182,8 +253,12 @@ var emitDiamondShape = (layout, round) => {
182
253
  type: "path",
183
254
  d: `M ${round(e[0])} ${round(e[1])} L ${round(n[0])} ${round(n[1])} L ${round(w[0])} ${round(w[1])} L ${round(s[0])} ${round(s[1])} Z`,
184
255
  fill: layout.fill ?? "transparent",
256
+ fillOpacity: layout.fillOpacity,
185
257
  stroke: layout.stroke ?? "currentColor",
186
- strokeWidth: layout.strokeWidth ?? 1
258
+ strokeOpacity: layout.strokeOpacity,
259
+ strokeWidth: layout.strokeWidth ?? 1,
260
+ strokeDasharray: layout.strokeDasharray,
261
+ opacity: layout.opacity
187
262
  };
188
263
  };
189
264
  /**
@@ -209,18 +284,27 @@ var emitNodePrimitives = (layout, round) => {
209
284
  break;
210
285
  }
211
286
  const inner = [shapePrim];
212
- if (layout.text) inner.push({
213
- type: "text",
214
- x: round(layout.rect.x),
215
- y: round(layout.rect.y),
216
- content: layout.text,
217
- fontSize: layout.fontSize,
218
- align: "middle",
219
- baseline: "middle",
220
- fill: "currentColor",
221
- measuredWidth: round(layout.textWidth),
222
- measuredHeight: round(layout.textHeight)
223
- });
287
+ if (layout.lines) {
288
+ const halfBlockW = layout.textWidth / 2;
289
+ const xOffset = layout.align === "start" ? -halfBlockW : layout.align === "end" ? halfBlockW : 0;
290
+ inner.push({
291
+ type: "text",
292
+ x: round(layout.rect.x + xOffset),
293
+ y: round(layout.rect.y),
294
+ lines: layout.lines,
295
+ fontSize: layout.fontSize,
296
+ fontFamily: layout.fontFamily,
297
+ fontWeight: layout.fontWeight,
298
+ fontStyle: layout.fontStyle,
299
+ align: layout.align,
300
+ baseline: "middle",
301
+ lineHeight: round(layout.lineHeight),
302
+ fill: layout.textColor ?? "currentColor",
303
+ opacity: layout.opacity,
304
+ measuredWidth: round(layout.textWidth),
305
+ measuredHeight: round(layout.textHeight)
306
+ });
307
+ }
224
308
  if (layout.rotateDeg === 0) return inner;
225
309
  return [{
226
310
  type: "group",
@@ -1,7 +1,7 @@
1
1
  import { Position } from '../geometry/point';
2
2
  import { Rect, RectAnchor } from '../geometry/rect';
3
3
  import { IRNode, NodeShape } from '../ir';
4
- import { ScenePrimitive } from '../primitive';
4
+ import { ScenePrimitive, TextLine } from '../primitive';
5
5
  import { TextMeasurer } from './text-metrics';
6
6
  export type NodeLayout = {
7
7
  /** 节点 id(如 IR Node 提供);其他位置可通过 id 引用本节点 */
@@ -22,20 +22,46 @@ export type NodeLayout = {
22
22
  rotateDeg: number;
23
23
  /** 外边距(user units,≥ 0);path 附着到形状外扩 margin 的虚拟边界上 */
24
24
  margin: number;
25
- /** 节点文本内容;空字符串视为无文本(undefined) */
26
- text?: string;
27
- /** 文本宽度(user units),由 TextMeasurer 算出 */
25
+ /**
26
+ * 节点文本行;undefined 表示无文本,否则非空数组。
27
+ * 每行可带覆盖样式(fill / opacity / fontSize / fontFamily / fontWeight / fontStyle);
28
+ * 未覆盖的字段在 emit 阶段不写出,由下游走 TextPrim 块级默认。
29
+ */
30
+ lines?: Array<TextLine>;
31
+ /** 文本块宽度(user units)= max(per-line measureText.width) */
28
32
  textWidth: number;
29
- /** 文本高度(user units),由 TextMeasurer 算出 */
33
+ /** 文本块高度(user units)≈ lines × lineHeight */
30
34
  textHeight: number;
31
- /** 文本字号(user units) */
35
+ /** 文本对齐(已映射到 SVG textAnchor 三态);emit 时透传给 TextPrim.align */
36
+ align: 'start' | 'middle' | 'end';
37
+ /** 行高(user units),已应用默认值;emit 时透传给 TextPrim.lineHeight */
38
+ lineHeight: number;
39
+ /** 文本字号(user units),已应用默认值 */
32
40
  fontSize: number;
41
+ /** 字体族;CSS font-family;emit 时透传给 TextPrim */
42
+ fontFamily?: string;
43
+ /** 字重;emit 时透传给 TextPrim */
44
+ fontWeight?: string | number;
45
+ /** 字形:normal / italic / oblique;emit 时透传给 TextPrim */
46
+ fontStyle?: 'normal' | 'italic' | 'oblique';
33
47
  /** 节点背景色,CSS 颜色字符串;emit 时用 'transparent' 兜底 */
34
48
  fill?: string;
49
+ /** 节点填充透明度 0~1;透传 shape primitive */
50
+ fillOpacity?: number;
35
51
  /** 节点边框色,CSS 颜色字符串;emit 时用 'currentColor' 兜底 */
36
52
  stroke?: string;
53
+ /** 节点描边透明度 0~1;TikZ `draw opacity`,透传 shape primitive */
54
+ strokeOpacity?: number;
37
55
  /** 节点边框宽度(user units);emit 时用 1 兜底 */
38
56
  strokeWidth?: number;
57
+ /** SVG stroke-dasharray 字符串;compile 已把 dashed / dotted 预设解析为具体 pattern */
58
+ strokeDasharray?: string;
59
+ /** rectangle shape 的圆角半径(user units);非 rect shape 该字段无效 */
60
+ roundedCorners?: number;
61
+ /** 文字颜色;emit 时透传给 TextPrim.fill,兜底 'currentColor' */
62
+ textColor?: string;
63
+ /** 整节点透明度 0~1;emit 时同时挂 shape 与 text primitive */
64
+ opacity?: number;
39
65
  };
40
66
  /**
41
67
  * 取节点 shape 在 toward 方向上的"附着点"——path 端点贴边用。
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAOnD,MAAM,MAAM,UAAU,GAAG;IACvB,2CAA2C;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,IAAI,EAAE,IAAI,CAAC;IACX,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAsCF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,QAAQ,QAAQ,KAAG,QAYtE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,UAAU,EAAE,MAAM,UAAU,KAAG,QAW/D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,UAAU,MAAM,KAAG,QActE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,aAAa,YAAY,EACzB,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,KACjC,UAmEF,CAAC;AAyDF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,UAAU,EAClB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC3B,KAAK,CAAC,cAAc,CAyCtB,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAc,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA8BnD,MAAM,MAAM,UAAU,GAAG;IACvB,2CAA2C;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,IAAI,EAAE,IAAI,CAAC;IACX,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClC,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,sDAAsD;IACtD,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAsCF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,QAAQ,QAAQ,KAAG,QAYtE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,UAAU,EAAE,MAAM,UAAU,KAAG,QAW/D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,UAAU,MAAM,KAAG,QActE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,aAAa,YAAY,EACzB,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,KACjC,UAgJF,CAAC;AAsEF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,UAAU,EAClB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC3B,KAAK,CAAC,cAAc,CAoDtB,CAAC"}
@@ -6,8 +6,8 @@ export type FontSpec = {
6
6
  size: number;
7
7
  /** 字重;可以是 'normal' / 'bold' / 100~900 数字等 */
8
8
  weight?: string | number;
9
- /** 字形:normal italic */
10
- style?: 'normal' | 'italic';
9
+ /** 字形:normal / italic / oblique */
10
+ style?: 'normal' | 'italic' | 'oblique';
11
11
  };
12
12
  /** 文字度量结果:宽高 + 可选的基线 ascent/descent */
13
13
  export type TextMetrics = {
@@ -1 +1 @@
1
- {"version":3,"file":"text-metrics.d.ts","sourceRoot":"","sources":["../../../src/compile/text-metrics.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,MAAM,MAAM,QAAQ,GAAG;IACrB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,yBAAyB;IACzB,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC7B,CAAC;AAEF,uCAAuC;AACvC,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,WAAW,CAAC;AAEzE,uCAAuC;AACvC,eAAO,MAAM,gBAAgB,EAAE,YAG7B,CAAC"}
1
+ {"version":3,"file":"text-metrics.d.ts","sourceRoot":"","sources":["../../../src/compile/text-metrics.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,MAAM,MAAM,QAAQ,GAAG;IACrB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,mCAAmC;IACnC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,uCAAuC;AACvC,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,WAAW,CAAC;AAEzE,uCAAuC;AACvC,eAAO,MAAM,gBAAgB,EAAE,YAG7B,CAAC"}
@@ -22,10 +22,14 @@ exports.ChildSchema = require_scene.ChildSchema;
22
22
  exports.CycleStepSchema = require_step.CycleStepSchema;
23
23
  exports.DrawWay = require_parseWay.DrawWay;
24
24
  exports.FoldStepSchema = require_step.FoldStepSchema;
25
+ exports.FontSchema = require_node.FontSchema;
26
+ exports.LineSpecSchema = require_node.LineSpecSchema;
25
27
  exports.LineStepSchema = require_step.LineStepSchema;
26
28
  exports.MoveStepSchema = require_step.MoveStepSchema;
27
29
  exports.NODE_SHAPES = require_node.NODE_SHAPES;
30
+ exports.NODE_TEXT_ALIGNS = require_node.NODE_TEXT_ALIGNS;
28
31
  exports.NodeSchema = require_node.NodeSchema;
32
+ exports.NodeTextSchema = require_node.NodeTextSchema;
29
33
  exports.PathSchema = require_path.PathSchema;
30
34
  exports.PolarPositionSchema = require_polar_position.PolarPositionSchema;
31
35
  exports.PositionSchema = require_position.PositionSchema;
@@ -6,10 +6,10 @@
6
6
  *
7
7
  * 本包零 React、零 DOM 依赖。
8
8
  */
9
- export { PositionSchema, PolarPositionSchema, TargetSchema, MoveStepSchema, LineStepSchema, FoldStepSchema, CycleStepSchema, StepSchema, NodeSchema, PathSchema, ChildSchema, SceneSchema, CURRENT_IR_VERSION, } from './ir';
10
- export type { IRPosition, IRTarget, IRMoveStep, IRLineStep, IRFoldStep, IRCycleStep, IRStep, IRNode, IRPath, IRChild, IR, ArrowShape, NodeShape, } from './ir';
11
- export { ARROW_SHAPES, NODE_SHAPES } from './ir';
12
- export type { ScenePrimitive, RectPrim, EllipsePrim, TextPrim, PathPrim, GroupPrim, ViewBox, Scene, } from './primitive';
9
+ export { PositionSchema, PolarPositionSchema, TargetSchema, MoveStepSchema, LineStepSchema, FoldStepSchema, CycleStepSchema, StepSchema, NodeSchema, FontSchema, NodeTextSchema, LineSpecSchema, PathSchema, ChildSchema, SceneSchema, CURRENT_IR_VERSION, } from './ir';
10
+ export type { IRPosition, IRTarget, IRMoveStep, IRLineStep, IRFoldStep, IRCycleStep, IRStep, IRNode, IRFont, IRLineSpec, IRPath, IRChild, IR, ArrowShape, NodeShape, NodeTextAlign, } from './ir';
11
+ export { ARROW_SHAPES, NODE_SHAPES, NODE_TEXT_ALIGNS } from './ir';
12
+ export type { ScenePrimitive, RectPrim, EllipsePrim, TextPrim, TextLine, PathPrim, GroupPrim, ViewBox, Scene, } from './primitive';
13
13
  export type { FontSpec, TextMetrics, TextMeasurer, CompileOptions, } from './compile';
14
14
  export { fallbackMeasurer, compileToScene } from './compile';
15
15
  export type { WayItem, WayDSL, WayCycle, WayVia } from './parsers';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,GACnB,MAAM,MAAM,CAAC;AACd,YAAY,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,MAAM,EACN,OAAO,EACP,EAAE,EACF,UAAU,EACV,SAAS,GACV,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAGjD,YAAY,EACV,cAAc,EACd,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,OAAO,EACP,KAAK,GACN,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG7D,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAI9C,YAAY,EACV,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,MAAM,EACN,YAAY,EACZ,OAAO,EACP,aAAa,EACb,OAAO,EACP,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxF,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,UAAU,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,GACnB,MAAM,MAAM,CAAC;AACd,YAAY,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,MAAM,EACN,UAAU,EACV,MAAM,EACN,OAAO,EACP,EAAE,EACF,UAAU,EACV,SAAS,EACT,aAAa,GACd,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAGnE,YAAY,EACV,cAAc,EACd,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,OAAO,EACP,KAAK,GACN,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG7D,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAI9C,YAAY,EACV,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,MAAM,EACN,YAAY,EACZ,OAAO,EACP,aAAa,EACb,OAAO,EACP,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxF,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
@@ -23,20 +23,90 @@ var NODE_SHAPES = {
23
23
  ellipse: "ellipse",
24
24
  diamond: "diamond"
25
25
  };
26
+ /**
27
+ * 节点字体规格——family / size / weight / style 全部可选;
28
+ * 单字段透传到 SVG `<text>` 的 `font-*` 属性 / `font-size`。
29
+ *
30
+ * 取代 alpha.1 的标量 `fontSize` 字段(已删)。
31
+ */
32
+ var FontSchema = zod.z.object({
33
+ family: zod.z.string().optional().describe("CSS font-family string, e.g. \"serif\", \"monospace\", \"Inter, sans-serif\""),
34
+ size: zod.z.number().positive().optional().describe("Font size in user units; falls back to the renderer default when omitted"),
35
+ weight: zod.z.union([zod.z.enum(["normal", "bold"]), zod.z.number()]).optional().describe("CSS font-weight: keyword `normal` / `bold` or numeric 100..900"),
36
+ style: zod.z.enum([
37
+ "normal",
38
+ "italic",
39
+ "oblique"
40
+ ]).optional().describe("CSS font-style")
41
+ }).describe("Font properties for the node text label; all fields optional, nested object form (replaces the alpha.1 `fontSize` scalar).");
42
+ /**
43
+ * 单行文本规格——纯字符串走块级默认样式;对象形式可对该行覆盖 fill / opacity / font。
44
+ *
45
+ * 行级覆盖只生效于本行的 `<tspan>`:
46
+ * - `fill`:仅这一行颜色
47
+ * - `opacity`:仅这一行 0~1 透明度
48
+ * - `font`:family / size / weight / style 任意子集;未填字段继承块级 font
49
+ *
50
+ * 块级 `align` / `lineHeight` 不可被行覆盖(多行块整体属性)。
51
+ */
52
+ var LineSpecSchema = zod.z.union([zod.z.string(), zod.z.object({
53
+ text: zod.z.string().describe("Line content"),
54
+ fill: zod.z.string().optional().describe("Per-line text color; overrides block default"),
55
+ opacity: zod.z.number().min(0).max(1).optional().describe("Per-line opacity 0..1"),
56
+ font: FontSchema.optional().describe("Per-line font overrides; missing fields inherit from block-level `font`")
57
+ })]).describe("Single line of text: bare string for default styling, or an object with per-line `fill` / `opacity` / `font` overrides.");
58
+ /**
59
+ * 节点文本——单行字符串或非空多行数组(每元素一个 LineSpec):
60
+ * - `'Hello'` 等价于 `[{ text: 'Hello' }]`,按一行渲染
61
+ * - `['Line 1', 'Line 2']` 两行无样式覆盖
62
+ * - `[{ text: 'Heading', fill: 'red', font: { weight: 'bold' } }, 'body']` 混排
63
+ *
64
+ * 选 `Array<LineSpec>` 而非 `'\n'` 字符串:JSON 友好(无 escape);行级覆盖天然落字段。
65
+ */
66
+ var NodeTextSchema = zod.z.union([zod.z.string(), zod.z.array(LineSpecSchema).min(1)]).describe("Text label rendered inside the node: a single string for one line, or a non-empty array of line specs (string for default, object for per-line overrides).");
67
+ /** 节点文本对齐(多行内文本对齐)——TikZ `align=` 同义词 */
68
+ var NODE_TEXT_ALIGNS = {
69
+ left: "left",
70
+ center: "center",
71
+ right: "right"
72
+ };
26
73
  var NodeSchema = zod.z.object({
27
74
  type: zod.z.literal("node").describe("Discriminator marking this child as a node"),
28
75
  id: zod.z.string().min(1).optional().describe("Optional unique id; required if any path needs to reference this node by string"),
29
76
  shape: zod.z.nativeEnum(NODE_SHAPES).optional().describe("Node visual shape; defaults to `rectangle`. The boundary fully contains text + padding (circumscribed for circle / ellipse / diamond)."),
30
77
  position: zod.z.union([require_position.PositionSchema, require_polar_position.PolarPositionSchema]).describe("Center point of the node content box; Cartesian [x, y] or polar (resolved at compile time)"),
31
78
  rotate: zod.z.number().optional().describe("Rotation in degrees around the node center; positive = clockwise (matches TikZ rotate=...)"),
32
- text: zod.z.string().optional().describe("Text label rendered inside the node; omit for an empty node"),
79
+ text: NodeTextSchema.optional(),
80
+ align: zod.z.nativeEnum(NODE_TEXT_ALIGNS).optional().describe("Multi-line text alignment within the text block; `left` / `center` / `right`. Defaults to `center` (matches TikZ)."),
81
+ lineHeight: zod.z.number().positive().optional().describe("Line height in user units; falls back to `font.size × 1.2` when omitted."),
33
82
  fill: zod.z.string().optional().describe("Background color of the node shape; any CSS color (e.g. \"lightblue\", \"#fafafa\", \"rgba(...)\")"),
83
+ fillOpacity: zod.z.number().min(0).max(1).optional().describe("Fill opacity 0..1; affects only the shape fill, leaves stroke / text alone."),
34
84
  stroke: zod.z.string().optional().describe("Border color of the node shape; any CSS color. Defaults to currentColor when omitted"),
85
+ drawOpacity: zod.z.number().min(0).max(1).optional().describe("Stroke opacity 0..1 (TikZ `draw opacity`); affects only the border."),
35
86
  strokeWidth: zod.z.number().optional().describe("Border width in user units; defaults to 1 when omitted"),
36
- padding: zod.z.number().optional().describe("Inner padding in user units between the text content and the node border"),
37
- margin: zod.z.number().nonnegative().optional().describe("Outer margin in user units: distance between the visual border and where paths attach. Lines stop this far from the border. Defaults to 0."),
38
- fontSize: zod.z.number().optional().describe("Text font size in user units; defaults to a fixed size for now (TikZ font sizes will be supported later)")
87
+ dashed: zod.z.boolean().optional().describe("Border style preset: dashed line (TikZ `dashed`); compiled to a default dash pattern. `dashArray` takes precedence."),
88
+ dotted: zod.z.boolean().optional().describe("Border style preset: dotted line (TikZ `dotted`); compiled to a default dot pattern. `dashArray` and `dashed` take precedence."),
89
+ dashArray: zod.z.string().optional().describe("Explicit SVG stroke-dasharray value (e.g. \"4 2\"); overrides `dashed` / `dotted`."),
90
+ roundedCorners: zod.z.number().nonnegative().optional().describe("Corner radius in user units; only effective on `rectangle` shape (rx / ry on `<rect>`)."),
91
+ minimumWidth: zod.z.number().nonnegative().optional().describe("Minimum visual border width in user units; floors the bounding box width."),
92
+ minimumHeight: zod.z.number().nonnegative().optional().describe("Minimum visual border height in user units; floors the bounding box height."),
93
+ minimumSize: zod.z.number().nonnegative().optional().describe("Symmetric alias for `minimumWidth` + `minimumHeight`; axis-specific fields take precedence."),
94
+ scale: zod.z.number().positive().optional().describe("Uniform scale factor; multiplies all node dimensions (border, padding, text, fontSize) at layout time. Affects path attachment positions."),
95
+ xScale: zod.z.number().positive().optional().describe("Horizontal scale factor; overrides `scale` for the X axis."),
96
+ yScale: zod.z.number().positive().optional().describe("Vertical scale factor; overrides `scale` for the Y axis."),
97
+ textColor: zod.z.string().optional().describe("Text label color; any CSS color. Defaults to `currentColor`."),
98
+ opacity: zod.z.number().min(0).max(1).optional().describe("Whole-node opacity 0..1; applies uniformly to shape and text."),
99
+ innerXSep: zod.z.number().nonnegative().optional().describe("Inner horizontal padding from text to border in user units. Falls back to `padding` then default."),
100
+ innerYSep: zod.z.number().nonnegative().optional().describe("Inner vertical padding from text to border in user units. Falls back to `padding` then default."),
101
+ outerSep: zod.z.number().nonnegative().optional().describe("Outer margin from border to path attachment point in user units; does NOT change the visible border. Falls back to `margin`."),
102
+ padding: zod.z.number().nonnegative().optional().describe("Symmetric inner padding (alias for `innerXSep` + `innerYSep`); axis-specific fields take precedence."),
103
+ margin: zod.z.number().nonnegative().optional().describe("Symmetric outer margin (alias for `outerSep`); axis-specific field takes precedence."),
104
+ font: FontSchema.optional().describe("Font spec for the inner text label (family / size / weight / style); all fields optional, all fall back to renderer defaults.")
39
105
  }).describe("Node primitive: a positioned, optionally textual shape (rectangle / circle / ellipse / diamond)");
40
106
  //#endregion
107
+ exports.FontSchema = FontSchema;
108
+ exports.LineSpecSchema = LineSpecSchema;
41
109
  exports.NODE_SHAPES = NODE_SHAPES;
110
+ exports.NODE_TEXT_ALIGNS = NODE_TEXT_ALIGNS;
42
111
  exports.NodeSchema = NodeSchema;
112
+ exports.NodeTextSchema = NodeTextSchema;