dishui 0.0.45 → 0.0.46

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 (60) hide show
  1. package/dist/chart.js +46 -0
  2. package/dist/components/Chart/Chart.d.ts +17 -0
  3. package/dist/components/Chart/Chart.js +29 -0
  4. package/dist/components/Chart/Chart.js.map +1 -0
  5. package/dist/components/Chart/index.d.ts +15 -0
  6. package/dist/components/Input/index.js +2 -2
  7. package/dist/components/Input/index.js.map +1 -1
  8. package/dist/components/Select/index.js +1 -1
  9. package/dist/components/Select/index.js.map +1 -1
  10. package/dist/components/pro/Flow/Flow.js +492 -392
  11. package/dist/components/pro/Flow/Flow.js.map +1 -1
  12. package/dist/components/pro/Flow/FlowCanvas.js +895 -864
  13. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  14. package/dist/components/pro/Flow/context/FlowUIContext.d.ts +2 -0
  15. package/dist/components/pro/Flow/context/FlowUIContext.js +68 -65
  16. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  17. package/dist/components/pro/Flow/edges/edgePaths.js +234 -216
  18. package/dist/components/pro/Flow/edges/edgePaths.js.map +1 -1
  19. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js +21 -10
  20. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js.map +1 -1
  21. package/dist/components/pro/Flow/hooks/useMindMap.js +138 -134
  22. package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
  23. package/dist/components/pro/Flow/index.d.ts +1 -1
  24. package/dist/components/pro/Flow/nodes/MediaContent.js +47 -25
  25. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  26. package/dist/components/pro/Flow/nodes/Model3DView.d.ts +7 -0
  27. package/dist/components/pro/Flow/nodes/Model3DView.js +118 -0
  28. package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -0
  29. package/dist/components/pro/Flow/nodes/NodeHandles.d.ts +2 -1
  30. package/dist/components/pro/Flow/nodes/NodeHandles.js +4 -2
  31. package/dist/components/pro/Flow/nodes/NodeHandles.js.map +1 -1
  32. package/dist/components/pro/Flow/nodes/NodeRenderer.d.ts +2 -0
  33. package/dist/components/pro/Flow/nodes/NodeRenderer.js +115 -113
  34. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  35. package/dist/components/pro/Flow/nodes/NodeText.d.ts +3 -0
  36. package/dist/components/pro/Flow/nodes/NodeText.js +26 -17
  37. package/dist/components/pro/Flow/nodes/NodeText.js.map +1 -1
  38. package/dist/components/pro/Flow/panels/FlowToolbar.js +85 -79
  39. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  40. package/dist/components/pro/Flow/panels/InspectorPanel.js +618 -488
  41. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  42. package/dist/components/pro/Flow/panels/OutlinePanel.js +15 -15
  43. package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
  44. package/dist/components/pro/Flow/panels/ShapePalette.js +71 -55
  45. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  46. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +1 -0
  47. package/dist/components/pro/Flow/panels/toolbarIcons.js +59 -41
  48. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  49. package/dist/components/pro/Flow/types.d.ts +13 -4
  50. package/dist/components/pro/Flow/types.js.map +1 -1
  51. package/dist/dishui.css +1 -1
  52. package/dist/index-nostyled.d.ts +3 -1
  53. package/dist/index.d.ts +3 -1
  54. package/dist/index.js +145 -143
  55. package/dist/utils/i18n.d.ts +1 -0
  56. package/dist/utils/i18n.js +200 -6
  57. package/dist/utils/i18n.js.map +1 -1
  58. package/dist/utils/menu.js +26 -10
  59. package/dist/utils/menu.js.map +1 -1
  60. package/package.json +14 -3
