@particle-academy/fancy-flow 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/{chunk-AUL4LU63.js → chunk-ATQXZEVD.js} +122 -7
  2. package/dist/chunk-ATQXZEVD.js.map +1 -0
  3. package/dist/{chunk-OHVSEHDC.js → chunk-N5ICD2WZ.js} +3 -3
  4. package/dist/{chunk-OHVSEHDC.js.map → chunk-N5ICD2WZ.js.map} +1 -1
  5. package/dist/{chunk-O7F6SGV4.js → chunk-OFW7GN3Y.js} +18 -6
  6. package/dist/chunk-OFW7GN3Y.js.map +1 -0
  7. package/dist/{chunk-ZB4HHQMR.js → chunk-OWENS2H5.js} +11 -3
  8. package/dist/chunk-OWENS2H5.js.map +1 -0
  9. package/dist/{chunk-YXRLIV7A.js → chunk-Q6IPK64P.js} +4 -2
  10. package/dist/chunk-Q6IPK64P.js.map +1 -0
  11. package/dist/{chunk-KDHLKBL2.js → chunk-U2VJB7HR.js} +7 -5
  12. package/dist/chunk-U2VJB7HR.js.map +1 -0
  13. package/dist/engine.cjs +4 -2
  14. package/dist/engine.cjs.map +1 -1
  15. package/dist/engine.js +3 -3
  16. package/dist/index.cjs +382 -130
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +7 -10
  19. package/dist/index.d.ts +7 -10
  20. package/dist/index.js +177 -64
  21. package/dist/index.js.map +1 -1
  22. package/dist/registry/index.d.cts +2 -2
  23. package/dist/registry/index.d.ts +2 -2
  24. package/dist/registry.cjs +114 -2
  25. package/dist/registry.cjs.map +1 -1
  26. package/dist/registry.js +4 -4
  27. package/dist/runtime/index.d.cts +13 -1
  28. package/dist/runtime/index.d.ts +13 -1
  29. package/dist/runtime.cjs +17 -3
  30. package/dist/runtime.cjs.map +1 -1
  31. package/dist/runtime.js +4 -4
  32. package/dist/schema.cjs.map +1 -1
  33. package/dist/schema.js +2 -2
  34. package/dist/styles.css +80 -0
  35. package/dist/styles.css.map +1 -1
  36. package/dist/{types-CFEtuRWJ.d.ts → types-BGtR3k9J.d.ts} +8 -1
  37. package/dist/{types-DneUoivl.d.cts → types-B_pxRqfw.d.cts} +8 -1
  38. package/dist/ux.cjs.map +1 -1
  39. package/dist/ux.d.cts +1 -1
  40. package/dist/ux.d.ts +1 -1
  41. package/dist/ux.js +1 -1
  42. package/package.json +1 -1
  43. package/dist/chunk-AUL4LU63.js.map +0 -1
  44. package/dist/chunk-KDHLKBL2.js.map +0 -1
  45. package/dist/chunk-O7F6SGV4.js.map +0 -1
  46. package/dist/chunk-YXRLIV7A.js.map +0 -1
  47. package/dist/chunk-ZB4HHQMR.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -81,19 +81,19 @@ function we(e, n, t, r) {
81
81
  }
