dishui 0.0.47 → 0.0.49

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 (82) hide show
  1. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +1 -2
  2. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
  3. package/dist/components/pro/CodeEditor/themes.js +0 -25
  4. package/dist/components/pro/CodeEditor/themes.js.map +1 -1
  5. package/dist/components/pro/CodeEditor/types.d.ts +1 -1
  6. package/dist/components/pro/Flow/Flow.js +500 -483
  7. package/dist/components/pro/Flow/Flow.js.map +1 -1
  8. package/dist/components/pro/Flow/FlowCanvas.js +526 -524
  9. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  10. package/dist/components/pro/Flow/canvas/GridRenderer.d.ts +3 -0
  11. package/dist/components/pro/Flow/canvas/GridRenderer.js +28 -23
  12. package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
  13. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js +18 -17
  14. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
  15. package/dist/components/pro/Flow/canvas/PixiApp.d.ts +2 -0
  16. package/dist/components/pro/Flow/canvas/PixiApp.js +14 -11
  17. package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
  18. package/dist/components/pro/Flow/constants.js +7 -7
  19. package/dist/components/pro/Flow/constants.js.map +1 -1
  20. package/dist/components/pro/Flow/context/FlowAIContext.d.ts +15 -0
  21. package/dist/components/pro/Flow/context/FlowAIContext.js +32 -0
  22. package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -0
  23. package/dist/components/pro/Flow/context/FlowUIContext.d.ts +4 -1
  24. package/dist/components/pro/Flow/context/FlowUIContext.js +58 -55
  25. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  26. package/dist/components/pro/Flow/edges/EdgeRenderer.js +22 -21
  27. package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
  28. package/dist/components/pro/Flow/hooks/useFlowImportExport.js +32 -32
  29. package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
  30. package/dist/components/pro/Flow/hooks/usePixiApp.d.ts +6 -1
  31. package/dist/components/pro/Flow/hooks/usePixiApp.js +49 -30
  32. package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
  33. package/dist/components/pro/Flow/index.d.ts +2 -0
  34. package/dist/components/pro/Flow/lines/FreehandTool.js +21 -20
  35. package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
  36. package/dist/components/pro/Flow/lines/GeometricLineTool.js +22 -18
  37. package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
  38. package/dist/components/pro/Flow/lines/LineRenderer.js +19 -18
  39. package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
  40. package/dist/components/pro/Flow/nodes/MediaContent.js +143 -124
  41. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  42. package/dist/components/pro/Flow/nodes/MediaOverlay.js +22 -17
  43. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  44. package/dist/components/pro/Flow/nodes/NodeRenderer.js +77 -76
  45. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  46. package/dist/components/pro/Flow/nodes/aiClient.d.ts +22 -0
  47. package/dist/components/pro/Flow/nodes/aiClient.js +107 -54
  48. package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
  49. package/dist/components/pro/Flow/nodes/svgIcons.js +6 -6
  50. package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
  51. package/dist/components/pro/Flow/panels/AIPanel.d.ts +2 -0
  52. package/dist/components/pro/Flow/panels/AIPanel.js +498 -0
  53. package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -0
  54. package/dist/components/pro/Flow/panels/FlowPanelGroup.js +51 -39
  55. package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
  56. package/dist/components/pro/Flow/panels/FlowToolbar.js +91 -85
  57. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  58. package/dist/components/pro/Flow/panels/InspectorPanel.js +372 -332
  59. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  60. package/dist/components/pro/Flow/panels/OutlinePanel.js +28 -27
  61. package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
  62. package/dist/components/pro/Flow/panels/ShapePalette.js +107 -104
  63. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  64. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +1 -0
  65. package/dist/components/pro/Flow/panels/toolbarIcons.js +25 -20
  66. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  67. package/dist/components/pro/Flow/types.d.ts +13 -0
  68. package/dist/components/pro/Flow/types.js.map +1 -1
  69. package/dist/components/pro/Flow/utils/themeColor.d.ts +87 -0
  70. package/dist/components/pro/Flow/utils/themeColor.js +212 -0
  71. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -0
  72. package/dist/contexts/AppContext.d.ts +1 -1
  73. package/dist/contexts/AppContext.js +28 -29
  74. package/dist/contexts/AppContext.js.map +1 -1
  75. package/dist/dishui.css +1 -1
  76. package/dist/favicon.svg +10 -0
  77. package/dist/flow.js +56 -51
  78. package/dist/styles/themeStyles.js +6 -11
  79. package/dist/styles/themeStyles.js.map +1 -1
  80. package/dist/utils/themes.js +3 -23
  81. package/dist/utils/themes.js.map +1 -1
  82. package/package.json +17 -18