@@ -1,63 +1,65 @@
1
- import { drawRoundRectBorder as R, shapeDrawers as v } from "./shapes.js";
2
- import { createNodeText as W, updateNodeText as M } from "./NodeText.js";
3
- import { createHandleGraphics as O, getHandlePositions as S, updateHandleGraphics as N } from "./NodeHandles.js";
4
- import { getFlipScale as z, getRotationRad as A } from "./nodeUtils.js";
5
- import { getIconTexture as I, subscribeIconTextureReady as T } from "./svgIconTexture.js";
6
- import { Container as C, Graphics as _, Sprite as H, Text as L } from "pixi.js";
7
- var E = class {
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 {
8
8
  world;
9
9
  nodeLayer;
10
10
  nodes = /* @__PURE__ */ new Map();
11
11
  _dynamicOffset = 0;
12
12
  _unsubscribeTextureReady;
13
- advanceAnimation(i) {
14
- this._dynamicOffset = (this._dynamicOffset + i * 0.06) % 1e3;
13
+ advanceAnimation(s) {
14
+ this._dynamicOffset = (this._dynamicOffset + s * 0.06) % 1e3;
15
15
  }
16
- constructor(i) {
17
- this.world = i, this.nodeLayer = new C({
16
+ constructor(s) {
17
+ this.world = s, this.nodeLayer = new _({
18
18
  label: "nodes",
19
19
  sortableChildren: !0
20
- }), this.world.addChild(this.nodeLayer), this._unsubscribeTextureReady = T(() => this._resync?.());
20
+ }), this.world.addChild(this.nodeLayer), this._unsubscribeTextureReady = G(() => this._resync?.());
21
21
  }
22
22
  _resync = null;
23
- sync(i, t, a, c, h) {
24
- const o = /* @__PURE__ */ new Set();
25
- this._resync = () => this.sync(i, t, a, c, h);
26
- const r = c ?? (() => {
27
- const e = i.filter((n) => n.type === "animAnchor").sort((n, f) => (n.data.animIndex ?? 0) - (f.data.animIndex ?? 0)), s = /* @__PURE__ */ new Map();
28
- return e.forEach((n, f) => s.set(n.id, f + 1)), s;
23
+ sync(s, t, l, f, d) {
24
+ 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;
29
29
  })();
30
- for (const e of i) {
31
- o.add(e.id);
32
- let s = this.nodes.get(e.id);
33
- s || (s = this._createNode(e), this.nodes.set(e.id, s)), this._updateNode(s, e, t.has(e.id), a === e.id, r.get(e.id), h);
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);
34
34
  }
35
- for (const [e, s] of this.nodes) o.has(e) || (this.nodeLayer.removeChild(s.container), s.container.destroy({ children: !0 }), this.nodes.delete(e));
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
36
  }
37
- getNodeContainer(i) {
38
- return this.nodes.get(i);
37
+ getNodeContainer(s) {
38
+ return this.nodes.get(s);
39
39
  }
40
40
  getAllNodeContainers() {
41
41
  return [...this.nodes.values()];
42
42
  }
43
- _createNode(i) {
44
- const t = new C({ label: `node-${i.id}` });
43
+ _createNode(s) {
44
+ const t = new _({ label: `node-${s.id}` });
45
45
  t.eventMode = "static", t.cursor = "pointer";
46
- const a = new _();
47
- a.label = "sub-canvas-glow", t.addChild(a);
48
- const c = new _();
49
- c.label = "shape", t.addChild(c);
50
- const h = new H();
51
- h.label = "svg-icon", h.anchor.set(0.5, 0.5), h.visible = !1, t.addChild(h);
52
- const o = W({
53
- label: i.data.label,
54
- color: i.data.labelColor ?? i.data.color,
55
- fontSize: i.data.fontSize,
56
- width: i.width,
57
- height: i.height
46
+ const l = new _({ label: "svg-transform" });
47
+ t.addChild(l);
48
+ const f = new W();
49
+ f.label = "sub-canvas-glow", t.addChild(f);
50
+ const d = new W();
51
+ d.label = "shape", t.addChild(d);
52
+ const r = new P();
53
+ r.label = "svg-icon", r.anchor.set(0.5, 0.5), r.visible = !1, t.addChild(r);
54
+ const e = O({
55
+ label: s.data.label,
56
+ color: s.data.labelColor ?? s.data.color,
57
+ fontSize: s.data.fontSize,
58
+ width: s.width,
59
+ height: s.height
58
60
  });
59
- t.addChild(o);
60
- const r = S(i.width, i.height), e = O(t, r, !1), s = new L({
61
+ t.addChild(e);
62
+ const i = R(s.width, s.height), a = A(t, i, !1), h = new D({
61
63
  text: "",
62
64
  style: {
63
65
  fontFamily: "system-ui, sans-serif",
@@ -66,120 +68,120 @@ var E = class {
66
68
  fontWeight: "700"
67
69
  }
68
70
  });
69
- return s.label = "anim-badge", s.anchor.set(0.5, 0.5), s.visible = !1, t.addChild(s), this.nodeLayer.addChild(t), {
71
+ return h.label = "anim-badge", h.anchor.set(0.5, 0.5), h.visible = !1, t.addChild(h), this.nodeLayer.addChild(t), {
70
72
  container: t,
71
- shape: c,
72
- icon: h,
73
- text: o,
74
- animBadge: s,
75
- handles: e,
76
- handleDefs: r,
77
- nodeId: i.id,
78
- subCanvasGlow: a
73
+ shape: d,
74
+ svgTransform: l,
75
+ icon: r,
76
+ text: e,
77
+ animBadge: h,
78
+ handles: a,
79
+ handleDefs: i,
80
+ nodeId: s.id,
81
+ subCanvasGlow: f
79
82
  };
80
83
  }
81
- _updateNode(i, t, a, c, h, o) {
82
- const { container: r, shape: e, icon: s, text: n, animBadge: f, handles: b, subCanvasGlow: y } = i;
83
- r.position.set(t.position.x, t.position.y), r.zIndex = t.zIndex ?? 0;
84
- const w = A(t.data), p = z(t.data);
85
- r.rotation = w, r.scale.set(p.sx, p.sy), w !== 0 || p.sx < 0 || p.sy < 0 ? (r.pivot.set(t.width / 2, t.height / 2), r.position.set(t.position.x + t.width / 2, t.position.y + t.height / 2)) : r.pivot.set(0, 0);
86
- const g = t.type === "shapeSvg", k = t.type === "mediaNode", m = t.type === "animAnchor";
87
- if (e.clear(), e.alpha = 1, g) this._updateSvgNode(i, t, a);
88
- else if (k) {
89
- s.visible = !1;
90
- const l = t.data.fill && t.data.fill !== "transparent" ? t.data.fill : "#ffffff", d = t.data.borderStyle === "none", u = a ? "#3b82f6" : t.data.stroke, x = a ? Math.max(t.data.strokeWidth, 2) : t.data.strokeWidth;
91
- v.shapeRoundRect(e, {
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";
88
+ if (a.clear(), a.alpha = 1, w) this._updateSvgNode(s, t, l);
89
+ else if (S) {
90
+ 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
93
  width: t.width,
93
94
  height: t.height,
94
- fill: l,
95
- stroke: u,
96
- strokeWidth: x,
97
- borderStyle: a && d ? "solid" : t.data.borderStyle,
95
+ fill: c,
96
+ stroke: p,
97
+ strokeWidth: C,
98
+ borderStyle: l && n ? "solid" : t.data.borderStyle,
98
99
  dashOffset: this._dynamicOffset
99
100
  });
100
- } else if (m) {
101
- s.visible = !1;
102
- const l = "#8b5cf6", d = o?.presentation ?? !1, u = d ? (o?.presentationAnchorVisible ?? !1) && o?.presentationAnchorId === t.id : o?.showAnchors ?? !0;
103
- u && (e.alpha = d ? 0.48 : 0.9, v.shapeRoundRect(e, {
101
+ } else if (x) {
102
+ 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
105
  width: t.width,
105
106
  height: t.height,
106
107
  fill: "transparent",
107
- stroke: a && !d ? "#3b82f6" : l,
108
- strokeWidth: a && !d ? 2.5 : 1.5,
108
+ stroke: l && !n ? "#3b82f6" : c,
109
+ strokeWidth: l && !n ? 2.5 : 1.5,
109
110
  borderStyle: "dashed"
110
- }), e.circle(0, 0, d ? 11 : 13).fill({ color: a && !d ? "#3b82f6" : l })), f.text = String(h ?? ""), f.alpha = d ? 0.7 : 1, f.visible = u, f.position.set(0, 0);
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);
111
112
  } else {
112
- s.visible = !1;
113
- const l = v[t.type] ?? v.shapeRect, d = t.data.borderStyle === "none";
114
- l(e, {
113
+ h.visible = !1;
114
+ const c = k[t.type] ?? k.shapeRect, n = t.data.borderStyle === "none";
115
+ c(a, {
115
116
  width: t.width,
116
117
  height: t.height,
117
118
  fill: t.data.fill,
118
- stroke: a ? "#3b82f6" : t.data.stroke,
119
- strokeWidth: a ? Math.max(t.data.strokeWidth, 2) : t.data.strokeWidth,
120
- borderStyle: a && d ? "solid" : t.data.borderStyle,
119
+ stroke: l ? "#3b82f6" : t.data.stroke,
120
+ strokeWidth: l ? Math.max(t.data.strokeWidth, 2) : t.data.strokeWidth,
121
+ borderStyle: l && n ? "solid" : t.data.borderStyle,
121
122
  dashOffset: this._dynamicOffset
122
123
  });
123
124
  }
124
- if (m || (f.visible = !1), y.clear(), t.data.childCanvasId) {
125
- const d = t.width + 8, u = t.height + 8, x = 0.5 + 0.3 * Math.sin(this._dynamicOffset * 8e-3);
126
- y.roundRect(-4, -4, d, u, 6), y.stroke({
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);
127
+ y.roundRect(-4, -4, n, p, 6), y.stroke({
127
128
  color: 9133302,
128
129
  width: 2.5,
129
- alpha: x
130
- }), y.roundRect(-6, -6, d + 4, u + 4, 8), y.stroke({
130
+ alpha: C
131
+ }), y.roundRect(-6, -6, n + 4, p + 4, 8), y.stroke({
131
132
  color: 9133302,
132
133
  width: 1,
133
- alpha: x * 0.4
134
+ alpha: C * 0.4
134
135
  });
135
136
  }
136
- if (M(n, {
137
- label: k || m ? "" : t.data.label,
137
+ const v = I(t.data.labelPlacement);
138
+ if (N(o, {
139
+ label: S || x ? "" : w ? T(t.data.label, v) : t.data.label,
138
140
  color: t.data.labelColor ?? t.data.color,
139
141
  fontSize: t.data.fontSize,
140
142
  width: t.width,
141
143
  height: t.height
142
- }), n.visible = !k && !m, t.type === "shapeCorner") {
143
- const l = Math.min(t.width, t.height) * 0.4;
144
- n.position.set((l + t.width) / 2, (l + t.height) / 2);
145
- } else if (g) {
146
- const l = t.data.labelPlacement ?? "below";
147
- l === "below" ? n.position.set(t.width / 2, t.height + 2 + (t.data.fontSize ?? 12) / 2) : l === "above" ? n.position.set(t.width / 2, -2 - (t.data.fontSize ?? 12) / 2) : n.position.set(t.width / 2, t.height / 2);
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);
147
+ } else if (w) {
148
+ 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;
148
150
  }
149
- if (n.rotation = -w, n.scale.set(p.sx, p.sy), b.visible = (c || a) && !(m && o?.presentation), b.visible) {
150
- const l = S(t.width, t.height);
151
- i.handleDefs = l, N(b, l);
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
154
  }
153
155
  }
154
- _updateSvgNode(i, t, a) {
155
- const { shape: c, icon: h } = i, { width: o, height: r, data: e } = t, s = e.iconBox ?? !1, n = e.borderStyle ?? (s ? "solid" : "none"), f = n === "none", b = Math.min(8, o * 0.12, r * 0.12);
156
- e.fill && e.fill !== "transparent" && (s || !f) && c.roundRect(0, 0, o, r, b).fill({ color: e.fill }), !f && e.stroke && e.stroke !== "transparent" && e.strokeWidth > 0 && R(c, {
157
- width: o,
158
- height: r,
156
+ _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, {
159
+ width: r,
160
+ height: e,
159
161
  fill: "transparent",
160
- stroke: e.stroke,
161
- strokeWidth: e.strokeWidth,
162
- borderStyle: n,
162
+ stroke: i.stroke,
163
+ strokeWidth: i.strokeWidth,
164
+ borderStyle: h,
163
165
  dashOffset: this._dynamicOffset
164
- }, b), a && c.roundRect(0, 0, o, r, b).stroke({
166
+ }, b), l && f.roundRect(0, 0, r, e, b).stroke({
165
167
  color: "#3b82f6",
166
- width: Math.max(e.strokeWidth, 2)
168
+ width: Math.max(i.strokeWidth, 2)
167
169
  });
168
- const y = e.color || "#334155", w = I(e.svgId ?? "", y);
169
- if (w) {
170
- h.texture = w, h.visible = !0;
171
- const p = s ? Math.min(o, r) * 0.18 : 2, g = Math.max(4, Math.min(o, r) - p * 2);
172
- h.width = g, h.height = g, h.position.set(o / 2, r / 2);
173
- } else h.visible = !1;
170
+ const g = i.color || "#334155", y = B(i.svgId ?? "", g);
171
+ if (y) {
172
+ 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);
175
+ } else d.visible = !1;
174
176
  }
175
177
  destroy() {
176
178
  this._unsubscribeTextureReady(), this._resync = null;
177
- for (const [, i] of this.nodes) i.container.destroy({ children: !0 });
179
+ for (const [, s] of this.nodes) s.container.destroy({ children: !0 });
178
180
  this.nodes.clear(), this.nodeLayer.destroy({ children: !0 });
179
181
  }
180
182
  };
181
183
  export {
182
- E as NodeRenderer
184
+ j as NodeRenderer
183
185
  };
184
186
 
185
187
  //# 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, 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 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 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, 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, shape, icon, text, animBadge, handles, subCanvasGlow } = nc;\n\n // Position\n container.position.set(node.position.x, node.position.y);\n\n container.zIndex = node.zIndex ?? 0;\n\n // Rotation & flip\n const rad = getRotationRad(node.data);\n const flip = getFlipScale(node.data);\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 const isSvg = node.type === 'shapeSvg';\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 updateNodeText(text, {\n label: isMedia || isAnchor ? '' : 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 // SVG stamps: label sits below the icon by default (drawio-like).\n const placement = node.data.labelPlacement ?? 'below';\n if (placement === 'below') {\n text.position.set(node.width / 2, node.height + 2 + (node.data.fontSize ?? 12) / 2);\n } else if (placement === 'above') {\n text.position.set(node.width / 2, -2 - (node.data.fontSize ?? 12) / 2);\n } else {\n text.position.set(node.width / 2, node.height / 2);\n }\n }\n\n text.rotation = -rad;\n text.scale.set(flip.sx, flip.sy);\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';\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,4 +1,5 @@
1
1
  import { Text } from 'pixi.js';
2
+ import type { FlowIconLabelPlacement } from '../types';
2
3
  export interface NodeTextOptions {
3
4
  label: string;
4
5
  color: string;
@@ -12,4 +13,6 @@ export interface NodeTextOptions {
12
13
  * centered within the node bounds.
13
14
  */
14
15
  export declare function createNodeText(opts: NodeTextOptions): Text;
16
+ export declare function normalizeIconLabelPlacement(value: unknown): FlowIconLabelPlacement;
17
+ export declare function formatIconLabel(label: string, placement: FlowIconLabelPlacement): string;
15
18
  export declare function updateNodeText(text: Text, opts: NodeTextOptions): void;
@@ -1,26 +1,35 @@
1
- import { Text as n, TextStyle as l } from "pixi.js";
2
- function r(e) {
3
- const t = new l({
4
- fontFamily: e.fontFamily ?? "system-ui, -apple-system, sans-serif",
5
- fontSize: e.fontSize,
6
- fill: e.color,
1
+ import { Text as r, TextStyle as i } from "pixi.js";
2
+ function f(t) {
3
+ const e = new i({
4
+ fontFamily: t.fontFamily ?? "system-ui, -apple-system, sans-serif",
5
+ fontSize: t.fontSize,
6
+ fill: t.color,
7
7
  align: "center",
8
8
  wordWrap: !0,
9
- wordWrapWidth: e.width - 16
10
- }), i = new n({
11
- text: e.label,
12
- style: t
9
+ wordWrapWidth: t.width - 16
10
+ }), n = new r({
11
+ text: t.label,
12
+ style: e
13
13
  });
14
- return i.anchor.set(0.5, 0.5), i.position.set(e.width / 2, e.height / 2), i.label = "node-text", i;
14
+ return n.anchor.set(0.5, 0.5), n.position.set(t.width / 2, t.height / 2), n.label = "node-text", n;
15
15
  }
16
- function a(e, t) {
17
- e.text = t.label;
18
- const i = e.style;
19
- i.fontSize = t.fontSize, i.fill = t.color, i.wordWrapWidth = t.width - 16, e.position.set(t.width / 2, t.height / 2);
16
+ function d(t) {
17
+ return t === "above" ? "top" : t === "center" ? "middle" : t === "below" ? "bottom" : t === "top" || t === "middle" || t === "bottom" || t === "left" || t === "right" ? t : "bottom";
18
+ }
19
+ function m(t, e) {
20
+ return e !== "left" && e !== "right" ? t : (typeof Intl < "u" && "Segmenter" in Intl ? Array.from(new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(t), (n) => n.segment) : Array.from(t)).join(`
21
+ `);
22
+ }
23
+ function l(t, e) {
24
+ t.text = e.label;
25
+ const n = t.style;
26
+ n.fontSize = e.fontSize, n.fill = e.color, n.wordWrapWidth = e.width - 16, t.position.set(e.width / 2, e.height / 2);
20
27
  }
21
28
  export {
22
- r as createNodeText,
23
- a as updateNodeText
29
+ f as createNodeText,
30
+ m as formatIconLabel,
31
+ d as normalizeIconLabelPlacement,
32
+ l as updateNodeText
24
33
  };
25
34
 
26
35
  //# sourceMappingURL=NodeText.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeText.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/NodeText.ts"],"sourcesContent":["import { Text, TextStyle, Container } from 'pixi.js';\n\nexport interface NodeTextOptions {\n label: string;\n color: string;\n fontSize: number;\n width: number;\n height: number;\n fontFamily?: string;\n}\n\n/**\n * Creates or updates a PixiJS Text object for a node label,\n * centered within the node bounds.\n */\nexport function createNodeText(opts: NodeTextOptions): Text {\n const style = new TextStyle({\n fontFamily: opts.fontFamily ?? 'system-ui, -apple-system, sans-serif',\n fontSize: opts.fontSize,\n fill: opts.color,\n align: 'center',\n wordWrap: true,\n wordWrapWidth: opts.width - 16,\n });\n\n const text = new Text({ text: opts.label, style });\n text.anchor.set(0.5, 0.5);\n text.position.set(opts.width / 2, opts.height / 2);\n text.label = 'node-text';\n return text;\n}\n\nexport function updateNodeText(text: Text, opts: NodeTextOptions): void {\n text.text = opts.label;\n const s = text.style as TextStyle;\n s.fontSize = opts.fontSize;\n s.fill = opts.color;\n s.wordWrapWidth = opts.width - 16;\n text.position.set(opts.width / 2, opts.height / 2);\n}\n"],"mappings":";AAeA,SAAgB,EAAe,GAA6B;AAC1D,QAAM,IAAQ,IAAI,EAAU;AAAA,IAC1B,YAAY,EAAK,cAAc;AAAA,IAC/B,UAAU,EAAK;AAAA,IACf,MAAM,EAAK;AAAA,IACX,OAAO;AAAA,IACP,UAAU;AAAA,IACV,eAAe,EAAK,QAAQ;AAAA,EAC9B,CAAC,GAEK,IAAO,IAAI,EAAK;AAAA,IAAE,MAAM,EAAK;AAAA,IAAO,OAAA;AAAA,EAAM,CAAC;AACjD,SAAA,EAAK,OAAO,IAAI,KAAK,GAAG,GACxB,EAAK,SAAS,IAAI,EAAK,QAAQ,GAAG,EAAK,SAAS,CAAC,GACjD,EAAK,QAAQ,aACN;AACT;AAEA,SAAgB,EAAe,GAAY,GAA6B;AACtE,EAAA,EAAK,OAAO,EAAK;AACjB,QAAM,IAAI,EAAK;AACf,EAAA,EAAE,WAAW,EAAK,UAClB,EAAE,OAAO,EAAK,OACd,EAAE,gBAAgB,EAAK,QAAQ,IAC/B,EAAK,SAAS,IAAI,EAAK,QAAQ,GAAG,EAAK,SAAS,CAAC;AACnD"}
1
+ {"version":3,"file":"NodeText.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/NodeText.ts"],"sourcesContent":["import { Text, TextStyle, Container } from 'pixi.js';\nimport type { FlowIconLabelPlacement } from '../types';\n\nexport interface NodeTextOptions {\n label: string;\n color: string;\n fontSize: number;\n width: number;\n height: number;\n fontFamily?: string;\n}\n\n/**\n * Creates or updates a PixiJS Text object for a node label,\n * centered within the node bounds.\n */\nexport function createNodeText(opts: NodeTextOptions): Text {\n const style = new TextStyle({\n fontFamily: opts.fontFamily ?? 'system-ui, -apple-system, sans-serif',\n fontSize: opts.fontSize,\n fill: opts.color,\n align: 'center',\n wordWrap: true,\n wordWrapWidth: opts.width - 16,\n });\n\n const text = new Text({ text: opts.label, style });\n text.anchor.set(0.5, 0.5);\n text.position.set(opts.width / 2, opts.height / 2);\n text.label = 'node-text';\n return text;\n}\n\nexport function normalizeIconLabelPlacement(value: unknown): FlowIconLabelPlacement {\n if (value === 'above') return 'top';\n if (value === 'center') return 'middle';\n if (value === 'below') return 'bottom';\n return value === 'top' || value === 'middle' || value === 'bottom' || value === 'left' || value === 'right'\n ? value\n : 'bottom';\n}\n\nexport function formatIconLabel(label: string, placement: FlowIconLabelPlacement): string {\n if (placement !== 'left' && placement !== 'right') return label;\n const segments = typeof Intl !== 'undefined' && 'Segmenter' in Intl\n ? Array.from(new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(label), item => item.segment)\n : Array.from(label);\n return segments.join('\\n');\n}\n\nexport function updateNodeText(text: Text, opts: NodeTextOptions): void {\n text.text = opts.label;\n const s = text.style as TextStyle;\n s.fontSize = opts.fontSize;\n s.fill = opts.color;\n s.wordWrapWidth = opts.width - 16;\n text.position.set(opts.width / 2, opts.height / 2);\n}\n"],"mappings":";AAgBA,SAAgB,EAAe,GAA6B;AAC1D,QAAM,IAAQ,IAAI,EAAU;AAAA,IAC1B,YAAY,EAAK,cAAc;AAAA,IAC/B,UAAU,EAAK;AAAA,IACf,MAAM,EAAK;AAAA,IACX,OAAO;AAAA,IACP,UAAU;AAAA,IACV,eAAe,EAAK,QAAQ;AAAA,EAC9B,CAAC,GAEK,IAAO,IAAI,EAAK;AAAA,IAAE,MAAM,EAAK;AAAA,IAAO,OAAA;AAAA,EAAM,CAAC;AACjD,SAAA,EAAK,OAAO,IAAI,KAAK,GAAG,GACxB,EAAK,SAAS,IAAI,EAAK,QAAQ,GAAG,EAAK,SAAS,CAAC,GACjD,EAAK,QAAQ,aACN;AACT;AAEA,SAAgB,EAA4B,GAAwC;AAClF,SAAI,MAAU,UAAgB,QAC1B,MAAU,WAAiB,WAC3B,MAAU,UAAgB,WACvB,MAAU,SAAS,MAAU,YAAY,MAAU,YAAY,MAAU,UAAU,MAAU,UAChG,IACA;AACN;AAEA,SAAgB,EAAgB,GAAe,GAA2C;AACxF,SAAI,MAAc,UAAU,MAAc,UAAgB,KACzC,OAAO,OAAS,OAAe,eAAe,OAC3D,MAAM,KAAK,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC,EAAE,QAAQ,CAAK,GAAA,CAAG,MAAQ,EAAK,OAAO,IAC1G,MAAM,KAAK,CAAK,GACJ,KAAK;AAAA,CAAI;AAC3B;AAEA,SAAgB,EAAe,GAAY,GAA6B;AACtE,EAAA,EAAK,OAAO,EAAK;AACjB,QAAM,IAAI,EAAK;AACf,EAAA,EAAE,WAAW,EAAK,UAClB,EAAE,OAAO,EAAK,OACd,EAAE,gBAAgB,EAAK,QAAQ,IAC/B,EAAK,SAAS,IAAI,EAAK,QAAQ,GAAG,EAAK,SAAS,CAAC;AACnD"}