82
82
  function Nn(e, n, t, r) {
83
83
  let o = {}, i, s = 0, a = e.nodes(), d = function(c) {
84
- let h = t(c);
85
- o[c.v].distance + h < o[c.w].distance && (o[c.w] = { distance: o[c.v].distance + h, predecessor: c.v }, i = true);
84
+ let h2 = t(c);
85
+ o[c.v].distance + h2 < o[c.w].distance && (o[c.w] = { distance: o[c.v].distance + h2, predecessor: c.v }, i = true);
86
86
  }, l = function() {
87
87
  a.forEach(function(c) {
88
- r(c).forEach(function(h) {
89
- let f = h.v === c ? h.v : h.w, g = f === h.v ? h.w : h.v;
88
+ r(c).forEach(function(h2) {
89
+ let f = h2.v === c ? h2.v : h2.w, g = f === h2.v ? h2.w : h2.v;
90
90
  d({ v: f, w: g });
91
91
  });
92
92
  });
93
93
  };
94
94
  a.forEach(function(c) {
95
- let h = c === n ? 0 : Number.POSITIVE_INFINITY;
96
- o[c] = { distance: h, predecessor: "" };
95
+ let h2 = c === n ? 0 : Number.POSITIVE_INFINITY;
96
+ o[c] = { distance: h2, predecessor: "" };
97
97
  });
98
98
  let u = a.length;
99
99
  for (let c = 1; c < u && (i = false, s++, l(), !!i); c++) ;
@@ -117,8 +117,8 @@ function F(e, n, t, r) {
117
117
  }
118
118
  function vn(e, n, t, r) {
119
119
  let o = {}, i = new Ne(), s, a, d = function(l) {
120
- let u = l.v !== s ? l.v : l.w, c = o[u], h = t(l), f = a.distance + h;
121
- if (h < 0) throw new Error("dijkstra does not allow negative edge weights. Bad edge: " + l + " Weight: " + h);
120
+ let u = l.v !== s ? l.v : l.w, c = o[u], h2 = t(l), f = a.distance + h2;
121
+ if (h2 < 0) throw new Error("dijkstra does not allow negative edge weights. Bad edge: " + l + " Weight: " + h2);
122
122
  f < c.distance && (c.distance = f, c.predecessor = s, i.decrease(u, f));
123
123
  };
124
124
  for (e.nodes().forEach(function(l) {
@@ -174,8 +174,8 @@ function In(e, n, t) {
174
174
  o.forEach(function(a) {
175
175
  let d = r[a];
176
176
  o.forEach(function(l) {
177
- let u = d[i], c = s[l], h = d[l], f = u.distance + c.distance;
178
- f < h.distance && (h.distance = f, h.predecessor = c.predecessor);
177
+ let u = d[i], c = s[l], h2 = d[l], f = u.distance + c.distance;
178
+ f < h2.distance && (h2.distance = f, h2.predecessor = c.predecessor);
179
179
  });
180
180
  });
181
181
  }), r;
@@ -268,7 +268,7 @@ function Fn(e, n, t, r) {
268
268
  }
269
269
  return F(e, n, t, r);
270
270
  }
271
- function w(e, n, t, r) {
271
+ function w2(e, n, t, r) {
272
272
  let o = r;
273
273
  for (; e.hasNode(o); ) o = j(r);
274
274
  return t.dummy = n, e.setNode(o, t), o;
@@ -324,7 +324,7 @@ function Oe(e) {
324
324
  }
325
325
  function q(e, n, t, r) {
326
326
  let o = { width: 0, height: 0 };
327
- return arguments.length >= 4 && (o.rank = t, o.order = r), w(e, "border", o, n);
327
+ return arguments.length >= 4 && (o.rank = t, o.order = r), w2(e, "border", o, n);
328
328
  }
329
329
  function Dn(e, n = Ie) {
330
330
  let t = [];
@@ -431,8 +431,8 @@ function Yn(e, n) {
431
431
  }), e.edges().forEach((a) => {
432
432
  let d = t.edge(a.v, a.w) || 0, l = n(a), u = d + l;
433
433
  t.setEdge(a.v, a.w, u);
434
- let c = t.node(a.v), h = t.node(a.w);
435
- o = Math.max(o, c.out += l), r = Math.max(r, h.in += l);
434
+ let c = t.node(a.v), h2 = t.node(a.w);
435
+ o = Math.max(o, c.out += l), r = Math.max(r, h2.in += l);
436
436
  });
437
437
  let i = zn(o + r + 3).map(() => new Me()), s = r + 1;
438
438
  return t.nodes().forEach((a) => {
@@ -484,7 +484,7 @@ function Xn(e, n) {
484
484
  if (i === r + 1) return;
485
485
  e.removeEdge(n);
486
486
  let l, u, c;
487
- for (c = 0, ++r; r < i; ++c, ++r) a.points = [], u = { width: 0, height: 0, edgeLabel: a, edgeObj: n, rank: r }, l = w(e, "edge", u, "_d"), r === d && (u.width = a.width, u.height = a.height, u.dummy = "edge-label", u.labelpos = a.labelpos), e.setEdge(t, l, { weight: a.weight }, s), c === 0 && e.graph().dummyChains.push(l), t = l;
487
+ for (c = 0, ++r; r < i; ++c, ++r) a.points = [], u = { width: 0, height: 0, edgeLabel: a, edgeObj: n, rank: r }, l = w2(e, "edge", u, "_d"), r === d && (u.width = a.width, u.height = a.height, u.dummy = "edge-label", u.labelpos = a.labelpos), e.setEdge(t, l, { weight: a.weight }, s), c === 0 && e.graph().dummyChains.push(l), t = l;
488
488
  e.setEdge(t, o, { weight: a.weight }, s);
489
489
  }
490
490
  function De(e) {
@@ -557,10 +557,10 @@ function We(e, n, t) {
557
557
  return d && d.forEach((l) => {
558
558
  let u = l.v === t, c = u ? l.w : l.v;
559
559
  if (c !== o) {
560
- let h = u === i, f = n.edge(l).weight;
561
- if (a += h ? f : -f, rt(e, t, c)) {
560
+ let h2 = u === i, f = n.edge(l).weight;
561
+ if (a += h2 ? f : -f, rt(e, t, c)) {
562
562
  let b = e.edge(t, c).cutvalue;
563
- a += h ? -b : b;
563
+ a += h2 ? -b : b;
564
564
  }
565
565
  }
566
566
  }), a;
@@ -665,7 +665,7 @@ function lt(e) {
665
665
  return e.children(_).forEach(r), n;
666
666
  }
667
667
  function Ke(e) {
668
- let n = w(e, "root", {}, "_root"), t = ut(e), r = Object.values(t), o = L(Math.max, r) - 1, i = 2 * o + 1;
668
+ let n = w2(e, "root", {}, "_root"), t = ut(e), r = Object.values(t), o = L(Math.max, r) - 1, i = 2 * o + 1;
669
669
  e.graph().nestingRoot = n, e.edges().forEach((a) => e.edge(a).minlen *= i);
670
670
  let s = ct(e) + 1;
671
671
  e.children(_).forEach((a) => $e(e, n, i, s, o, t, a)), e.graph().nodeRankFactor = i;
@@ -678,10 +678,10 @@ function $e(e, n, t, r, o, i, s) {
678
678
  return;
679
679
  }
680
680
  let d = q(e, "_bt"), l = q(e, "_bb"), u = e.node(s);
681
- e.setParent(d, s), u.borderTop = d, e.setParent(l, s), u.borderBottom = l, a.forEach((h) => {
681
+ e.setParent(d, s), u.borderTop = d, e.setParent(l, s), u.borderBottom = l, a.forEach((h2) => {
682
682
  var y;
683
- $e(e, n, t, r, o, i, h);
684
- let f = e.node(h), g = f.borderTop ? f.borderTop : h, b = f.borderBottom ? f.borderBottom : h, m = f.borderTop ? r : 2 * r, E = g !== b ? 1 : o - ((y = i[s]) != null ? y : 0) + 1;
683
+ $e(e, n, t, r, o, i, h2);
684
+ let f = e.node(h2), g = f.borderTop ? f.borderTop : h2, b = f.borderBottom ? f.borderBottom : h2, m = f.borderTop ? r : 2 * r, E = g !== b ? 1 : o - ((y = i[s]) != null ? y : 0) + 1;
685
685
  e.setEdge(d, g, { weight: m, minlen: E, nestingEdge: true }), e.setEdge(b, l, { weight: m, minlen: E, nestingEdge: true });
686
686
  }), e.parent(s) || e.setEdge(n, d, { weight: 0, minlen: o + ((c = i[s]) != null ? c : 0) });
687
687
  }
@@ -713,7 +713,7 @@ function ft(e) {
713
713
  e.children(_).forEach(n);
714
714
  }
715
715
  function Qe(e, n, t, r, o, i) {
716
- let s = { width: 0, height: 0, rank: i, borderType: n }, a = o[n][i - 1], d = w(e, "border", s, t);
716
+ let s = { width: 0, height: 0, rank: i, borderType: n }, a = o[n][i - 1], d = w2(e, "border", s, t);
717
717
  o[n][i] = d, e.setParent(d, r), a && e.setEdge(a, d, { weight: 1 });
718
718
  }
719
719
  function nn(e) {
@@ -774,7 +774,7 @@ function oe(e, n) {
774
774
  function mt(e, n, t) {
775
775
  let r = Re(t, t.map((l, u) => u)), o = n.flatMap((l) => {
776
776
  let u = e.outEdges(l);
777
- return u ? u.map((c) => ({ pos: r[c.w], weight: e.edge(c).weight })).sort((c, h) => c.pos - h.pos) : [];
777
+ return u ? u.map((c) => ({ pos: r[c.w], weight: e.edge(c).weight })).sort((c, h2) => c.pos - h2.pos) : [];
778
778
  }), i = 1;
779
779
  for (; i < t.length; ) i <<= 1;
780
780
  let s = 2 * i - 1;
@@ -853,12 +853,12 @@ function yt(e) {
853
853
  }
854
854
  function W(e, n, t, r) {
855
855
  let o = e.children(n), i = e.node(n), s = i ? i.borderLeft : void 0, a = i ? i.borderRight : void 0, d = {};
856
- s && (o = o.filter((h) => h !== s && h !== a));
856
+ s && (o = o.filter((h2) => h2 !== s && h2 !== a));
857
857
  let l = ie(e, o);
858
- l.forEach((h) => {
859
- if (e.children(h.v).length) {
860
- let f = W(e, h.v, t, r);
861
- d[h.v] = f, Object.hasOwn(f, "barycenter") && Nt(h, f);
858
+ l.forEach((h2) => {
859
+ if (e.children(h2.v).length) {
860
+ let f = W(e, h2.v, t, r);
861
+ d[h2.v] = f, Object.hasOwn(f, "barycenter") && Nt(h2, f);
862
862
  }
863
863
  });
864
864
  let u = se(l, t);
@@ -866,9 +866,9 @@ function W(e, n, t, r) {
866
866
  let c = ae(u, r);
867
867
  if (s && a) {
868
868
  c.vs = [s, c.vs, a].flat(1);
869
- let h = e.predecessors(s);
870
- if (h && h.length) {
871
- let f = e.node(h[0]), g = e.predecessors(a), b = e.node(g[0]);
869
+ let h2 = e.predecessors(s);
870
+ if (h2 && h2.length) {
871
+ let f = e.node(h2[0]), g = e.predecessors(a), b = e.node(g[0]);
872
872
  Object.hasOwn(c, "barycenter") || (c.barycenter = 0, c.weight = 0), c.barycenter = (c.barycenter * c.weight + f.order + b.order) / (c.weight + 2), c.weight += 2;
873
873
  }
874
874
  }
@@ -891,7 +891,7 @@ function de(e, n, t, r) {
891
891
  i.setNode(s), i.setParent(s, d || o);
892
892
  let l = e[t](s);
893
893
  l && l.forEach((u) => {
894
- let c = u.v === s ? u.w : u.v, h = i.edge(c, s), f = h !== void 0 ? h.weight : 0;
894
+ let c = u.v === s ? u.w : u.v, h2 = i.edge(c, s), f = h2 !== void 0 ? h2.weight : 0;
895
895
  i.setEdge(c, s, { weight: e.edge(u).weight + f });
896
896
  }), Object.hasOwn(a, "minRank") && i.setNode(s, { borderLeft: a.borderLeft[n], borderRight: a.borderRight[n] });
897
897
  }
@@ -958,8 +958,8 @@ function vt(e, n) {
958
958
  function r(o, i) {
959
959
  let s = 0, a = 0, d = o.length, l = i[i.length - 1];
960
960
  return i.forEach((u, c) => {
961
- let h = xt(e, u), f = h ? e.node(h).order : d;
962
- (h || u === l) && (i.slice(a, c + 1).forEach((g) => {
961
+ let h2 = xt(e, u), f = h2 ? e.node(h2).order : d;
962
+ (h2 || u === l) && (i.slice(a, c + 1).forEach((g) => {
963
963
  let b = e.predecessors(g);
964
964
  b && b.forEach((m) => {
965
965
  let E = e.node(m), y = E.order;
@@ -976,8 +976,8 @@ function _t(e, n) {
976
976
  k(s, a).forEach((u) => {
977
977
  let c = i[u];
978
978
  if (c !== void 0 && e.node(c).dummy) {
979
- let h = e.predecessors(c);
980
- h && h.forEach((f) => {
979
+ let h2 = e.predecessors(c);
980
+ h2 && h2.forEach((f) => {
981
981
  if (f === void 0) return;
982
982
  let g = e.node(f);
983
983
  g.dummy && (g.order < d || g.order > l) && dn(t, f, c);
@@ -989,9 +989,9 @@ function _t(e, n) {
989
989
  let a = -1, d = -1, l = 0;
990
990
  return s.forEach((u, c) => {
991
991
  if (e.node(u).dummy === "border") {
992
- let h = e.predecessors(u);
993
- if (h && h.length) {
994
- let f = h[0];
992
+ let h2 = e.predecessors(u);
993
+ if (h2 && h2.length) {
994
+ let f = h2[0];
995
995
  if (f === void 0) return;
996
996
  d = e.node(f).order, r(s, l, c, a, d), l = c, a = d;
997
997
  }
@@ -1037,8 +1037,8 @@ function Ot(e, n, t, r) {
1037
1037
  let c = u.sort((f, g) => {
1038
1038
  let b = s[f], m = s[g];
1039
1039
  return (b !== void 0 ? b : 0) - (m !== void 0 ? m : 0);
1040
- }), h = (c.length - 1) / 2;
1041
- for (let f = Math.floor(h), g = Math.ceil(h); f <= g; ++f) {
1040
+ }), h2 = (c.length - 1) / 2;
1041
+ for (let f = Math.floor(h2), g = Math.ceil(h2); f <= g; ++f) {
1042
1042
  let b = c[f];
1043
1043
  if (b === void 0) continue;
1044
1044
  let m = s[b];
@@ -1084,10 +1084,10 @@ function It(e, n, t, r, o = false) {
1084
1084
  function c(f) {
1085
1085
  return s.predecessors(f) || [];
1086
1086
  }
1087
- function h(f) {
1087
+ function h2(f) {
1088
1088
  return s.successors(f) || [];
1089
1089
  }
1090
- return d(l, c), d(u, h), Object.keys(r).forEach((f) => {
1090
+ return d(l, c), d(u, h2), Object.keys(r).forEach((f) => {
1091
1091
  var b;
1092
1092
  let g = t[f];
1093
1093
  g !== void 0 && (i[f] = (b = i[g]) != null ? b : 0);
@@ -1103,8 +1103,8 @@ function Ct(e, n, t, r) {
1103
1103
  if (o.setNode(u), d !== void 0) {
1104
1104
  let c = t[d];
1105
1105
  if (c !== void 0) {
1106
- let h = o.edge(c, u);
1107
- o.setEdge(c, u, Math.max(s(e, l, d), h || 0));
1106
+ let h2 = o.edge(c, u);
1107
+ o.setEdge(c, u, Math.max(s(e, l, d), h2 || 0));
1108
1108
  }
1109
1109
  }
1110
1110
  d = l;
@@ -1248,7 +1248,7 @@ function Kt(e) {
1248
1248
  let t = e.edge(n);
1249
1249
  if (t.width && t.height) {
1250
1250
  let r = e.node(n.v), i = { rank: (e.node(n.w).rank - r.rank) / 2 + r.rank, e: n };
1251
- w(e, "edge-proxy", i, "_ep");
1251
+ w2(e, "edge-proxy", i, "_ep");
1252
1252
  }
1253
1253
  });
1254
1254
  }
@@ -1271,8 +1271,8 @@ function Jt(e) {
1271
1271
  function Qt(e) {
1272
1272
  let n = Number.POSITIVE_INFINITY, t = 0, r = Number.POSITIVE_INFINITY, o = 0, i = e.graph(), s = i.marginx || 0, a = i.marginy || 0;
1273
1273
  function d(l) {
1274
- let u = l.x, c = l.y, h = l.width, f = l.height;
1275
- n = Math.min(n, u - h / 2), t = Math.max(t, u + h / 2), r = Math.min(r, c - f / 2), o = Math.max(o, c + f / 2);
1274
+ let u = l.x, c = l.y, h2 = l.width, f = l.height;
1275
+ n = Math.min(n, u - h2 / 2), t = Math.max(t, u + h2 / 2), r = Math.min(r, c - f / 2), o = Math.max(o, c + f / 2);
1276
1276
  }
1277
1277
  e.nodes().forEach((l) => d(e.node(l))), e.edges().forEach((l) => {
1278
1278
  let u = e.edge(l);
@@ -1336,7 +1336,7 @@ function or(e) {
1336
1336
  t.forEach((o, i) => {
1337
1337
  let s = e.node(o);
1338
1338
  s.order = i + r, (s.selfEdges || []).forEach((a) => {
1339
- w(e, "selfedge", { width: a.label.width, height: a.label.height, rank: s.rank, order: i + ++r, e: a.e, label: a.label }, "_se");
1339
+ w2(e, "selfedge", { width: a.label.width, height: a.label.height, rank: s.rank, order: i + ++r, e: a.e, label: a.label }, "_se");
1340
1340
  }), delete s.selfEdges;
1341
1341
  });
1342
1342
  });
@@ -1870,6 +1870,8 @@ function categoryAccent(category) {
1870
1870
  return "#a855f7";
1871
1871
  case "layout":
1872
1872
  return "#64748b";
1873
+ case "annotation":
1874
+ return "#eab308";
1873
1875
  default:
1874
1876
  return "#71717a";
1875
1877
  }
@@ -3319,11 +3321,11 @@ function hex(value) {
3319
3321
  value = clampi(value);
3320
3322
  return (value < 16 ? "0" : "") + value.toString(16);
3321
3323
  }
3322
- function hsla(h, s, l, a) {
3323
- if (a <= 0) h = s = l = NaN;
3324
- else if (l <= 0 || l >= 1) h = s = NaN;
3325
- else if (s <= 0) h = NaN;
3326
- return new Hsl(h, s, l, a);
3324
+ function hsla(h2, s, l, a) {
3325
+ if (a <= 0) h2 = s = l = NaN;
3326
+ else if (l <= 0 || l >= 1) h2 = s = NaN;
3327
+ else if (s <= 0) h2 = NaN;
3328
+ return new Hsl(h2, s, l, a);
3327
3329
  }
3328
3330
  function hslConvert(o) {
3329
3331
  if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
@@ -3331,23 +3333,23 @@ function hslConvert(o) {
3331
3333
  if (!o) return new Hsl();
3332
3334
  if (o instanceof Hsl) return o;
3333
3335
  o = o.rgb();
3334
- var r = o.r / 255, g = o.g / 255, b = o.b / 255, min = Math.min(r, g, b), max = Math.max(r, g, b), h = NaN, s = max - min, l = (max + min) / 2;
3336
+ var r = o.r / 255, g = o.g / 255, b = o.b / 255, min = Math.min(r, g, b), max = Math.max(r, g, b), h2 = NaN, s = max - min, l = (max + min) / 2;
3335
3337
  if (s) {
3336
- if (r === max) h = (g - b) / s + (g < b) * 6;
3337
- else if (g === max) h = (b - r) / s + 2;
3338
- else h = (r - g) / s + 4;
3338
+ if (r === max) h2 = (g - b) / s + (g < b) * 6;
3339
+ else if (g === max) h2 = (b - r) / s + 2;
3340
+ else h2 = (r - g) / s + 4;
3339
3341
  s /= l < 0.5 ? max + min : 2 - max - min;
3340
- h *= 60;
3342
+ h2 *= 60;
3341
3343
  } else {
3342
- s = l > 0 && l < 1 ? 0 : h;
3344
+ s = l > 0 && l < 1 ? 0 : h2;
3343
3345
  }
3344
- return new Hsl(h, s, l, o.opacity);
3346
+ return new Hsl(h2, s, l, o.opacity);
3345
3347
  }
3346
- function hsl(h, s, l, opacity) {
3347
- return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
3348
+ function hsl(h2, s, l, opacity) {
3349
+ return arguments.length === 1 ? hslConvert(h2) : new Hsl(h2, s, l, opacity == null ? 1 : opacity);
3348
3350
  }
3349
- function Hsl(h, s, l, opacity) {
3350
- this.h = +h;
3351
+ function Hsl(h2, s, l, opacity) {
3352
+ this.h = +h2;
3351
3353
  this.s = +s;
3352
3354
  this.l = +l;
3353
3355
  this.opacity = +opacity;
@@ -3362,11 +3364,11 @@ define_default(Hsl, hsl, extend(Color, {
3362
3364
  return new Hsl(this.h, this.s, this.l * k2, this.opacity);
3363
3365
  },
3364
3366
  rgb() {
3365
- var h = this.h % 360 + (this.h < 0) * 360, s = isNaN(h) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < 0.5 ? l : 1 - l) * s, m1 = 2 * l - m2;
3367
+ var h2 = this.h % 360 + (this.h < 0) * 360, s = isNaN(h2) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < 0.5 ? l : 1 - l) * s, m1 = 2 * l - m2;
3366
3368
  return new Rgb(
3367
- hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
3368
- hsl2rgb(h, m1, m2),
3369
- hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
3369
+ hsl2rgb(h2 >= 240 ? h2 - 240 : h2 + 120, m1, m2),
3370
+ hsl2rgb(h2, m1, m2),
3371
+ hsl2rgb(h2 < 120 ? h2 + 240 : h2 - 120, m1, m2),
3370
3372
  this.opacity
3371
3373
  );
3372
3374
  },
@@ -3388,8 +3390,8 @@ function clamph(value) {
3388
3390
  function clampt(value) {
3389
3391
  return Math.max(0, Math.min(1, value || 0));
3390
3392
  }
3391
- function hsl2rgb(h, m1, m2) {
3392
- return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
3393
+ function hsl2rgb(h2, m1, m2) {
3394
+ return (h2 < 60 ? m1 + (m2 - m1) * h2 / 60 : h2 < 180 ? m2 : h2 < 240 ? m1 + (m2 - m1) * (240 - h2) / 60 : m1) * 255;
3393
3395
  }
3394
3396
 
3395
3397
  // node_modules/d3-interpolate/src/constant.js
@@ -4651,11 +4653,11 @@ function zoom_default2() {
4651
4653
  }).on("interrupt.zoom end.zoom", function() {
4652
4654
  gesture(this, arguments).event(event).end();
4653
4655
  }).tween("zoom", function() {
4654
- var that = this, args = arguments, g = gesture(that, args).event(event), e = extent.apply(that, args), p2 = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, w2 = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = that.__zoom, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i = interpolate(a.invert(p2).concat(w2 / a.k), b.invert(p2).concat(w2 / b.k));
4656
+ var that = this, args = arguments, g = gesture(that, args).event(event), e = extent.apply(that, args), p2 = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, w3 = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = that.__zoom, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i = interpolate(a.invert(p2).concat(w3 / a.k), b.invert(p2).concat(w3 / b.k));
4655
4657
  return function(t) {
4656
4658
  if (t === 1) t = b;
4657
4659
  else {
4658
- var l = i(t), k2 = w2 / l[2];
4660
+ var l = i(t), k2 = w3 / l[2];
4659
4661
  t = new Transform(k2, p2[0] - l[0] * k2, p2[1] - l[1] * k2);
4660
4662
  }
4661
4663
  g.zoom(null, t);
@@ -6558,7 +6560,7 @@ function getHandle(nodeId, handleType, handleId, nodeLookup, connectionMode, wit
6558
6560
  return null;
6559
6561
  }
6560
6562
  const handles = connectionMode === "strict" ? node.internals.handleBounds?.[handleType] : [...node.internals.handleBounds?.source ?? [], ...node.internals.handleBounds?.target ?? []];
6561
- const handle = (handleId ? handles?.find((h) => h.id === handleId) : handles?.[0]) ?? null;
6563
+ const handle = (handleId ? handles?.find((h2) => h2.id === handleId) : handles?.[0]) ?? null;
6562
6564
  return handle && withAbsolutePosition ? { ...handle, ...getHandlePosition(node, handle, handle.position, true) } : handle;
6563
6565
  }
6564
6566
  function getHandleType(edgeUpdaterType, handleDomNode) {
@@ -10455,6 +10457,14 @@ function ReactFlow({ nodes, edges, defaultNodes, defaultEdges, className, nodeTy
10455
10457
  return jsxRuntime.jsx("div", { "data-testid": "rf__wrapper", ...rest, onScroll: wrapperOnScroll, style: { ...style2, ...wrapperStyle }, ref, className: cc(["react-flow", className, colorModeClassName]), id: id2, role: "application", children: jsxRuntime.jsxs(Wrapper, { nodes, edges, width, height, fitView, fitViewOptions, minZoom, maxZoom, nodeOrigin, nodeExtent, zIndexMode, children: [jsxRuntime.jsx(StoreUpdater, { nodes, edges, defaultNodes, defaultEdges, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, nodesDraggable, autoPanOnNodeFocus, nodesConnectable, nodesFocusable, edgesFocusable, edgesReconnectable, elementsSelectable, elevateNodesOnSelect, elevateEdgesOnSelect, minZoom, maxZoom, nodeExtent, onNodesChange, onEdgesChange, snapToGrid, snapGrid, connectionMode, translateExtent, connectOnClick, defaultEdgeOptions, fitView, fitViewOptions, onNodesDelete, onEdgesDelete, onDelete, onNodeDragStart, onNodeDrag, onNodeDragStop, onSelectionDrag, onSelectionDragStart, onSelectionDragStop, onMove, onMoveStart, onMoveEnd, noPanClassName, nodeOrigin, rfId, autoPanOnConnect, autoPanOnNodeDrag, autoPanSpeed, onError, connectionRadius, isValidConnection, selectNodesOnDrag, nodeDragThreshold, connectionDragThreshold, onBeforeDelete, debug, ariaLabelConfig, zIndexMode }), jsxRuntime.jsx(GraphView, { onInit, onNodeClick, onEdgeClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, nodeTypes, edgeTypes, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, deleteKeyCode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, onlyRenderVisibleElements, defaultViewport: defaultViewport$1, translateExtent, minZoom, maxZoom, preventScrolling, zoomOnScroll, zoomOnPinch, zoomOnDoubleClick, panOnScroll, panOnScrollSpeed, panOnScrollMode, panOnDrag, autoPanOnSelection, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, paneClickDistance, nodeClickDistance, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onReconnect, onReconnectStart, onReconnectEnd, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, defaultMarkerColor, noDragClassName, noWheelClassName, noPanClassName, rfId, disableKeyboardA11y, nodeExtent, viewport, onViewportChange }), jsxRuntime.jsx(SelectionListener, { onSelectionChange }), children2, jsxRuntime.jsx(Attribution, { proOptions, position: attributionPosition }), jsxRuntime.jsx(A11yDescriptions, { rfId, disableKeyboardA11y })] }) });
10456
10458
  }
10457
10459
  var index = fixedForwardRef(ReactFlow);
10460
+ var selector$5 = (s) => s.domNode?.querySelector(".react-flow__viewport-portal");
10461
+ function ViewportPortal({ children: children2 }) {
10462
+ const viewPortalDiv = useStore(selector$5);
10463
+ if (!viewPortalDiv) {
10464
+ return null;
10465
+ }
10466
+ return reactDom.createPortal(children2, viewPortalDiv);
10467
+ }
10458
10468
  function LinePattern({ dimensions, lineWidth, variant, className }) {
10459
10469
  return jsxRuntime.jsx("path", { strokeWidth: lineWidth, d: `M${dimensions[0] / 2} 0 V${dimensions[1]} M0 ${dimensions[1] / 2} H${dimensions[0]}`, className: cc(["react-flow__background-pattern", variant, className]) });
10460
10470
  }
@@ -10968,6 +10978,88 @@ function LaneNodeInner(props) {
10968
10978
  );
10969
10979
  }
10970
10980
  var LaneNode = ReactExports.memo(LaneNodeInner);
10981
+ var FlowEditorContext = ReactExports.createContext(null);
10982
+ var FlowEditorProvider = FlowEditorContext.Provider;
10983
+ function useFlowEditor() {
10984
+ const api = ReactExports.useContext(FlowEditorContext);
10985
+ if (api === null) {
10986
+ throw new Error("useFlowEditor() must be called inside <FlowEditor>.");
10987
+ }
10988
+ return api;
10989
+ }
10990
+ function useFlowEditorOptional() {
10991
+ return ReactExports.useContext(FlowEditorContext);
10992
+ }
10993
+ var NOTE_COLORS = {
10994
+ amber: { bg: "rgba(234, 179, 8, 0.14)", border: "rgba(234, 179, 8, 0.55)", title: "#a16207" },
10995
+ sky: { bg: "rgba(14, 165, 233, 0.12)", border: "rgba(14, 165, 233, 0.5)", title: "#0369a1" },
10996
+ violet: { bg: "rgba(139, 92, 246, 0.13)", border: "rgba(139, 92, 246, 0.5)", title: "#6d28d9" },
10997
+ emerald: { bg: "rgba(16, 185, 129, 0.13)", border: "rgba(16, 185, 129, 0.5)", title: "#047857" },
10998
+ rose: { bg: "rgba(244, 63, 94, 0.12)", border: "rgba(244, 63, 94, 0.5)", title: "#be123c" },
10999
+ slate: { bg: "rgba(100, 116, 139, 0.12)", border: "rgba(100, 116, 139, 0.5)", title: "#475569" }
11000
+ };
11001
+ function coerceColor(v2) {
11002
+ return typeof v2 === "string" && v2 in NOTE_COLORS ? v2 : "amber";
11003
+ }
11004
+ function NoteNodeInner(props) {
11005
+ const data = props.data;
11006
+ const config = data.config ?? {};
11007
+ const api = useFlowEditorOptional();
11008
+ const hasConfigText = typeof config.text === "string" && config.text.length > 0;
11009
+ const text = hasConfigText ? String(config.text) : typeof data.body === "string" ? data.body : typeof data.text === "string" ? data.text : "";
11010
+ const title = typeof config.title === "string" && config.title || (!hasConfigText && typeof data.body === "string" && typeof data.label === "string" ? data.label : "");
11011
+ const skin = NOTE_COLORS[coerceColor(config.color)];
11012
+ const [editing, setEditing] = ReactExports.useState(false);
11013
+ const [draft, setDraft] = ReactExports.useState(text);
11014
+ const areaRef = ReactExports.useRef(null);
11015
+ ReactExports.useEffect(() => {
11016
+ if (editing && areaRef.current) {
11017
+ const el = areaRef.current;
11018
+ el.focus();
11019
+ el.setSelectionRange(el.value.length, el.value.length);
11020
+ }
11021
+ }, [editing]);
11022
+ const commit = () => {
11023
+ setEditing(false);
11024
+ if (!api || draft === text) return;
11025
+ const current = api.nodes.find((n) => n.id === props.id);
11026
+ if (!current) return;
11027
+ api.updateNode({
11028
+ ...current,
11029
+ data: { ...current.data, config: { ...config, text: draft } }
11030
+ });
11031
+ };
11032
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11033
+ "div",
11034
+ {
11035
+ className: ["ff-note", props.selected ? "ff-note--selected" : ""].filter(Boolean).join(" "),
11036
+ style: { background: skin.bg, borderColor: skin.border },
11037
+ onDoubleClick: api ? () => {
11038
+ setDraft(text);
11039
+ setEditing(true);
11040
+ } : void 0,
11041
+ children: [
11042
+ /* @__PURE__ */ jsxRuntime.jsx(NodeResizer, { isVisible: props.selected ?? false, color: skin.border, minWidth: 140, minHeight: 80 }),
11043
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-note__title", style: { color: skin.title }, children: title }),
11044
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11045
+ "textarea",
11046
+ {
11047
+ ref: areaRef,
11048
+ className: "ff-note__input nodrag nowheel",
11049
+ value: draft,
11050
+ onChange: (e) => setDraft(e.target.value),
11051
+ onBlur: commit,
11052
+ onKeyDown: (e) => {
11053
+ if (e.key === "Escape") setEditing(false);
11054
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) commit();
11055
+ }
11056
+ }
11057
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-note__body", children: text || /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-note__placeholder", children: api ? "Double-click to write a note\u2026" : "Note" }) })
11058
+ ]
11059
+ }
11060
+ );
11061
+ }
11062
+ var NoteNode = ReactExports.memo(NoteNodeInner);
10971
11063
 
10972
11064
  // src/registry/capabilities.ts
10973
11065
  var llmClient = null;
@@ -11083,12 +11175,14 @@ async function runFlow(graph, executors, onEvent = () => {
11083
11175
  }
11084
11176
  }
11085
11177
  const visualKind = getNodeKind(node.type ?? "");
11086
- if (node.type === "note" || visualKind?.category === "layout") {
11178
+ const isLayout = visualKind?.category === "layout";
11179
+ const isAnnotation = node.type === "note" || visualKind?.category === "annotation";
11180
+ if (isLayout || isAnnotation) {
11087
11181
  onEvent({
11088
11182
  type: "node-status",
11089
11183
  nodeId: node.id,
11090
11184
  status: "idle",
11091
- text: visualKind?.category === "layout" ? "lane" : "annotation"
11185
+ text: isLayout ? "lane" : "annotation"
11092
11186
  });
11093
11187
  continue;
11094
11188
  }
@@ -12045,6 +12139,35 @@ var KINDS = [
12045
12139
  defaultConfig: { title: "Lane", orientation: "horizontal" },
12046
12140
  resizable: { minWidth: 160, minHeight: 72 },
12047
12141
  component: LaneNode
12142
+ },
12143
+ {
12144
+ // Note — a sticky-note annotation. Portless + visual-only: the runtime skips
12145
+ // the `annotation` category, so a note's text NEVER reaches a runner — it
12146
+ // rides in the document purely for people, editors, and MCP tools. Uses its
12147
+ // own renderer (NoteNode); double-click on the canvas to edit in place.
12148
+ name: "@particle-academy/note",
12149
+ aliases: ["note", "@fancy/note"],
12150
+ category: "annotation",
12151
+ label: "Note",
12152
+ description: "A sticky note that documents the canvas. Never runs \u2014 editor + agent only.",
12153
+ icon: "\u{1F5D2}",
12154
+ inputs: [],
12155
+ outputs: [],
12156
+ configSchema: [
12157
+ { type: "text", key: "title", label: "Title", placeholder: "Optional heading" },
12158
+ { type: "textarea", key: "text", label: "Note", rows: 5, placeholder: "What does this part of the flow do?" },
12159
+ { type: "select", key: "color", label: "Color", default: "amber", options: [
12160
+ { value: "amber", label: "Amber" },
12161
+ { value: "sky", label: "Sky" },
12162
+ { value: "violet", label: "Violet" },
12163
+ { value: "emerald", label: "Emerald" },
12164
+ { value: "rose", label: "Rose" },
12165
+ { value: "slate", label: "Slate" }
12166
+ ] }
12167
+ ],
12168
+ defaultConfig: { text: "", color: "amber" },
12169
+ resizable: { minWidth: 140, minHeight: 80 },
12170
+ component: NoteNode
12048
12171
  }
12049
12172
  ];
12050
12173
  function registerBuiltinKinds() {
@@ -12143,14 +12266,6 @@ function OutputNodeInner(props) {
12143
12266
  return /* @__PURE__ */ jsxRuntime.jsx(NodeShell, { node: props, accent: "#a855f7", tag: "OUTPUT", icon: "\u25CF", showOutputs: false });
12144
12267
  }
12145
12268
  var OutputNode2 = ReactExports.memo(OutputNodeInner);
12146
- function NoteNodeInner({ data, selected: selected2 }) {
12147
- const noteData = data;
12148
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `ff-note ${selected2 ? "ff-note--selected" : ""}`, children: [
12149
- noteData.label && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-note__title", children: noteData.label }),
12150
- noteData.body && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ff-note__body", children: noteData.body })
12151
- ] });
12152
- }
12153
- var NoteNode = ReactExports.memo(NoteNodeInner);
12154
12269
  function SubgraphNodeInner(props) {
12155
12270
  const data = props.data;
12156
12271
  const childCount = data.childIds?.length ?? 0;
@@ -12342,6 +12457,97 @@ function distributeNodes(nodes, axis) {
12342
12457
  return { ...n, position: axis === "h" ? { ...n.position, x: p2 } : { ...n.position, y: p2 } };
12343
12458
  });
12344
12459
  }
12460
+
12461
+ // src/components/canvas/helper-lines.ts
12462
+ var w = (n) => n.width ?? n.measured?.width ?? 0;
12463
+ var h = (n) => n.height ?? n.measured?.height ?? 0;
12464
+ function getHelperLines(change, nodes, distance2 = 6) {
12465
+ const result = { snapPosition: { x: void 0, y: void 0 } };
12466
+ const a = nodes.find((n) => n.id === change.id);
12467
+ if (!a || !change.position) return result;
12468
+ const A2 = {
12469
+ left: change.position.x,
12470
+ right: change.position.x + w(a),
12471
+ top: change.position.y,
12472
+ bottom: change.position.y + h(a),
12473
+ width: w(a),
12474
+ height: h(a)
12475
+ };
12476
+ let vDist = distance2;
12477
+ let hDist = distance2;
12478
+ for (const b of nodes) {
12479
+ if (b.id === a.id) continue;
12480
+ const B2 = { left: b.position.x, right: b.position.x + w(b), top: b.position.y, bottom: b.position.y + h(b) };
12481
+ const ll = Math.abs(A2.left - B2.left);
12482
+ if (ll < vDist) {
12483
+ result.snapPosition.x = B2.left;
12484
+ result.vertical = B2.left;
12485
+ vDist = ll;
12486
+ }
12487
+ const rr2 = Math.abs(A2.right - B2.right);
12488
+ if (rr2 < vDist) {
12489
+ result.snapPosition.x = B2.right - A2.width;
12490
+ result.vertical = B2.right;
12491
+ vDist = rr2;
12492
+ }
12493
+ const lr = Math.abs(A2.left - B2.right);
12494
+ if (lr < vDist) {
12495
+ result.snapPosition.x = B2.right;
12496
+ result.vertical = B2.right;
12497
+ vDist = lr;
12498
+ }
12499
+ const rl = Math.abs(A2.right - B2.left);
12500
+ if (rl < vDist) {
12501
+ result.snapPosition.x = B2.left - A2.width;
12502
+ result.vertical = B2.left;
12503
+ vDist = rl;
12504
+ }
12505
+ const tt2 = Math.abs(A2.top - B2.top);
12506
+ if (tt2 < hDist) {
12507
+ result.snapPosition.y = B2.top;
12508
+ result.horizontal = B2.top;
12509
+ hDist = tt2;
12510
+ }
12511
+ const bb = Math.abs(A2.bottom - B2.bottom);
12512
+ if (bb < hDist) {
12513
+ result.snapPosition.y = B2.bottom - A2.height;
12514
+ result.horizontal = B2.bottom;
12515
+ hDist = bb;
12516
+ }
12517
+ const tb = Math.abs(A2.top - B2.bottom);
12518
+ if (tb < hDist) {
12519
+ result.snapPosition.y = B2.bottom;
12520
+ result.horizontal = B2.bottom;
12521
+ hDist = tb;
12522
+ }
12523
+ const bt2 = Math.abs(A2.bottom - B2.top);
12524
+ if (bt2 < hDist) {
12525
+ result.snapPosition.y = B2.top - A2.height;
12526
+ result.horizontal = B2.top;
12527
+ hDist = bt2;
12528
+ }
12529
+ }
12530
+ return result;
12531
+ }
12532
+ function HelperLines({ horizontal, vertical }) {
12533
+ if (horizontal === void 0 && vertical === void 0) return null;
12534
+ return /* @__PURE__ */ jsxRuntime.jsxs(ViewportPortal, { children: [
12535
+ vertical !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
12536
+ "div",
12537
+ {
12538
+ className: "ff-helper-line",
12539
+ style: { position: "absolute", transform: `translateX(${vertical}px)`, top: -5e3, height: 1e4, width: 1, pointerEvents: "none" }
12540
+ }
12541
+ ),
12542
+ horizontal !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
12543
+ "div",
12544
+ {
12545
+ className: "ff-helper-line",
12546
+ style: { position: "absolute", transform: `translateY(${horizontal}px)`, left: -5e3, width: 1e4, height: 1, pointerEvents: "none" }
12547
+ }
12548
+ )
12549
+ ] });
12550
+ }
12345
12551
  var DEFAULT_FIT_VIEW = { padding: 0.2 };
12346
12552
  var DEFAULT_EDGE_OPTIONS = {
12347
12553
  type: "smoothstep",
@@ -12356,6 +12562,9 @@ function FlowCanvas({
12356
12562
  height = 600,
12357
12563
  validateConnections = true,
12358
12564
  isValidConnection,
12565
+ colorMode,
12566
+ showHelperLines = false,
12567
+ onNodesChange,
12359
12568
  toolbar,
12360
12569
  nodeTypes,
12361
12570
  edgeTypes,
@@ -12382,33 +12591,68 @@ function FlowCanvas({
12382
12591
  [edgeTypes]
12383
12592
  );
12384
12593
  const orderedNodes = ReactExports.useMemo(() => sortNodesParentFirst(nodes), [nodes]);
12385
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ["ff-canvas", className ?? ""].filter(Boolean).join(" "), style: { height, ...style2 }, children: [
12386
- toolbar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-canvas__toolbar", children: toolbar }),
12387
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-canvas__surface", children: /* @__PURE__ */ jsxRuntime.jsxs(
12388
- index,
12389
- {
12390
- nodes: orderedNodes,
12391
- edges,
12392
- nodeTypes: mergedNodeTypes,
12393
- edgeTypes: mergedEdgeTypes,
12394
- fitView: true,
12395
- fitViewOptions: DEFAULT_FIT_VIEW,
12396
- defaultEdgeOptions: DEFAULT_EDGE_OPTIONS,
12397
- proOptions: { hideAttribution: true },
12398
- zoomActivationKeyCode: "Shift",
12399
- preventScrolling: false,
12400
- isValidConnection: resolvedIsValidConnection,
12401
- ...rest,
12402
- children: [
12403
- background !== "none" && /* @__PURE__ */ jsxRuntime.jsx(Background, { variant: background, gap: 20, size: 1, color: "rgba(0,0,0,0.18)" }),
12404
- showControls && /* @__PURE__ */ jsxRuntime.jsx(Controls, { className: "ff-controls", position: "bottom-right" }),
12405
- showMinimap && /* @__PURE__ */ jsxRuntime.jsx(MiniMap, { className: "ff-minimap", pannable: true, zoomable: true })
12406
- ]
12594
+ const [helperLines, setHelperLines] = ReactExports.useState({});
12595
+ const handleNodesChange = ReactExports.useCallback(
12596
+ (changes) => {
12597
+ if (showHelperLines) {
12598
+ const pos = changes.filter((c) => c.type === "position" && c.position);
12599
+ if (pos.length === 1 && pos[0].dragging) {
12600
+ const lines = getHelperLines(pos[0], nodesRef.current);
12601
+ if (lines.snapPosition.x !== void 0) pos[0].position.x = lines.snapPosition.x;
12602
+ if (lines.snapPosition.y !== void 0) pos[0].position.y = lines.snapPosition.y;
12603
+ setHelperLines({ horizontal: lines.horizontal, vertical: lines.vertical });
12604
+ } else {
12605
+ setHelperLines({});
12606
+ }
12407
12607
  }
12408
- ) })
12409
- ] });
12608
+ onNodesChange?.(changes);
12609
+ },
12610
+ [showHelperLines, onNodesChange]
12611
+ );
12612
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12613
+ "div",
12614
+ {
12615
+ className: [
12616
+ "ff-canvas",
12617
+ // colorMode drives BOTH react-flow's chrome (below) and our `ff-` styles
12618
+ // via the shared `.dark` class / light opt-out — one theme signal.
12619
+ colorMode === "dark" ? "dark" : "",
12620
+ colorMode === "light" ? "ff-canvas--light" : "",
12621
+ className ?? ""
12622
+ ].filter(Boolean).join(" "),
12623
+ style: { height, ...style2 },
12624
+ children: [
12625
+ toolbar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-canvas__toolbar", children: toolbar }),
12626
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-canvas__surface", children: /* @__PURE__ */ jsxRuntime.jsxs(
12627
+ index,
12628
+ {
12629
+ nodes: orderedNodes,
12630
+ edges,
12631
+ onNodesChange: handleNodesChange,
12632
+ colorMode,
12633
+ nodeTypes: mergedNodeTypes,
12634
+ edgeTypes: mergedEdgeTypes,
12635
+ fitView: true,
12636
+ fitViewOptions: DEFAULT_FIT_VIEW,
12637
+ defaultEdgeOptions: DEFAULT_EDGE_OPTIONS,
12638
+ proOptions: { hideAttribution: true },
12639
+ zoomActivationKeyCode: "Shift",
12640
+ preventScrolling: false,
12641
+ isValidConnection: resolvedIsValidConnection,
12642
+ ...rest,
12643
+ children: [
12644
+ background !== "none" && /* @__PURE__ */ jsxRuntime.jsx(Background, { variant: background, gap: 20, size: 1, color: "rgba(0,0,0,0.18)" }),
12645
+ showControls && /* @__PURE__ */ jsxRuntime.jsx(Controls, { className: "ff-controls", position: "bottom-right" }),
12646
+ showMinimap && /* @__PURE__ */ jsxRuntime.jsx(MiniMap, { className: "ff-minimap", pannable: true, zoomable: true }),
12647
+ showHelperLines && /* @__PURE__ */ jsxRuntime.jsx(HelperLines, { horizontal: helperLines.horizontal, vertical: helperLines.vertical })
12648
+ ]
12649
+ }
12650
+ ) })
12651
+ ]
12652
+ }
12653
+ );
12410
12654
  }
12411
- var CATEGORY_ORDER = ["trigger", "logic", "data", "ai", "io", "human", "output", "layout", "custom"];
12655
+ var CATEGORY_ORDER = ["trigger", "logic", "data", "ai", "io", "human", "output", "layout", "annotation", "custom"];
12412
12656
  var CATEGORY_LABELS = {
12413
12657
  trigger: "Triggers",
12414
12658
  logic: "Logic",
@@ -12418,6 +12662,7 @@ var CATEGORY_LABELS = {
12418
12662
  human: "Human",
12419
12663
  output: "Output",
12420
12664
  layout: "Layout",
12665
+ annotation: "Notes",
12421
12666
  custom: "Custom"
12422
12667
  };
12423
12668
  function NodePalette({ categories, onPick, className, style: style2 }) {
@@ -13136,6 +13381,7 @@ function useFlowHistory(flow) {
13136
13381
  function useFlowRun({ maxFeed = 200 } = {}) {
13137
13382
  const [statuses, setStatuses] = ReactExports.useState({});
13138
13383
  const [statusText, setStatusText] = ReactExports.useState({});
13384
+ const [outputs, setOutputs] = ReactExports.useState({});
13139
13385
  const [feed, setFeed] = ReactExports.useState([]);
13140
13386
  const [running, setRunning] = ReactExports.useState(false);
13141
13387
  const [lastResult, setLastResult] = ReactExports.useState(null);
@@ -13149,6 +13395,7 @@ function useFlowRun({ maxFeed = 200 } = {}) {
13149
13395
  appendFeed({ level: "status", text: `${e.nodeId} \u2192 ${e.status}${e.text ? ` (${e.text})` : ""}`, nodeId: e.nodeId });
13150
13396
  break;
13151
13397
  case "node-output":
13398
+ setOutputs((o) => ({ ...o, [e.nodeId]: e.value }));
13152
13399
  appendFeed({ level: "info", text: `${e.nodeId}.${e.portId} = ${preview(e.value)}`, nodeId: e.nodeId, detail: e.value });
13153
13400
  break;
13154
13401
  case "log":
@@ -13185,6 +13432,7 @@ function useFlowRun({ maxFeed = 200 } = {}) {
13185
13432
  for (const n of graph.nodes) idleStatuses[n.id] = "idle";
13186
13433
  setStatuses(idleStatuses);
13187
13434
  setStatusText({});
13435
+ setOutputs({});
13188
13436
  setRunning(true);
13189
13437
  try {
13190
13438
  const result = await runFlow(graph, executors, handleEvent, { ...options, signal: controller.signal });
@@ -13201,10 +13449,18 @@ function useFlowRun({ maxFeed = 200 } = {}) {
13201
13449
  const reset = ReactExports.useCallback(() => {
13202
13450
  setStatuses({});
13203
13451
  setStatusText({});
13452
+ setOutputs({});
13204
13453
  setFeed([]);
13205
13454
  setLastResult(null);
13206
13455
  }, []);
13207
- return { statuses, statusText, feed, running, lastResult, run, cancel, reset };
13456
+ return { statuses, statusText, outputs, feed, running, lastResult, run, cancel, reset };
13457
+ }
13458
+ function applyOutputsToNodes(nodes, outputs) {
13459
+ return nodes.map((n) => {
13460
+ const kind = getNodeKind(n.data?.kind ?? n.type ?? "");
13461
+ if (!kind?.reactive || !(n.id in outputs)) return n;
13462
+ return { ...n, data: { ...n.data, output: outputs[n.id] } };
13463
+ });
13208
13464
  }
13209
13465
  function applyStatusesToNodes(nodes, statuses, statusText) {
13210
13466
  return nodes.map((n) => ({
@@ -13446,6 +13702,10 @@ function RegistryNodeInner(props) {
13446
13702
  data.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ff-node__desc", children: data.description }),
13447
13703
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-node__body", children: kind.renderBody ? kind.renderBody({ nodeId: props.id, config, selected: props.selected ?? false }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultBody, { config, kind: kind.configSchema }) }),
13448
13704
  data.statusText && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ff-node__status-text", children: data.statusText }),
13705
+ data.output !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "ff-node__output", title: "Latest output", children: [
13706
+ "\u2192 ",
13707
+ previewValue(data.output)
13708
+ ] }),
13449
13709
  inputs.map((p2, i) => /* @__PURE__ */ jsxRuntime.jsx(
13450
13710
  Handle,
13451
13711
  {
@@ -13542,18 +13802,6 @@ function buildNodeTypes() {
13542
13802
  }
13543
13803
  return map;
13544
13804
  }
13545
- var FlowEditorContext = ReactExports.createContext(null);
13546
- var FlowEditorProvider = FlowEditorContext.Provider;
13547
- function useFlowEditor() {
13548
- const api = ReactExports.useContext(FlowEditorContext);
13549
- if (api === null) {
13550
- throw new Error("useFlowEditor() must be called inside <FlowEditor>.");
13551
- }
13552
- return api;
13553
- }
13554
- function useFlowEditorOptional() {
13555
- return ReactExports.useContext(FlowEditorContext);
13556
- }
13557
13805
  var FlowEditor = ReactExports.forwardRef(function FlowEditor2(props, ref) {
13558
13806
  return /* @__PURE__ */ jsxRuntime.jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
13559
13807
  "div",
@@ -13595,8 +13843,11 @@ function FlowEditorInner({
13595
13843
  ReactExports.useEffect(() => onNodeKindsChanged(() => force((n) => n + 1)), []);
13596
13844
  const nodeTypes = ReactExports.useMemo(() => buildNodeTypes(), [listNodeKinds().length]);
13597
13845
  const renderedNodes = ReactExports.useMemo(
13598
- () => applyStatusesToNodes(flow.nodes, runner.statuses, runner.statusText),
13599
- [flow.nodes, runner.statuses, runner.statusText]
13846
+ () => applyOutputsToNodes(
13847
+ applyStatusesToNodes(flow.nodes, runner.statuses, runner.statusText),
13848
+ runner.outputs
13849
+ ),
13850
+ [flow.nodes, runner.statuses, runner.statusText, runner.outputs]
13600
13851
  );
13601
13852
  const [selectedId, setSelectedId] = ReactExports.useState(null);
13602
13853
  const selected2 = ReactExports.useMemo(() => flow.nodes.find((n) => n.id === selectedId) ?? null, [flow.nodes, selectedId]);
@@ -13780,10 +14031,10 @@ function FlowEditorInner({
13780
14031
  (orientation = "horizontal", title) => {
13781
14032
  const vertical = orientation === "vertical";
13782
14033
  const lanes = flow.nodes.filter(isLaneNode);
13783
- const w2 = vertical ? 280 : 680;
13784
- const h = vertical ? 480 : 168;
14034
+ const w3 = vertical ? 280 : 680;
14035
+ const h2 = vertical ? 480 : 168;
13785
14036
  const end = lanes.reduce(
13786
- (m, l) => Math.max(m, vertical ? l.position.x + (l.width ?? w2) : l.position.y + (l.height ?? h)),
14037
+ (m, l) => Math.max(m, vertical ? l.position.x + (l.width ?? w3) : l.position.y + (l.height ?? h2)),
13787
14038
  0
13788
14039
  );
13789
14040
  const id2 = newNodeId();
@@ -13792,8 +14043,8 @@ function FlowEditorInner({
13792
14043
  id: id2,
13793
14044
  type: "@particle-academy/lane",
13794
14045
  position: vertical ? { x: lanes.length ? end + 12 : 0, y: 0 } : { x: 0, y: lanes.length ? end + 12 : 0 },
13795
- width: w2,
13796
- height: h,
14046
+ width: w3,
14047
+ height: h2,
13797
14048
  data: { kind: "@particle-academy/lane", label: name, config: { title: name, orientation } }
13798
14049
  };
13799
14050
  flow.setNodes((all) => [...all, node]);
@@ -14269,6 +14520,7 @@ exports.TriggerNode = TriggerNode;
14269
14520
  exports.WORKFLOW_SCHEMA_URL = WORKFLOW_SCHEMA_URL;
14270
14521
  exports.WORKFLOW_SCHEMA_VERSION = WORKFLOW_SCHEMA_VERSION;
14271
14522
  exports.alignNodes = alignNodes;
14523
+ exports.applyOutputsToNodes = applyOutputsToNodes;
14272
14524
  exports.applyStatusesToNodes = applyStatusesToNodes;
14273
14525
  exports.buildNodeTypes = buildNodeTypes;
14274
14526
  exports.categoryAccent = categoryAccent;