@@ -1,10 +1,11 @@
1
- import { drawRoundRectBorder as M, shapeDrawers as k } from "./shapes.js";
2
- import { createNodeText as O, formatIconLabel as T, normalizeIconLabelPlacement as I, updateNodeText as N } from "./NodeText.js";
3
- import { createHandleGraphics as A, getHandlePositions as R, updateHandleGraphics as L } from "./NodeHandles.js";
4
- import { getFlipScale as z, getRotationRad as H } from "./nodeUtils.js";
5
- import { getIconTexture as B, subscribeIconTextureReady as G } from "./svgIconTexture.js";
6
- import { Container as _, Graphics as W, Sprite as P, Text as D } from "pixi.js";
7
- var j = class {
1
+ import { resolveThemeColor as m } from "../utils/themeColor.js";
2
+ import { drawRoundRectBorder as T, shapeDrawers as S } from "./shapes.js";
3
+ import { createNodeText as I, formatIconLabel as N, normalizeIconLabelPlacement as A, updateNodeText as L } from "./NodeText.js";
4
+ import { createHandleGraphics as z, getHandlePositions as W, updateHandleGraphics as H } from "./NodeHandles.js";
5
+ import { getFlipScale as B, getRotationRad as G } from "./nodeUtils.js";
6
+ import { getIconTexture as P, subscribeIconTextureReady as D } from "./svgIconTexture.js";
7
+ import { Container as R, Graphics as M, Sprite as F, Text as V } from "pixi.js";
8
+ var K = class {
8
9
  world;
9
10
  nodeLayer;
10
11
  nodes = /* @__PURE__ */ new Map();
@@ -14,25 +15,25 @@ var j = class {
14
15
  this._dynamicOffset = (this._dynamicOffset + s * 0.06) % 1e3;
15
16
  }
16
17
  constructor(s) {
17
- this.world = s, this.nodeLayer = new _({
18
+ this.world = s, this.nodeLayer = new R({
18
19
  label: "nodes",
19
20
  sortableChildren: !0
20
- }), this.world.addChild(this.nodeLayer), this._unsubscribeTextureReady = G(() => this._resync?.());
21
+ }), this.world.addChild(this.nodeLayer), this._unsubscribeTextureReady = D(() => this._resync?.());
21
22
  }
22
23
  _resync = null;
23
- sync(s, t, l, f, d) {
24
+ sync(s, t, l, c, d) {
24
25
  const r = /* @__PURE__ */ new Set();
25
- this._resync = () => this.sync(s, t, l, f, d);
26
- const e = f ?? (() => {
27
- const i = s.filter((h) => h.type === "animAnchor").sort((h, o) => (h.data.animIndex ?? 0) - (o.data.animIndex ?? 0)), a = /* @__PURE__ */ new Map();
28
- return i.forEach((h, o) => a.set(h.id, o + 1)), a;
26
+ this._resync = () => this.sync(s, t, l, c, d);
27
+ const i = c ?? (() => {
28
+ const e = s.filter((h) => h.type === "animAnchor").sort((h, o) => (h.data.animIndex ?? 0) - (o.data.animIndex ?? 0)), a = /* @__PURE__ */ new Map();
29
+ return e.forEach((h, o) => a.set(h.id, o + 1)), a;
29
30
  })();
30
- for (const i of s) {
31
- r.add(i.id);
32
- let a = this.nodes.get(i.id);
33
- a || (a = this._createNode(i), this.nodes.set(i.id, a)), this._updateNode(a, i, t.has(i.id), l === i.id, e.get(i.id), d);
31
+ for (const e of s) {
32
+ r.add(e.id);
33
+ let a = this.nodes.get(e.id);
34
+ a || (a = this._createNode(e), this.nodes.set(e.id, a)), this._updateNode(a, e, t.has(e.id), l === e.id, i.get(e.id), d);
34
35
  }
35
- for (const [i, a] of this.nodes) r.has(i) || (this.nodeLayer.removeChild(a.container), a.container.destroy({ children: !0 }), this.nodes.delete(i));
36
+ for (const [e, a] of this.nodes) r.has(e) || (this.nodeLayer.removeChild(a.container), a.container.destroy({ children: !0 }), this.nodes.delete(e));
36
37
  }
37
38
  getNodeContainer(s) {
38
39
  return this.nodes.get(s);
@@ -41,25 +42,25 @@ var j = class {
41
42
  return [...this.nodes.values()];
42
43
  }
43
44
  _createNode(s) {
44
- const t = new _({ label: `node-${s.id}` });
45
+ const t = new R({ label: `node-${s.id}` });
45
46
  t.eventMode = "static", t.cursor = "pointer";
46
- const l = new _({ label: "svg-transform" });
47
+ const l = new R({ label: "svg-transform" });
47
48
  t.addChild(l);
48
- const f = new W();
49
- f.label = "sub-canvas-glow", t.addChild(f);
50
- const d = new W();
49
+ const c = new M();
50
+ c.label = "sub-canvas-glow", t.addChild(c);
51
+ const d = new M();
51
52
  d.label = "shape", t.addChild(d);
52
- const r = new P();
53
+ const r = new F();
53
54
  r.label = "svg-icon", r.anchor.set(0.5, 0.5), r.visible = !1, t.addChild(r);
54
- const e = O({
55
+ const i = I({
55
56
  label: s.data.label,
56
- color: s.data.labelColor ?? s.data.color,
57
+ color: m(s.data.labelColor ?? s.data.color, "#111827"),
57
58
  fontSize: s.data.fontSize,
58
59
  width: s.width,
59
60
  height: s.height
60
61
  });
61
- t.addChild(e);
62
- const i = R(s.width, s.height), a = A(t, i, !1), h = new D({
62
+ t.addChild(i);
63
+ const e = W(s.width, s.height), a = z(t, e, !1), h = new V({
63
64
  text: "",
64
65
  style: {
65
66
  fontFamily: "system-ui, sans-serif",
@@ -73,105 +74,105 @@ var j = class {
73
74
  shape: d,
74
75
  svgTransform: l,
75
76
  icon: r,
76
- text: e,
77
+ text: i,
77
78
  animBadge: h,
78
79
  handles: a,
79
- handleDefs: i,
80
+ handleDefs: e,
80
81
  nodeId: s.id,
81
- subCanvasGlow: f
82
+ subCanvasGlow: c
82
83
  };
83
84
  }
84
- _updateNode(s, t, l, f, d, r) {
85
- const { container: e, svgTransform: i, shape: a, icon: h, text: o, animBadge: b, handles: g, subCanvasGlow: y } = s, w = t.type === "shapeSvg", u = H(t.data), m = z(t.data);
86
- e.zIndex = t.zIndex ?? 0, w ? (a.parent !== i && i.addChild(a), h.parent !== i && i.addChild(h), g.parent !== i && i.addChild(g), e.position.set(t.position.x, t.position.y), e.rotation = 0, e.scale.set(1, 1), e.pivot.set(0, 0), i.position.set(t.width / 2, t.height / 2), i.pivot.set(t.width / 2, t.height / 2), i.rotation = u, i.scale.set(m.sx, m.sy)) : (a.parent !== e && e.addChildAt(a, Math.min(2, e.children.length)), h.parent !== e && e.addChild(h), g.parent !== e && e.addChild(g), i.rotation = 0, i.scale.set(1, 1), e.position.set(t.position.x, t.position.y), e.rotation = u, e.scale.set(m.sx, m.sy), u !== 0 || m.sx < 0 || m.sy < 0 ? (e.pivot.set(t.width / 2, t.height / 2), e.position.set(t.position.x + t.width / 2, t.position.y + t.height / 2)) : e.pivot.set(0, 0));
87
- const S = t.type === "mediaNode", x = t.type === "animAnchor";
85
+ _updateNode(s, t, l, c, d, r) {
86
+ const { container: i, svgTransform: e, shape: a, icon: h, text: o, animBadge: b, handles: g, subCanvasGlow: y } = s, w = t.type === "shapeSvg", x = G(t.data), u = B(t.data);
87
+ i.zIndex = t.zIndex ?? 0, w ? (a.parent !== e && e.addChild(a), h.parent !== e && e.addChild(h), g.parent !== e && e.addChild(g), i.position.set(t.position.x, t.position.y), i.rotation = 0, i.scale.set(1, 1), i.pivot.set(0, 0), e.position.set(t.width / 2, t.height / 2), e.pivot.set(t.width / 2, t.height / 2), e.rotation = x, e.scale.set(u.sx, u.sy)) : (a.parent !== i && i.addChildAt(a, Math.min(2, i.children.length)), h.parent !== i && i.addChild(h), g.parent !== i && i.addChild(g), e.rotation = 0, e.scale.set(1, 1), i.position.set(t.position.x, t.position.y), i.rotation = x, i.scale.set(u.sx, u.sy), x !== 0 || u.sx < 0 || u.sy < 0 ? (i.pivot.set(t.width / 2, t.height / 2), i.position.set(t.position.x + t.width / 2, t.position.y + t.height / 2)) : i.pivot.set(0, 0));
88
+ const _ = t.type === "mediaNode", v = t.type === "animAnchor";
88
89
  if (a.clear(), a.alpha = 1, w) this._updateSvgNode(s, t, l);
89
- else if (S) {
90
+ else if (_) {
90
91
  h.visible = !1;
91
- const c = t.data.fill && t.data.fill !== "transparent" ? t.data.fill : "#ffffff", n = t.data.borderStyle === "none", p = l ? "#3b82f6" : t.data.stroke, C = l ? Math.max(t.data.strokeWidth, 2) : t.data.strokeWidth;
92
- k.shapeRoundRect(a, {
92
+ const f = t.data.fill && t.data.fill !== "transparent" ? m(t.data.fill, "#ffffff") : "#ffffff", n = t.data.borderStyle === "none", p = l ? "#3b82f6" : m(t.data.stroke, "#374151"), k = l ? Math.max(t.data.strokeWidth, 2) : t.data.strokeWidth;
93
+ S.shapeRoundRect(a, {
93
94
  width: t.width,
94
95
  height: t.height,
95
- fill: c,
96
+ fill: f,
96
97
  stroke: p,
97
- strokeWidth: C,
98
+ strokeWidth: k,
98
99
  borderStyle: l && n ? "solid" : t.data.borderStyle,
99
100
  dashOffset: this._dynamicOffset
100
101
  });
101
- } else if (x) {
102
+ } else if (v) {
102
103
  h.visible = !1;
103
- const c = "#8b5cf6", n = r?.presentation ?? !1, p = n ? (r?.presentationAnchorVisible ?? !1) && r?.presentationAnchorId === t.id : r?.showAnchors ?? !0;
104
- p && (a.alpha = n ? 0.48 : 0.9, k.shapeRoundRect(a, {
104
+ const f = "#8b5cf6", n = r?.presentation ?? !1, p = n ? (r?.presentationAnchorVisible ?? !1) && r?.presentationAnchorId === t.id : r?.showAnchors ?? !0;
105
+ p && (a.alpha = n ? 0.48 : 0.9, S.shapeRoundRect(a, {
105
106
  width: t.width,
106
107
  height: t.height,
107
108
  fill: "transparent",
108
- stroke: l && !n ? "#3b82f6" : c,
109
+ stroke: l && !n ? "#3b82f6" : f,
109
110
  strokeWidth: l && !n ? 2.5 : 1.5,
110
111
  borderStyle: "dashed"
111
- }), a.circle(0, 0, n ? 11 : 13).fill({ color: l && !n ? "#3b82f6" : c })), b.text = String(d ?? ""), b.alpha = n ? 0.7 : 1, b.visible = p, b.position.set(0, 0);
112
+ }), a.circle(0, 0, n ? 11 : 13).fill({ color: l && !n ? "#3b82f6" : f })), b.text = String(d ?? ""), b.alpha = n ? 0.7 : 1, b.visible = p, b.position.set(0, 0);
112
113
  } else {
113
114
  h.visible = !1;
114
- const c = k[t.type] ?? k.shapeRect, n = t.data.borderStyle === "none";
115
- c(a, {
115
+ const f = S[t.type] ?? S.shapeRect, n = t.data.borderStyle === "none";
116
+ f(a, {
116
117
  width: t.width,
117
118
  height: t.height,
118
- fill: t.data.fill,
119
- stroke: l ? "#3b82f6" : t.data.stroke,
119
+ fill: m(t.data.fill, "#ffffff"),
120
+ stroke: l ? "#3b82f6" : m(t.data.stroke, "#374151"),
120
121
  strokeWidth: l ? Math.max(t.data.strokeWidth, 2) : t.data.strokeWidth,
121
122
  borderStyle: l && n ? "solid" : t.data.borderStyle,
122
123
  dashOffset: this._dynamicOffset
123
124
  });
124
125
  }
125
- if (x || (b.visible = !1), y.clear(), t.data.childCanvasId) {
126
- const n = t.width + 8, p = t.height + 8, C = 0.5 + 0.3 * Math.sin(this._dynamicOffset * 8e-3);
126
+ if (v || (b.visible = !1), y.clear(), t.data.childCanvasId) {
127
+ const n = t.width + 8, p = t.height + 8, k = 0.5 + 0.3 * Math.sin(this._dynamicOffset * 8e-3);
127
128
  y.roundRect(-4, -4, n, p, 6), y.stroke({
128
129
  color: 9133302,
129
130
  width: 2.5,
130
- alpha: C
131
+ alpha: k
131
132
  }), y.roundRect(-6, -6, n + 4, p + 4, 8), y.stroke({
132
133
  color: 9133302,
133
134
  width: 1,
134
- alpha: C * 0.4
135
+ alpha: k * 0.4
135
136
  });
136
137
  }
137
- const v = I(t.data.labelPlacement);
138
- if (N(o, {
139
- label: S || x ? "" : w ? T(t.data.label, v) : t.data.label,
140
- color: t.data.labelColor ?? t.data.color,
138
+ const C = A(t.data.labelPlacement), O = t.data.labelColor ?? (w ? "theme:base-content" : t.data.color);
139
+ if (L(o, {
140
+ label: _ || v ? "" : w ? N(t.data.label, C) : t.data.label,
141
+ color: m(O, "#111827"),
141
142
  fontSize: t.data.fontSize,
142
143
  width: t.width,
143
144
  height: t.height
144
- }), o.visible = !S && !x, t.type === "shapeCorner") {
145
- const c = Math.min(t.width, t.height) * 0.4;
146
- o.position.set((c + t.width) / 2, (c + t.height) / 2);
145
+ }), o.visible = !_ && !v, t.type === "shapeCorner") {
146
+ const f = Math.min(t.width, t.height) * 0.4;
147
+ o.position.set((f + t.width) / 2, (f + t.height) / 2);
147
148
  } else if (w) {
148
149
  const n = o.width / 2, p = o.height / 2;
149
- v === "top" ? o.position.set(t.width / 2, -4 - p) : v === "bottom" ? o.position.set(t.width / 2, t.height + 4 + p) : v === "left" ? o.position.set(-4 - n, t.height / 2) : v === "right" ? o.position.set(t.width + 4 + n, t.height / 2) : o.position.set(t.width / 2, t.height / 2), o.position.x += t.data.labelOffsetX ?? 0, o.position.y += t.data.labelOffsetY ?? 0;
150
+ C === "top" ? o.position.set(t.width / 2, -4 - p) : C === "bottom" ? o.position.set(t.width / 2, t.height + 4 + p) : C === "left" ? o.position.set(-4 - n, t.height / 2) : C === "right" ? o.position.set(t.width + 4 + n, t.height / 2) : o.position.set(t.width / 2, t.height / 2), o.position.x += t.data.labelOffsetX ?? 0, o.position.y += t.data.labelOffsetY ?? 0;
150
151
  }
151
- if (w ? (o.rotation = 0, o.scale.set(1, 1)) : (o.rotation = -u, o.scale.set(m.sx, m.sy)), g.visible = (f || l) && !(x && r?.presentation), g.visible) {
152
- const c = R(t.width, t.height);
153
- s.handleDefs = c, L(g, c);
152
+ if (w ? (o.rotation = 0, o.scale.set(1, 1)) : (o.rotation = -x, o.scale.set(u.sx, u.sy)), g.visible = (c || l) && !(v && r?.presentation), g.visible) {
153
+ const f = W(t.width, t.height);
154
+ s.handleDefs = f, H(g, f);
154
155
  }
155
156
  }
156
157
  _updateSvgNode(s, t, l) {
157
- const { shape: f, icon: d } = s, { width: r, height: e, data: i } = t, a = i.iconBox ?? !1, h = i.borderStyle ?? (a ? "solid" : "none"), o = h === "none", b = Math.min(8, r * 0.12, e * 0.12);
158
- i.fill && i.fill !== "transparent" && (a || !o) && f.roundRect(0, 0, r, e, b).fill({ color: i.fill }), !o && i.stroke && i.stroke !== "transparent" && i.strokeWidth > 0 && M(f, {
158
+ const { shape: c, icon: d } = s, { width: r, height: i, data: e } = t, a = e.iconBox ?? !1, h = e.borderStyle ?? (a ? "solid" : "none"), o = h === "none", b = Math.min(8, r * 0.12, i * 0.12);
159
+ e.fill && e.fill !== "transparent" && (a || !o) && c.roundRect(0, 0, r, i, b).fill({ color: m(e.fill, "#ffffff") }), !o && e.stroke && e.stroke !== "transparent" && e.strokeWidth > 0 && T(c, {
159
160
  width: r,
160
- height: e,
161
+ height: i,
161
162
  fill: "transparent",
162
- stroke: i.stroke,
163
- strokeWidth: i.strokeWidth,
163
+ stroke: m(e.stroke, "#374151"),
164
+ strokeWidth: e.strokeWidth,
164
165
  borderStyle: h,
165
166
  dashOffset: this._dynamicOffset
166
- }, b), l && f.roundRect(0, 0, r, e, b).stroke({
167
+ }, b), l && c.roundRect(0, 0, r, i, b).stroke({
167
168
  color: "#3b82f6",
168
- width: Math.max(i.strokeWidth, 2)
169
+ width: Math.max(e.strokeWidth, 2)
169
170
  });
170
- const g = i.color || "#334155", y = B(i.svgId ?? "", g);
171
+ const g = m(e.color, "#334155") || "#334155", y = P(e.svgId ?? "", g);
171
172
  if (y) {
172
173
  d.texture = y, d.visible = !0;
173
- const w = a ? Math.min(r, e) * 0.18 : 2, u = Math.max(4, Math.min(r, e) - w * 2);
174
- d.width = u, d.height = u, d.position.set(r / 2, e / 2);
174
+ const w = a ? Math.min(r, i) * 0.18 : 2, x = Math.max(4, Math.min(r, i) - w * 2);
175
+ d.width = x, d.height = x, d.position.set(r / 2, i / 2);
175
176
  } else d.visible = !1;
176
177
  }
177
178
  destroy() {
@@ -181,7 +182,7 @@ var j = class {
181
182
  }
182
183
  };
183
184
  export {
184
- j as NodeRenderer
185
+ K as NodeRenderer
185
186
  };
186
187
 
187
188
  //# sourceMappingURL=NodeRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/NodeRenderer.ts"],"sourcesContent":["import { Container, Graphics, Text, Sprite } from 'pixi.js';\nimport type { FlowNode } from '../types';\nimport { drawRoundRectBorder, shapeDrawers, type ShapeDrawOptions } from './shapes';\nimport { createNodeText, formatIconLabel, normalizeIconLabelPlacement, updateNodeText } from './NodeText';\nimport { getHandlePositions, createHandleGraphics, updateHandleGraphics, type HandleDef } from './NodeHandles';\nimport { getRotationRad, getFlipScale } from './nodeUtils';\nimport { getIconTexture, subscribeIconTextureReady } from './svgIconTexture';\n\nexport interface NodeContainer {\n container: Container;\n shape: Graphics;\n /** Rotated/flipped visual content for SVG icon stamps. */\n svgTransform: Container;\n icon: Sprite;\n text: Text;\n /** Sequence badge shown on `animAnchor` nodes. */\n animBadge: Text;\n handles: Graphics;\n handleDefs: HandleDef[];\n nodeId: string;\n subCanvasGlow: Graphics;\n}\n\n/**\n * Manages PixiJS display objects for all nodes on the current canvas.\n * Syncs from FlowNode[] data → PixiJS scene graph.\n */\nexport class NodeRenderer {\n private world: Container;\n private nodeLayer: Container;\n private nodes = new Map<string, NodeContainer>();\n private _dynamicOffset = 0;\n private _unsubscribeTextureReady: () => void;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.nodeLayer = new Container({ label: 'nodes', sortableChildren: true });\n this.world.addChild(this.nodeLayer);\n this._unsubscribeTextureReady = subscribeIconTextureReady(() => this._resync?.());\n }\n\n private _resync: (() => void) | null = null;\n\n /**\n * Reconcile PixiJS containers with the current node data.\n * Creates new containers, updates existing, removes stale.\n */\n sync(\n flowNodes: FlowNode[],\n selectedIds: Set<string>,\n hoveredId: string | null,\n animSeqMap?: Map<string, number>,\n options?: {\n showAnchors?: boolean;\n presentation?: boolean;\n presentationAnchorId?: string;\n presentationAnchorVisible?: boolean;\n },\n ): void {\n const seen = new Set<string>();\n this._resync = () => this.sync(flowNodes, selectedIds, hoveredId, animSeqMap, options);\n\n // Animation-anchor display sequence (1-based). When a global map is\n // provided (document-wide, shared across sub-canvases) it is used directly;\n // otherwise derive a per-canvas order from stable creation index.\n const seqOf = animSeqMap ?? (() => {\n const anchors = flowNodes\n .filter((n) => n.type === 'animAnchor')\n .sort((a, b) => (a.data.animIndex ?? 0) - (b.data.animIndex ?? 0));\n const m = new Map<string, number>();\n anchors.forEach((n, i) => m.set(n.id, i + 1));\n return m;\n })();\n\n for (const node of flowNodes) {\n seen.add(node.id);\n let nc = this.nodes.get(node.id);\n if (!nc) {\n nc = this._createNode(node);\n this.nodes.set(node.id, nc);\n }\n this._updateNode(\n nc,\n node,\n selectedIds.has(node.id),\n hoveredId === node.id,\n seqOf.get(node.id),\n options,\n );\n }\n\n // Remove nodes no longer in data\n for (const [id, nc] of this.nodes) {\n if (!seen.has(id)) {\n this.nodeLayer.removeChild(nc.container);\n nc.container.destroy({ children: true });\n this.nodes.delete(id);\n }\n }\n }\n\n getNodeContainer(id: string): NodeContainer | undefined {\n return this.nodes.get(id);\n }\n\n getAllNodeContainers(): NodeContainer[] {\n return [...this.nodes.values()];\n }\n\n private _createNode(node: FlowNode): NodeContainer {\n const container = new Container({ label: `node-${node.id}` });\n container.eventMode = 'static';\n container.cursor = 'pointer';\n\n const svgTransform = new Container({ label: 'svg-transform' });\n container.addChild(svgTransform);\n\n const subCanvasGlow = new Graphics();\n subCanvasGlow.label = 'sub-canvas-glow';\n container.addChild(subCanvasGlow);\n\n const shape = new Graphics();\n shape.label = 'shape';\n container.addChild(shape);\n\n const icon = new Sprite();\n icon.label = 'svg-icon';\n icon.anchor.set(0.5, 0.5);\n icon.visible = false;\n container.addChild(icon);\n\n const text = createNodeText({\n label: node.data.label,\n color: node.data.labelColor ?? node.data.color,\n fontSize: node.data.fontSize,\n width: node.width,\n height: node.height,\n });\n container.addChild(text);\n\n const handleDefs = getHandlePositions(node.width, node.height);\n const handles = createHandleGraphics(container, handleDefs, false);\n\n // Sequence badge for animation anchors (top-left corner).\n const animBadge = new Text({\n text: '',\n style: { fontFamily: 'system-ui, sans-serif', fontSize: 13, fill: '#ffffff', fontWeight: '700' },\n });\n animBadge.label = 'anim-badge';\n animBadge.anchor.set(0.5, 0.5);\n animBadge.visible = false;\n container.addChild(animBadge);\n\n this.nodeLayer.addChild(container);\n\n return { container, shape, svgTransform, icon, text, animBadge, handles, handleDefs, nodeId: node.id, subCanvasGlow };\n }\n\n private _updateNode(\n nc: NodeContainer,\n node: FlowNode,\n selected: boolean,\n hovered: boolean,\n animSeq?: number,\n options?: {\n showAnchors?: boolean;\n presentation?: boolean;\n presentationAnchorId?: string;\n presentationAnchorVisible?: boolean;\n },\n ): void {\n const { container, svgTransform, shape, icon, text, animBadge, handles, subCanvasGlow } = nc;\n\n const isSvg = node.type === 'shapeSvg';\n const rad = getRotationRad(node.data);\n const flip = getFlipScale(node.data);\n\n container.zIndex = node.zIndex ?? 0;\n if (isSvg) {\n // Keep the label in the untransformed root. Only the icon box, icon and\n // connection handles rotate/flip around the node center.\n if (shape.parent !== svgTransform) svgTransform.addChild(shape);\n if (icon.parent !== svgTransform) svgTransform.addChild(icon);\n if (handles.parent !== svgTransform) svgTransform.addChild(handles);\n container.position.set(node.position.x, node.position.y);\n container.rotation = 0;\n container.scale.set(1, 1);\n container.pivot.set(0, 0);\n svgTransform.position.set(node.width / 2, node.height / 2);\n svgTransform.pivot.set(node.width / 2, node.height / 2);\n svgTransform.rotation = rad;\n svgTransform.scale.set(flip.sx, flip.sy);\n } else {\n if (shape.parent !== container) container.addChildAt(shape, Math.min(2, container.children.length));\n if (icon.parent !== container) container.addChild(icon);\n if (handles.parent !== container) container.addChild(handles);\n svgTransform.rotation = 0;\n svgTransform.scale.set(1, 1);\n container.position.set(node.position.x, node.position.y);\n container.rotation = rad;\n container.scale.set(flip.sx, flip.sy);\n if (rad !== 0 || flip.sx < 0 || flip.sy < 0) {\n container.pivot.set(node.width / 2, node.height / 2);\n container.position.set(node.position.x + node.width / 2, node.position.y + node.height / 2);\n } else {\n container.pivot.set(0, 0);\n }\n }\n\n const isMedia = node.type === 'mediaNode';\n const isAnchor = node.type === 'animAnchor';\n\n // Redraw shape\n shape.clear();\n shape.alpha = 1;\n if (isSvg) {\n this._updateSvgNode(nc, node, selected);\n } else if (isMedia) {\n // Media nodes render their content in a synced DOM overlay; PixiJS only\n // draws the frame (background + border) beneath the overlay.\n icon.visible = false;\n const r = 6;\n const fill = node.data.fill && node.data.fill !== 'transparent' ? node.data.fill : '#ffffff';\n const borderHidden = node.data.borderStyle === 'none';\n const strokeColor = selected ? '#3b82f6' : node.data.stroke;\n const strokeW = selected ? Math.max(node.data.strokeWidth, 2) : node.data.strokeWidth;\n shapeDrawers.shapeRoundRect(shape, {\n width: node.width,\n height: node.height,\n fill,\n stroke: strokeColor,\n strokeWidth: strokeW,\n borderStyle: selected && borderHidden ? 'solid' : node.data.borderStyle,\n dashOffset: this._dynamicOffset,\n });\n } else if (isAnchor) {\n // Animation anchors are globally visible/hidden in editing mode. During\n // presentation the current frame remains as a subtle dashed overlay.\n icon.visible = false;\n const accent = '#8b5cf6';\n const presentation = options?.presentation ?? false;\n const anchorVisible = presentation\n ? (options?.presentationAnchorVisible ?? false) && options?.presentationAnchorId === node.id\n : (options?.showAnchors ?? true);\n if (anchorVisible) {\n shape.alpha = presentation ? 0.48 : 0.9;\n shapeDrawers.shapeRoundRect(shape, {\n width: node.width,\n height: node.height,\n fill: 'transparent',\n stroke: selected && !presentation ? '#3b82f6' : accent,\n strokeWidth: selected && !presentation ? 2.5 : 1.5,\n borderStyle: 'dashed',\n });\n shape.circle(0, 0, presentation ? 11 : 13).fill({\n color: selected && !presentation ? '#3b82f6' : accent,\n });\n }\n animBadge.text = String(animSeq ?? '');\n animBadge.alpha = presentation ? 0.7 : 1;\n animBadge.visible = anchorVisible;\n animBadge.position.set(0, 0);\n } else {\n icon.visible = false;\n const drawFn = shapeDrawers[node.type] ?? shapeDrawers.shapeRect;\n const borderHidden = node.data.borderStyle === 'none';\n const opts: ShapeDrawOptions = {\n width: node.width,\n height: node.height,\n fill: node.data.fill,\n stroke: selected ? '#3b82f6' : node.data.stroke,\n strokeWidth: selected ? Math.max(node.data.strokeWidth, 2) : node.data.strokeWidth,\n borderStyle: (selected && borderHidden) ? 'solid' : node.data.borderStyle,\n dashOffset: this._dynamicOffset,\n };\n drawFn(shape, opts);\n }\n if (!isAnchor) animBadge.visible = false;\n\n // Sub-canvas glow indicator\n subCanvasGlow.clear();\n if (node.data.childCanvasId) {\n const pad = 4;\n const w = node.width + pad * 2;\n const h = node.height + pad * 2;\n const pulse = 0.5 + 0.3 * Math.sin(this._dynamicOffset * 0.008);\n subCanvasGlow.roundRect(-pad, -pad, w, h, 6);\n subCanvasGlow.stroke({ color: 0x8b5cf6, width: 2.5, alpha: pulse });\n subCanvasGlow.roundRect(-pad - 2, -pad - 2, w + 4, h + 4, 8);\n subCanvasGlow.stroke({ color: 0x8b5cf6, width: 1, alpha: pulse * 0.4 });\n }\n\n // Text: counter-rotate and counter-flip so it stays upright\n const iconLabelPlacement = normalizeIconLabelPlacement(node.data.labelPlacement);\n updateNodeText(text, {\n label: isMedia || isAnchor\n ? ''\n : isSvg\n ? formatIconLabel(node.data.label, iconLabelPlacement)\n : node.data.label,\n color: node.data.labelColor ?? node.data.color,\n fontSize: node.data.fontSize,\n width: node.width,\n height: node.height,\n });\n text.visible = !isMedia && !isAnchor;\n\n if (node.type === 'shapeCorner') {\n const half = Math.min(node.width, node.height) * 0.4;\n text.position.set((half + node.width) / 2, (half + node.height) / 2);\n } else if (isSvg) {\n const gap = 4;\n const halfTextWidth = text.width / 2;\n const halfTextHeight = text.height / 2;\n if (iconLabelPlacement === 'top') {\n text.position.set(node.width / 2, -gap - halfTextHeight);\n } else if (iconLabelPlacement === 'bottom') {\n text.position.set(node.width / 2, node.height + gap + halfTextHeight);\n } else if (iconLabelPlacement === 'left') {\n text.position.set(-gap - halfTextWidth, node.height / 2);\n } else if (iconLabelPlacement === 'right') {\n text.position.set(node.width + gap + halfTextWidth, node.height / 2);\n } else {\n text.position.set(node.width / 2, node.height / 2);\n }\n text.position.x += node.data.labelOffsetX ?? 0;\n text.position.y += node.data.labelOffsetY ?? 0;\n }\n\n if (isSvg) {\n text.rotation = 0;\n text.scale.set(1, 1);\n } else {\n text.rotation = -rad;\n text.scale.set(flip.sx, flip.sy);\n }\n\n // Handles visibility\n handles.visible = (hovered || selected) && !(isAnchor && options?.presentation);\n if (handles.visible) {\n const defs = getHandlePositions(node.width, node.height);\n nc.handleDefs = defs;\n updateHandleGraphics(handles, defs);\n }\n }\n\n /**\n * Draw an SVG-stamp node: optional bordered box + centered icon sprite.\n * The icon texture is rasterized lazily; a redraw is requested when ready.\n */\n private _updateSvgNode(nc: NodeContainer, node: FlowNode, selected: boolean): void {\n const { shape, icon } = nc;\n const { width, height, data } = node;\n\n // Render the configured icon box independently from the solid selection\n // outline. Otherwise selecting an icon makes dotted/dashed borders appear\n // solid and hides whether the chosen border style is actually applied.\n const showBox = data.iconBox ?? false;\n const borderStyle = data.borderStyle ?? (showBox ? 'solid' : 'none');\n const borderHidden = borderStyle === 'none';\n const r = Math.min(8, width * 0.12, height * 0.12);\n if (data.fill && data.fill !== 'transparent' && (showBox || !borderHidden)) {\n shape.roundRect(0, 0, width, height, r).fill({ color: data.fill });\n }\n if (!borderHidden && data.stroke && data.stroke !== 'transparent' && data.strokeWidth > 0) {\n drawRoundRectBorder(shape, {\n width,\n height,\n fill: 'transparent',\n stroke: data.stroke,\n strokeWidth: data.strokeWidth,\n borderStyle,\n dashOffset: this._dynamicOffset,\n }, r);\n }\n if (selected) {\n shape.roundRect(0, 0, width, height, r).stroke({\n color: '#3b82f6',\n width: Math.max(data.strokeWidth, 2),\n });\n }\n\n // Icon sprite: fit within the box with padding, centered. The texture is\n // rasterized lazily; because the ticker re-runs sync every frame, it will\n // be picked up automatically once cached.\n const iconColor = data.color || '#334155';\n const tex = getIconTexture(data.svgId ?? '', iconColor);\n if (tex) {\n icon.texture = tex;\n icon.visible = true;\n const pad = showBox ? Math.min(width, height) * 0.18 : 2;\n const box = Math.max(4, Math.min(width, height) - pad * 2);\n icon.width = box;\n icon.height = box;\n icon.position.set(width / 2, height / 2);\n } else {\n icon.visible = false;\n }\n }\n\n destroy(): void {\n this._unsubscribeTextureReady();\n this._resync = null;\n for (const [, nc] of this.nodes) {\n nc.container.destroy({ children: true });\n }\n this.nodes.clear();\n this.nodeLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NodeRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/NodeRenderer.ts"],"sourcesContent":["import { Container, Graphics, Text, Sprite } from 'pixi.js';\nimport type { FlowNode } from '../types';\nimport { drawRoundRectBorder, shapeDrawers, type ShapeDrawOptions } from './shapes';\nimport { createNodeText, formatIconLabel, normalizeIconLabelPlacement, updateNodeText } from './NodeText';\nimport { getHandlePositions, createHandleGraphics, updateHandleGraphics, type HandleDef } from './NodeHandles';\nimport { getRotationRad, getFlipScale } from './nodeUtils';\nimport { getIconTexture, subscribeIconTextureReady } from './svgIconTexture';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nexport interface NodeContainer {\n container: Container;\n shape: Graphics;\n /** Rotated/flipped visual content for SVG icon stamps. */\n svgTransform: Container;\n icon: Sprite;\n text: Text;\n /** Sequence badge shown on `animAnchor` nodes. */\n animBadge: Text;\n handles: Graphics;\n handleDefs: HandleDef[];\n nodeId: string;\n subCanvasGlow: Graphics;\n}\n\n/**\n * Manages PixiJS display objects for all nodes on the current canvas.\n * Syncs from FlowNode[] data → PixiJS scene graph.\n */\nexport class NodeRenderer {\n private world: Container;\n private nodeLayer: Container;\n private nodes = new Map<string, NodeContainer>();\n private _dynamicOffset = 0;\n private _unsubscribeTextureReady: () => void;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.nodeLayer = new Container({ label: 'nodes', sortableChildren: true });\n this.world.addChild(this.nodeLayer);\n this._unsubscribeTextureReady = subscribeIconTextureReady(() => this._resync?.());\n }\n\n private _resync: (() => void) | null = null;\n\n /**\n * Reconcile PixiJS containers with the current node data.\n * Creates new containers, updates existing, removes stale.\n */\n sync(\n flowNodes: FlowNode[],\n selectedIds: Set<string>,\n hoveredId: string | null,\n animSeqMap?: Map<string, number>,\n options?: {\n showAnchors?: boolean;\n presentation?: boolean;\n presentationAnchorId?: string;\n presentationAnchorVisible?: boolean;\n },\n ): void {\n const seen = new Set<string>();\n this._resync = () => this.sync(flowNodes, selectedIds, hoveredId, animSeqMap, options);\n\n // Animation-anchor display sequence (1-based). When a global map is\n // provided (document-wide, shared across sub-canvases) it is used directly;\n // otherwise derive a per-canvas order from stable creation index.\n const seqOf = animSeqMap ?? (() => {\n const anchors = flowNodes\n .filter((n) => n.type === 'animAnchor')\n .sort((a, b) => (a.data.animIndex ?? 0) - (b.data.animIndex ?? 0));\n const m = new Map<string, number>();\n anchors.forEach((n, i) => m.set(n.id, i + 1));\n return m;\n })();\n\n for (const node of flowNodes) {\n seen.add(node.id);\n let nc = this.nodes.get(node.id);\n if (!nc) {\n nc = this._createNode(node);\n this.nodes.set(node.id, nc);\n }\n this._updateNode(\n nc,\n node,\n selectedIds.has(node.id),\n hoveredId === node.id,\n seqOf.get(node.id),\n options,\n );\n }\n\n // Remove nodes no longer in data\n for (const [id, nc] of this.nodes) {\n if (!seen.has(id)) {\n this.nodeLayer.removeChild(nc.container);\n nc.container.destroy({ children: true });\n this.nodes.delete(id);\n }\n }\n }\n\n getNodeContainer(id: string): NodeContainer | undefined {\n return this.nodes.get(id);\n }\n\n getAllNodeContainers(): NodeContainer[] {\n return [...this.nodes.values()];\n }\n\n private _createNode(node: FlowNode): NodeContainer {\n const container = new Container({ label: `node-${node.id}` });\n container.eventMode = 'static';\n container.cursor = 'pointer';\n\n const svgTransform = new Container({ label: 'svg-transform' });\n container.addChild(svgTransform);\n\n const subCanvasGlow = new Graphics();\n subCanvasGlow.label = 'sub-canvas-glow';\n container.addChild(subCanvasGlow);\n\n const shape = new Graphics();\n shape.label = 'shape';\n container.addChild(shape);\n\n const icon = new Sprite();\n icon.label = 'svg-icon';\n icon.anchor.set(0.5, 0.5);\n icon.visible = false;\n container.addChild(icon);\n\n const text = createNodeText({\n label: node.data.label,\n color: resolveThemeColor(node.data.labelColor ?? node.data.color, '#111827'),\n fontSize: node.data.fontSize,\n width: node.width,\n height: node.height,\n });\n container.addChild(text);\n\n const handleDefs = getHandlePositions(node.width, node.height);\n const handles = createHandleGraphics(container, handleDefs, false);\n\n // Sequence badge for animation anchors (top-left corner).\n const animBadge = new Text({\n text: '',\n style: { fontFamily: 'system-ui, sans-serif', fontSize: 13, fill: '#ffffff', fontWeight: '700' },\n });\n animBadge.label = 'anim-badge';\n animBadge.anchor.set(0.5, 0.5);\n animBadge.visible = false;\n container.addChild(animBadge);\n\n this.nodeLayer.addChild(container);\n\n return { container, shape, svgTransform, icon, text, animBadge, handles, handleDefs, nodeId: node.id, subCanvasGlow };\n }\n\n private _updateNode(\n nc: NodeContainer,\n node: FlowNode,\n selected: boolean,\n hovered: boolean,\n animSeq?: number,\n options?: {\n showAnchors?: boolean;\n presentation?: boolean;\n presentationAnchorId?: string;\n presentationAnchorVisible?: boolean;\n },\n ): void {\n const { container, svgTransform, shape, icon, text, animBadge, handles, subCanvasGlow } = nc;\n\n const isSvg = node.type === 'shapeSvg';\n const rad = getRotationRad(node.data);\n const flip = getFlipScale(node.data);\n\n container.zIndex = node.zIndex ?? 0;\n if (isSvg) {\n // Keep the label in the untransformed root. Only the icon box, icon and\n // connection handles rotate/flip around the node center.\n if (shape.parent !== svgTransform) svgTransform.addChild(shape);\n if (icon.parent !== svgTransform) svgTransform.addChild(icon);\n if (handles.parent !== svgTransform) svgTransform.addChild(handles);\n container.position.set(node.position.x, node.position.y);\n container.rotation = 0;\n container.scale.set(1, 1);\n container.pivot.set(0, 0);\n svgTransform.position.set(node.width / 2, node.height / 2);\n svgTransform.pivot.set(node.width / 2, node.height / 2);\n svgTransform.rotation = rad;\n svgTransform.scale.set(flip.sx, flip.sy);\n } else {\n if (shape.parent !== container) container.addChildAt(shape, Math.min(2, container.children.length));\n if (icon.parent !== container) container.addChild(icon);\n if (handles.parent !== container) container.addChild(handles);\n svgTransform.rotation = 0;\n svgTransform.scale.set(1, 1);\n container.position.set(node.position.x, node.position.y);\n container.rotation = rad;\n container.scale.set(flip.sx, flip.sy);\n if (rad !== 0 || flip.sx < 0 || flip.sy < 0) {\n container.pivot.set(node.width / 2, node.height / 2);\n container.position.set(node.position.x + node.width / 2, node.position.y + node.height / 2);\n } else {\n container.pivot.set(0, 0);\n }\n }\n\n const isMedia = node.type === 'mediaNode';\n const isAnchor = node.type === 'animAnchor';\n\n // Redraw shape\n shape.clear();\n shape.alpha = 1;\n if (isSvg) {\n this._updateSvgNode(nc, node, selected);\n } else if (isMedia) {\n // Media nodes render their content in a synced DOM overlay; PixiJS only\n // draws the frame (background + border) beneath the overlay.\n icon.visible = false;\n const r = 6;\n const fill = node.data.fill && node.data.fill !== 'transparent' ? resolveThemeColor(node.data.fill, '#ffffff') : '#ffffff';\n const borderHidden = node.data.borderStyle === 'none';\n const strokeColor = selected ? '#3b82f6' : resolveThemeColor(node.data.stroke, '#374151');\n const strokeW = selected ? Math.max(node.data.strokeWidth, 2) : node.data.strokeWidth;\n shapeDrawers.shapeRoundRect(shape, {\n width: node.width,\n height: node.height,\n fill,\n stroke: strokeColor,\n strokeWidth: strokeW,\n borderStyle: selected && borderHidden ? 'solid' : node.data.borderStyle,\n dashOffset: this._dynamicOffset,\n });\n } else if (isAnchor) {\n // Animation anchors are globally visible/hidden in editing mode. During\n // presentation the current frame remains as a subtle dashed overlay.\n icon.visible = false;\n const accent = '#8b5cf6';\n const presentation = options?.presentation ?? false;\n const anchorVisible = presentation\n ? (options?.presentationAnchorVisible ?? false) && options?.presentationAnchorId === node.id\n : (options?.showAnchors ?? true);\n if (anchorVisible) {\n shape.alpha = presentation ? 0.48 : 0.9;\n shapeDrawers.shapeRoundRect(shape, {\n width: node.width,\n height: node.height,\n fill: 'transparent',\n stroke: selected && !presentation ? '#3b82f6' : accent,\n strokeWidth: selected && !presentation ? 2.5 : 1.5,\n borderStyle: 'dashed',\n });\n shape.circle(0, 0, presentation ? 11 : 13).fill({\n color: selected && !presentation ? '#3b82f6' : accent,\n });\n }\n animBadge.text = String(animSeq ?? '');\n animBadge.alpha = presentation ? 0.7 : 1;\n animBadge.visible = anchorVisible;\n animBadge.position.set(0, 0);\n } else {\n icon.visible = false;\n const drawFn = shapeDrawers[node.type] ?? shapeDrawers.shapeRect;\n const borderHidden = node.data.borderStyle === 'none';\n const opts: ShapeDrawOptions = {\n width: node.width,\n height: node.height,\n fill: resolveThemeColor(node.data.fill, '#ffffff'),\n stroke: selected ? '#3b82f6' : resolveThemeColor(node.data.stroke, '#374151'),\n strokeWidth: selected ? Math.max(node.data.strokeWidth, 2) : node.data.strokeWidth,\n borderStyle: (selected && borderHidden) ? 'solid' : node.data.borderStyle,\n dashOffset: this._dynamicOffset,\n };\n drawFn(shape, opts);\n }\n if (!isAnchor) animBadge.visible = false;\n\n // Sub-canvas glow indicator\n subCanvasGlow.clear();\n if (node.data.childCanvasId) {\n const pad = 4;\n const w = node.width + pad * 2;\n const h = node.height + pad * 2;\n const pulse = 0.5 + 0.3 * Math.sin(this._dynamicOffset * 0.008);\n subCanvasGlow.roundRect(-pad, -pad, w, h, 6);\n subCanvasGlow.stroke({ color: 0x8b5cf6, width: 2.5, alpha: pulse });\n subCanvasGlow.roundRect(-pad - 2, -pad - 2, w + 4, h + 4, 8);\n subCanvasGlow.stroke({ color: 0x8b5cf6, width: 1, alpha: pulse * 0.4 });\n }\n\n // Text: counter-rotate and counter-flip so it stays upright\n const iconLabelPlacement = normalizeIconLabelPlacement(node.data.labelPlacement);\n // SVG-icon labels default to the theme font color (so they read on any\n // theme) even when the icon body uses a brand color; other node types fall\n // back to the node's own text color.\n const labelColor = node.data.labelColor\n ?? (isSvg ? 'theme:base-content' : node.data.color);\n updateNodeText(text, {\n label: isMedia || isAnchor\n ? ''\n : isSvg\n ? formatIconLabel(node.data.label, iconLabelPlacement)\n : node.data.label,\n color: resolveThemeColor(labelColor, '#111827'),\n fontSize: node.data.fontSize,\n width: node.width,\n height: node.height,\n });\n text.visible = !isMedia && !isAnchor;\n\n if (node.type === 'shapeCorner') {\n const half = Math.min(node.width, node.height) * 0.4;\n text.position.set((half + node.width) / 2, (half + node.height) / 2);\n } else if (isSvg) {\n const gap = 4;\n const halfTextWidth = text.width / 2;\n const halfTextHeight = text.height / 2;\n if (iconLabelPlacement === 'top') {\n text.position.set(node.width / 2, -gap - halfTextHeight);\n } else if (iconLabelPlacement === 'bottom') {\n text.position.set(node.width / 2, node.height + gap + halfTextHeight);\n } else if (iconLabelPlacement === 'left') {\n text.position.set(-gap - halfTextWidth, node.height / 2);\n } else if (iconLabelPlacement === 'right') {\n text.position.set(node.width + gap + halfTextWidth, node.height / 2);\n } else {\n text.position.set(node.width / 2, node.height / 2);\n }\n text.position.x += node.data.labelOffsetX ?? 0;\n text.position.y += node.data.labelOffsetY ?? 0;\n }\n\n if (isSvg) {\n text.rotation = 0;\n text.scale.set(1, 1);\n } else {\n text.rotation = -rad;\n text.scale.set(flip.sx, flip.sy);\n }\n\n // Handles visibility\n handles.visible = (hovered || selected) && !(isAnchor && options?.presentation);\n if (handles.visible) {\n const defs = getHandlePositions(node.width, node.height);\n nc.handleDefs = defs;\n updateHandleGraphics(handles, defs);\n }\n }\n\n /**\n * Draw an SVG-stamp node: optional bordered box + centered icon sprite.\n * The icon texture is rasterized lazily; a redraw is requested when ready.\n */\n private _updateSvgNode(nc: NodeContainer, node: FlowNode, selected: boolean): void {\n const { shape, icon } = nc;\n const { width, height, data } = node;\n\n // Render the configured icon box independently from the solid selection\n // outline. Otherwise selecting an icon makes dotted/dashed borders appear\n // solid and hides whether the chosen border style is actually applied.\n const showBox = data.iconBox ?? false;\n const borderStyle = data.borderStyle ?? (showBox ? 'solid' : 'none');\n const borderHidden = borderStyle === 'none';\n const r = Math.min(8, width * 0.12, height * 0.12);\n if (data.fill && data.fill !== 'transparent' && (showBox || !borderHidden)) {\n shape.roundRect(0, 0, width, height, r).fill({ color: resolveThemeColor(data.fill, '#ffffff') });\n }\n if (!borderHidden && data.stroke && data.stroke !== 'transparent' && data.strokeWidth > 0) {\n drawRoundRectBorder(shape, {\n width,\n height,\n fill: 'transparent',\n stroke: resolveThemeColor(data.stroke, '#374151'),\n strokeWidth: data.strokeWidth,\n borderStyle,\n dashOffset: this._dynamicOffset,\n }, r);\n }\n if (selected) {\n shape.roundRect(0, 0, width, height, r).stroke({\n color: '#3b82f6',\n width: Math.max(data.strokeWidth, 2),\n });\n }\n\n // Icon sprite: fit within the box with padding, centered. The texture is\n // rasterized lazily; because the ticker re-runs sync every frame, it will\n // be picked up automatically once cached.\n const iconColor = resolveThemeColor(data.color, '#334155') || '#334155';\n const tex = getIconTexture(data.svgId ?? '', iconColor);\n if (tex) {\n icon.texture = tex;\n icon.visible = true;\n const pad = showBox ? Math.min(width, height) * 0.18 : 2;\n const box = Math.max(4, Math.min(width, height) - pad * 2);\n icon.width = box;\n icon.height = box;\n icon.position.set(width / 2, height / 2);\n } else {\n icon.visible = false;\n }\n }\n\n destroy(): void {\n this._unsubscribeTextureReady();\n this._resync = null;\n for (const [, nc] of this.nodes) {\n nc.container.destroy({ children: true });\n }\n this.nodes.clear();\n this.nodeLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
@@ -12,3 +12,25 @@ export interface AIChatMessage {
12
12
  content: string;
13
13
  }
14
14
  export declare function streamAIChat(config: FlowAIConfig, messages: AIChatMessage[], signal: AbortSignal): AsyncIterable<string>;
15
+ /**
16
+ * Non-streaming completion used by the AI flow generator. Accepts an optional
17
+ * image (data URL) for "reconstruct this diagram" requests. Returns the full
18
+ * assistant text.
19
+ */
20
+ export declare function completeAIChat(config: FlowAIConfig, userText: string, options?: {
21
+ imageDataUrl?: string;
22
+ systemPrompt?: string;
23
+ signal?: AbortSignal;
24
+ }): Promise<string>;
25
+ /**
26
+ * Streaming variant of `completeAIChat`: same multimodal request shape
27
+ * (optional image + system prompt override), but the reply is consumed as SSE
28
+ * deltas. `onDelta` fires with the accumulated text after every chunk so
29
+ * callers can render the response live. Returns the full assistant text.
30
+ */
31
+ export declare function completeAIChatStream(config: FlowAIConfig, userText: string, options?: {
32
+ imageDataUrl?: string;
33
+ systemPrompt?: string;
34
+ signal?: AbortSignal;
35
+ onDelta?: (accumulated: string) => void;
36
+ }): Promise<string>;
@@ -1,90 +1,143 @@
1
- async function* h(e, s, a) {
2
- const c = JSON.stringify({
3
- model: e.model,
4
- messages: [...e.systemPrompt ? [{
1
+ function u(t) {
2
+ const e = (t.gateway || "").trim().replace(/\/+$/, "");
3
+ if (!e) return e;
4
+ const r = t.protocol === "anthropic" ? "/messages" : "/chat/completions";
5
+ if (/\/(chat\/completions|messages|responses|completions)$/i.test(e)) return e;
6
+ if (/\/v\d+$/i.test(e)) return e + r;
7
+ try {
8
+ const n = new URL(e);
9
+ if (n.pathname === "" || n.pathname === "/") return e + "/v1" + r;
10
+ } catch {
11
+ }
12
+ return e + r;
13
+ }
14
+ async function* h(t, e, r) {
15
+ const n = JSON.stringify({
16
+ model: t.model,
17
+ messages: [...t.systemPrompt ? [{
5
18
  role: "system",
6
- content: e.systemPrompt
7
- }] : [], ...s],
19
+ content: t.systemPrompt
20
+ }] : [], ...e],
8
21
  stream: !0
9
- }), t = await fetch(e.gateway, {
22
+ }), s = await fetch(u(t), {
10
23
  method: "POST",
11
24
  headers: {
12
25
  "Content-Type": "application/json",
13
- ...e.apiKey ? { Authorization: `Bearer ${e.apiKey}` } : {},
14
- ...e.headers
26
+ ...t.apiKey ? { Authorization: `Bearer ${t.apiKey}` } : {},
27
+ ...t.headers
15
28
  },
16
- body: c,
17
- signal: a
29
+ body: n,
30
+ signal: r
18
31
  });
19
- if (!t.ok) throw new Error(`AI API error: ${t.status} ${t.statusText}`);
20
- const d = t.body?.getReader();
21
- if (!d) throw new Error("No response body");
22
- const p = new TextDecoder();
23
- let r = "";
32
+ if (!s.ok) throw new Error(`AI API error: ${s.status} ${s.statusText}`);
33
+ const c = s.body?.getReader();
34
+ if (!c) throw new Error("No response body");
35
+ const i = new TextDecoder();
36
+ let o = "";
24
37
  for (; ; ) {
25
- const { done: m, value: y } = await d.read();
26
- if (m) break;
27
- r += p.decode(y, { stream: !0 });
28
- const i = r.split(`
38
+ const { done: y, value: p } = await c.read();
39
+ if (y) break;
40
+ o += i.decode(p, { stream: !0 });
41
+ const a = o.split(`
29
42
  `);
30
- r = i.pop() || "";
31
- for (const l of i) {
32
- const o = l.trim();
33
- if (!(!o || o === "data: [DONE]" || !o.startsWith("data: ")))
43
+ o = a.pop() || "";
44
+ for (const m of a) {
45
+ const d = m.trim();
46
+ if (!(!d || d === "data: [DONE]" || !d.startsWith("data: ")))
34
47
  try {
35
- const n = JSON.parse(o.slice(6)).choices?.[0]?.delta?.content;
36
- n && (yield n);
48
+ const l = JSON.parse(d.slice(6)).choices?.[0]?.delta?.content;
49
+ l && (yield l);
37
50
  } catch {
38
51
  }
39
52
  }
40
53
  }
41
54
  }
42
- async function* u(e, s, a) {
43
- const c = JSON.stringify({
44
- model: e.model,
45
- max_tokens: 4096,
46
- ...e.systemPrompt ? { system: e.systemPrompt } : {},
47
- messages: s,
55
+ async function* f(t, e, r) {
56
+ const n = JSON.stringify({
57
+ model: t.model,
58
+ max_tokens: 8192,
59
+ ...t.systemPrompt ? { system: t.systemPrompt } : {},
60
+ messages: e,
48
61
  stream: !0
49
- }), t = await fetch(e.gateway, {
62
+ }), s = await fetch(u(t), {
50
63
  method: "POST",
51
64
  headers: {
52
65
  "Content-Type": "application/json",
53
- ...e.apiKey ? { "x-api-key": e.apiKey } : {},
66
+ ...t.apiKey ? { "x-api-key": t.apiKey } : {},
54
67
  "anthropic-version": "2023-06-01",
55
68
  "anthropic-dangerous-direct-browser-access": "true",
56
- ...e.headers
69
+ ...t.headers
57
70
  },
58
- body: c,
59
- signal: a
71
+ body: n,
72
+ signal: r
60
73
  });
61
- if (!t.ok) throw new Error(`AI API error: ${t.status} ${t.statusText}`);
62
- const d = t.body?.getReader();
63
- if (!d) throw new Error("No response body");
64
- const p = new TextDecoder();
65
- let r = "";
74
+ if (!s.ok) throw new Error(`AI API error: ${s.status} ${s.statusText}`);
75
+ const c = s.body?.getReader();
76
+ if (!c) throw new Error("No response body");
77
+ const i = new TextDecoder();
78
+ let o = "";
66
79
  for (; ; ) {
67
- const { done: m, value: y } = await d.read();
68
- if (m) break;
69
- r += p.decode(y, { stream: !0 });
70
- const i = r.split(`
80
+ const { done: y, value: p } = await c.read();
81
+ if (y) break;
82
+ o += i.decode(p, { stream: !0 });
83
+ const a = o.split(`
71
84
  `);
72
- r = i.pop() || "";
73
- for (const l of i) {
74
- const o = l.trim();
75
- if (o.startsWith("data: "))
85
+ o = a.pop() || "";
86
+ for (const m of a) {
87
+ const d = m.trim();
88
+ if (d.startsWith("data: "))
76
89
  try {
77
- const n = JSON.parse(o.slice(6));
78
- n.type === "content_block_delta" && n.delta?.text && (yield n.delta.text);
90
+ const l = JSON.parse(d.slice(6));
91
+ l.type === "content_block_delta" && l.delta?.text && (yield l.delta.text);
79
92
  } catch {
80
93
  }
81
94
  }
82
95
  }
83
96
  }
84
- function w(e, s, a) {
85
- return e.protocol === "anthropic" ? u(e, s, a) : h(e, s, a);
97
+ function w(t, e, r) {
98
+ return t.protocol === "anthropic" ? f(t, e, r) : h(t, e, r);
99
+ }
100
+ async function b(t, e, r) {
101
+ const n = r?.systemPrompt ?? t.systemPrompt, s = r?.imageDataUrl;
102
+ let c = e;
103
+ if (t.protocol === "anthropic") {
104
+ const a = [{
105
+ type: "text",
106
+ text: e
107
+ }];
108
+ if (s) {
109
+ const m = /^data:(.+?);base64,(.*)$/.exec(s);
110
+ m && a.unshift({
111
+ type: "image",
112
+ source: {
113
+ type: "base64",
114
+ media_type: m[1],
115
+ data: m[2]
116
+ }
117
+ });
118
+ }
119
+ c = a;
120
+ } else s && (c = [{
121
+ type: "text",
122
+ text: e
123
+ }, {
124
+ type: "image_url",
125
+ image_url: { url: s }
126
+ }]);
127
+ const i = n ? {
128
+ ...t,
129
+ systemPrompt: n
130
+ } : t, o = [{
131
+ role: "user",
132
+ content: c
133
+ }], y = i.protocol === "anthropic" ? f(i, o, r?.signal) : h(i, o, r?.signal);
134
+ let p = "";
135
+ for await (const a of y)
136
+ p += a, r?.onDelta?.(p);
137
+ return p;
86
138
  }
87
139
  export {
140
+ b as completeAIChatStream,
88
141
  w as streamAIChat
89
142
  };
90
143