@floegence/floe-webapp-core 0.86.21 → 0.86.23

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.
@@ -23,7 +23,7 @@ export interface GraphCanvasProps {
23
23
  /** Overlay content should use shared SurfaceFloatingLayer for point placement. */
24
24
  overlay?: JSX.Element;
25
25
  /** Optional interactive overview. Its geometry follows the same visible layout. */
26
- minimap?: Pick<GraphMinimapProps, 'ariaLabel' | 'nodeStyle'>;
26
+ minimap?: Pick<GraphMinimapProps, 'ariaLabel' | 'nodeStyle' | 'edges'>;
27
27
  class?: string;
28
28
  }
29
29
  /** Controlled graph surface. Hosts own documents and selection; Floe owns geometry and input. */
@@ -1,29 +1,29 @@
1
- import { insert as S, createComponent as w, setAttribute as c, effect as z, setStyleProperty as L, className as U, template as B, memo as it, use as ot, delegateEvents as lt } from "solid-js/web";
2
- import { createUniqueId as dt, createSignal as J, createMemo as x, onMount as ct, For as Y, Show as _, onCleanup as ut } from "solid-js";
3
- import { InfiniteCanvas as st } from "../ui/InfiniteCanvas.js";
1
+ import { insert as S, createComponent as w, setAttribute as c, effect as z, setStyleProperty as L, className as J, template as B, memo as it, use as lt, delegateEvents as dt } from "solid-js/web";
2
+ import { createUniqueId as ct, createSignal as Q, createMemo as v, onMount as ut, For as _, Show as N, onCleanup as st } from "solid-js";
3
+ import { InfiniteCanvas as gt } from "../ui/InfiniteCanvas.js";
4
4
  import { resolveSurfaceInteractionTargetRole as ht } from "../ui/localInteractionSurface.js";
5
- import { graphRelatedEdges as Q, graphEdgeLabelPosition as gt, graphSectionPath as vt } from "./geometry.js";
6
- import { GraphMinimap as ft } from "./GraphMinimap.js";
7
- var mt = /* @__PURE__ */ B("<div data-floe-canvas-pan-surface=true role=group tabindex=0>"), bt = /* @__PURE__ */ B("<div role=region tabindex=0>"), xt = /* @__PURE__ */ B('<svg class=floe-graph__edges><defs><marker viewBox="0 0 8 8"refX=7 refY=4 markerWidth=7 markerHeight=7 orient=auto-start-reverse><path d="M1 1 L7 4 L1 7"fill=none stroke=context-stroke stroke-width=1.2>'), yt = /* @__PURE__ */ B("<svg><g><path class=floe-graph__edge></path><path class=floe-graph__edge-target tabindex=0 role=button data-floe-canvas-pan-surface=true></svg>", !1, !0, !1), kt = /* @__PURE__ */ B("<svg><text class=floe-graph__edge-label aria-hidden=true></svg>", !1, !0, !1);
8
- function Lt(i) {
9
- const N = `graph-arrow-${dt()}`;
10
- let v;
11
- const [Z, p] = J(null), [V, tt] = J({
5
+ import { graphRelatedEdges as Z, graphEdgeLabelPosition as vt, graphSectionPath as ft } from "./geometry.js";
6
+ import { GraphMinimap as mt } from "./GraphMinimap.js";
7
+ var bt = /* @__PURE__ */ B("<div data-floe-canvas-pan-surface=true role=group tabindex=0>"), xt = /* @__PURE__ */ B("<div role=region tabindex=0>"), yt = /* @__PURE__ */ B('<svg class=floe-graph__edges><defs><marker viewBox="0 0 8 8"refX=7 refY=4 markerWidth=7 markerHeight=7 orient=auto-start-reverse><path d="M1 1 L7 4 L1 7"fill=none stroke=context-stroke stroke-width=1.2>'), kt = /* @__PURE__ */ B("<svg><g><path class=floe-graph__edge></path><path class=floe-graph__edge-target tabindex=0 role=button data-floe-canvas-pan-surface=true></svg>", !1, !0, !1), wt = /* @__PURE__ */ B("<svg><text class=floe-graph__edge-label aria-hidden=true></svg>", !1, !0, !1);
8
+ function It(o) {
9
+ const V = `graph-arrow-${ct()}`;
10
+ let f;
11
+ const [p, tt] = Q(null), [F, et] = Q({
12
12
  width: 0,
13
13
  height: 0
14
- }), F = () => i.highlight === void 0 ? Z() : i.highlight, et = x(() => new Map(i.layout.nodes.map((t) => [t.id, t]))), nt = x(() => {
15
- const t = F();
16
- return t?.kind === "node" ? Q(i.layout, t.id) : new Set(t ? [t.id] : []);
17
- }), W = x(() => {
18
- const t = F();
14
+ }), W = () => o.highlight === void 0 ? p() : o.highlight, j = v(() => o.layout.nodes), nt = v(() => new Map(j().map((t) => [t.id, t]))), rt = v(() => {
15
+ const t = W();
16
+ return t?.kind === "node" ? Z(o.layout, t.id) : new Set(t ? [t.id] : []);
17
+ }), q = v(() => {
18
+ const t = W();
19
19
  if (t?.kind !== "node") return null;
20
- const e = et().get(t.id), r = e?.kind === "group" ? e.id : e?.parentId;
21
- return r ? Q(i.layout, r) : null;
22
- }), j = (t) => i.selected?.kind === t.kind && i.selected.id === t.id, D = (t) => {
20
+ const e = nt().get(t.id), r = e?.kind === "group" ? e.id : e?.parentId;
21
+ return r ? Z(o.layout, r) : null;
22
+ }), D = (t) => o.selected?.kind === t.kind && o.selected.id === t.id, H = (t) => {
23
23
  const {
24
24
  width: e,
25
25
  height: r
26
- } = V();
26
+ } = F();
27
27
  if (!e || !r) return;
28
28
  const n = -t.x / t.scale - 240, a = -t.y / t.scale - 240, y = n + e / t.scale + 480, s = a + r / t.scale + 480;
29
29
  return {
@@ -32,34 +32,34 @@ function Lt(i) {
32
32
  right: y,
33
33
  bottom: s
34
34
  };
35
- }, rt = (t) => {
36
- const e = D(t);
37
- if (!e) return i.layout.nodes;
35
+ }, at = (t) => {
36
+ const e = H(t);
37
+ if (!e) return j();
38
38
  const {
39
39
  left: r,
40
40
  top: n,
41
41
  right: a,
42
42
  bottom: y
43
43
  } = e;
44
- return i.layout.nodes.filter((s) => s.id === i.selected?.id || s.x + s.width >= r && s.x <= a && s.y + s.height >= n && s.y <= y);
45
- }, q = x(() => i.layout.edges.map((t) => ({
44
+ return j().filter((s) => s.id === o.selected?.id || s.x + s.width >= r && s.x <= a && s.y + s.height >= n && s.y <= y);
45
+ }, K = v(() => o.layout.edges.map((t) => ({
46
46
  edge: t,
47
- path: t.sections.map(vt).join(" "),
48
- label: gt(t.sections),
47
+ path: t.sections.map(ft).join(" "),
48
+ label: vt(t.sections),
49
49
  segments: t.sections.flatMap((e) => e.slice(1).map((r, n) => ({
50
50
  left: Math.min(r.x, e[n].x),
51
51
  right: Math.max(r.x, e[n].x),
52
52
  top: Math.min(r.y, e[n].y),
53
53
  bottom: Math.max(r.y, e[n].y)
54
54
  })))
55
- }))), at = (t) => {
56
- const e = D(t);
57
- return e ? q().filter(({
55
+ }))), ot = (t) => {
56
+ const e = H(t);
57
+ return e ? K().filter(({
58
58
  edge: r,
59
59
  segments: n
60
- }) => r.id === i.selected?.id || n.some((a) => a.left <= e.right && a.right >= e.left && a.top <= e.bottom && a.bottom >= e.top)) : q();
61
- }, f = (t) => {
62
- p(t), i.onHover?.(t);
60
+ }) => r.id === o.selected?.id || n.some((a) => a.left <= e.right && a.right >= e.left && a.top <= e.bottom && a.bottom >= e.top)) : K();
61
+ }, m = (t) => {
62
+ tt(t), o.onHover?.(t);
63
63
  }, $ = (t, e, r) => {
64
64
  const n = e.getBoundingClientRect();
65
65
  return {
@@ -73,39 +73,39 @@ function Lt(i) {
73
73
  y: n.top + Math.min(32, n.height / 2)
74
74
  }
75
75
  };
76
- }, H = (t, e) => {
77
- i.onContextMenu && (e.preventDefault(), e.stopPropagation(), i.onContextMenu($(t, e.currentTarget, e)));
78
76
  }, X = (t, e) => {
79
- e.target === e.currentTarget && (e.key === "ContextMenu" || e.shiftKey && e.key === "F10" ? (e.preventDefault(), e.stopPropagation(), i.onContextMenu?.($(t, e.currentTarget))) : e.key === "Enter" ? (e.preventDefault(), e.stopPropagation(), i.onActivate?.($(t, e.currentTarget))) : e.key === "Escape" && (f(null), i.onActivate?.($(null, v))));
77
+ o.onContextMenu && (e.preventDefault(), e.stopPropagation(), o.onContextMenu($(t, e.currentTarget, e)));
78
+ }, Y = (t, e) => {
79
+ e.target === e.currentTarget && (e.key === "ContextMenu" || e.shiftKey && e.key === "F10" ? (e.preventDefault(), e.stopPropagation(), o.onContextMenu?.($(t, e.currentTarget))) : e.key === "Enter" ? (e.preventDefault(), e.stopPropagation(), o.onActivate?.($(t, e.currentTarget))) : e.key === "Escape" && (m(null), o.onActivate?.($(null, f))));
80
80
  };
81
- ct(() => {
82
- if (!v) return;
83
- const t = () => tt({
84
- width: v.clientWidth,
85
- height: v.clientHeight
81
+ ut(() => {
82
+ if (!f) return;
83
+ const t = () => et({
84
+ width: f.clientWidth,
85
+ height: f.clientHeight
86
86
  });
87
87
  t();
88
88
  const e = new ResizeObserver(t);
89
- e.observe(v), ut(() => e.disconnect());
89
+ e.observe(f), st(() => e.disconnect());
90
90
  });
91
- const K = (t) => {
91
+ const O = (t) => {
92
92
  const e = {
93
93
  kind: "node",
94
94
  id: t.id
95
95
  }, r = {
96
- selected: () => j(e),
97
- openMenu: (n) => H(e, n)
96
+ selected: () => D(e),
97
+ openMenu: (n) => X(e, n)
98
98
  };
99
99
  return (() => {
100
- var n = mt();
101
- return n.$$keydown = (a) => X(e, a), n.$$contextmenu = (a) => H(e, a), n.$$click = (a) => {
102
- a.target.closest("button, a, input, select, textarea, [data-floe-canvas-interactive]") || (a.stopPropagation(), i.onActivate?.($(e, a.currentTarget, a)));
103
- }, n.$$focusout = () => f(null), n.$$focusin = () => f(e), n.addEventListener("pointerleave", () => f(null)), n.addEventListener("pointerenter", () => f(e)), S(n, (() => {
104
- var a = it(() => !!(t.kind === "group" && i.renderGroup));
105
- return () => a() ? i.renderGroup(t, r) : i.renderNode(t, r);
100
+ var n = bt();
101
+ return n.$$keydown = (a) => Y(e, a), n.$$contextmenu = (a) => X(e, a), n.$$click = (a) => {
102
+ a.target.closest("button, a, input, select, textarea, [data-floe-canvas-interactive]") || (a.stopPropagation(), o.onActivate?.($(e, a.currentTarget, a)));
103
+ }, n.$$focusout = () => m(null), n.$$focusin = () => m(e), n.addEventListener("pointerleave", () => m(null)), n.addEventListener("pointerenter", () => m(e)), S(n, (() => {
104
+ var a = it(() => !!(t.kind === "group" && o.renderGroup));
105
+ return () => a() ? o.renderGroup(t, r) : o.renderNode(t, r);
106
106
  })()), z((a) => {
107
- var y = t.kind === "group" ? "floe-graph__group" : "floe-graph__node", s = t.id, G = j(e), d = `${t.x}px`, C = `${t.y}px`, M = `${t.width}px`, l = `${t.height}px`, u = t.label;
108
- return y !== a.e && U(n, a.e = y), s !== a.t && c(n, "data-graph-object", a.t = s), G !== a.a && c(n, "data-selected", a.a = G), d !== a.o && L(n, "left", a.o = d), C !== a.i && L(n, "top", a.i = C), M !== a.n && L(n, "width", a.n = M), l !== a.s && L(n, "height", a.s = l), u !== a.h && c(n, "aria-label", a.h = u), a;
107
+ var y = t.kind === "group" ? "floe-graph__group" : "floe-graph__node", s = t.id, G = D(e), d = `${t.x}px`, C = `${t.y}px`, M = `${t.width}px`, l = `${t.height}px`, u = t.label;
108
+ return y !== a.e && J(n, a.e = y), s !== a.t && c(n, "data-graph-object", a.t = s), G !== a.a && c(n, "data-selected", a.a = G), d !== a.o && L(n, "left", a.o = d), C !== a.i && L(n, "top", a.i = C), M !== a.n && L(n, "width", a.n = M), l !== a.s && L(n, "height", a.s = l), u !== a.h && c(n, "aria-label", a.h = u), a;
109
109
  }, {
110
110
  e: void 0,
111
111
  t: void 0,
@@ -119,95 +119,95 @@ function Lt(i) {
119
119
  })();
120
120
  };
121
121
  return (() => {
122
- var t = bt();
123
- t.$$keydown = (r) => X(null, r);
124
- var e = v;
125
- return typeof e == "function" ? ot(e, t) : v = t, S(t, w(st, {
122
+ var t = xt();
123
+ t.$$keydown = (r) => Y(null, r);
124
+ var e = f;
125
+ return typeof e == "function" ? lt(e, t) : f = t, S(t, w(gt, {
126
126
  get viewport() {
127
- return i.viewport;
127
+ return o.viewport;
128
128
  },
129
129
  minScale: 0.1,
130
130
  maxScale: 3,
131
131
  get ariaLabel() {
132
- return i.ariaLabel;
132
+ return o.ariaLabel;
133
133
  },
134
134
  get onViewportChange() {
135
- return i.onViewportChange;
135
+ return o.onViewportChange;
136
136
  },
137
- onViewportInteractionStart: () => i.onInteractionStart?.(),
137
+ onViewportInteractionStart: () => o.onInteractionStart?.(),
138
138
  resolveTargetRole: (r) => (r.target instanceof Element ? r.target : null)?.closest('button, a, input, select, textarea, [data-floe-canvas-interactive="true"]') ? "local_surface" : ht(r),
139
139
  onCanvasPointerDown: (r) => {
140
- !(r.target instanceof Element) || r.target.closest("[data-graph-object]") || i.onActivate?.($(null, v, r));
140
+ !(r.target instanceof Element) || r.target.closest("[data-graph-object]") || o.onActivate?.($(null, f, r));
141
141
  },
142
- onCanvasContextMenu: (r) => i.onContextMenu?.({
142
+ onCanvasContextMenu: (r) => o.onContextMenu?.({
143
143
  object: null,
144
- owner: v,
144
+ owner: f,
145
145
  position: {
146
146
  x: r.clientX,
147
147
  y: r.clientY
148
148
  }
149
149
  }),
150
150
  children: (r) => {
151
- const n = x(() => {
152
- const d = D(r());
151
+ const n = v(() => {
152
+ const d = H(r());
153
153
  if (d) return d;
154
154
  const {
155
155
  x: C,
156
156
  y: M,
157
157
  width: l,
158
158
  height: u
159
- } = i.layout.bounds;
159
+ } = o.layout.bounds;
160
160
  return {
161
161
  left: C - 240,
162
162
  top: M - 240,
163
163
  right: C + l + 240,
164
164
  bottom: M + u + 240
165
165
  };
166
- }), a = x(() => rt(r())), y = x(() => a().filter((d) => d.kind === "group")), s = x(() => a().filter((d) => d.kind !== "group")), G = x(() => at(r()));
167
- return [w(Y, {
166
+ }), a = v(() => at(r())), y = v(() => a().filter((d) => d.kind === "group")), s = v(() => a().filter((d) => d.kind !== "group")), G = v(() => ot(r()));
167
+ return [w(_, {
168
168
  get each() {
169
169
  return y();
170
170
  },
171
- children: K
171
+ children: O
172
172
  }), (() => {
173
- var d = xt(), C = d.firstChild, M = C.firstChild;
174
- return c(M, "id", N), S(d, w(Y, {
173
+ var d = yt(), C = d.firstChild, M = C.firstChild;
174
+ return c(M, "id", V), S(d, w(_, {
175
175
  get each() {
176
176
  return G();
177
177
  },
178
178
  children: (l) => {
179
179
  const {
180
180
  edge: u
181
- } = l, m = {
181
+ } = l, b = {
182
182
  kind: "edge",
183
183
  id: u.id
184
184
  }, I = () => l.path, R = () => l.label;
185
- return w(_, {
185
+ return w(N, {
186
186
  get when() {
187
- return !W() || W().has(u.id);
187
+ return !q() || q().has(u.id);
188
188
  },
189
189
  get children() {
190
- var b = yt(), E = b.firstChild, h = E.nextSibling;
191
- return c(E, "marker-end", `url(#${N})`), S(b, w(_, {
190
+ var x = kt(), E = x.firstChild, g = E.nextSibling;
191
+ return c(E, "marker-end", `url(#${V})`), S(x, w(N, {
192
192
  get when() {
193
193
  return R();
194
194
  },
195
- children: (o) => (() => {
196
- var k = kt();
197
- return S(k, () => u.label), z((g) => {
198
- var P = /^\d+$/.test(u.label), T = o().x, A = o().y - 6;
199
- return P !== g.e && c(k, "data-count", g.e = P), T !== g.t && c(k, "x", g.t = T), A !== g.a && c(k, "y", g.a = A), g;
195
+ children: (i) => (() => {
196
+ var k = wt();
197
+ return S(k, () => u.label), z((h) => {
198
+ var P = /^\d+$/.test(u.label), T = i().x, A = i().y - 6;
199
+ return P !== h.e && c(k, "data-count", h.e = P), T !== h.t && c(k, "x", h.t = T), A !== h.a && c(k, "y", h.a = A), h;
200
200
  }, {
201
201
  e: void 0,
202
202
  t: void 0,
203
203
  a: void 0
204
204
  }), k;
205
205
  })()
206
- }), h), h.$$keydown = (o) => X(m, o), h.$$contextmenu = (o) => H(m, o), h.$$click = (o) => {
207
- o.stopPropagation(), i.onActivate?.($(m, o.currentTarget, o));
208
- }, h.addEventListener("blur", () => f(null)), h.addEventListener("focus", () => f(m)), h.addEventListener("pointerleave", () => f(null)), h.addEventListener("pointerenter", () => f(m)), z((o) => {
209
- var k = u.id, g = nt().has(u.id), P = j(m), T = I(), A = I(), O = u.label;
210
- return k !== o.e && c(b, "data-graph-object", o.e = k), g !== o.t && c(b, "data-emphasized", o.t = g), P !== o.a && c(b, "data-selected", o.a = P), T !== o.o && c(E, "d", o.o = T), A !== o.i && c(h, "d", o.i = A), O !== o.n && c(h, "aria-label", o.n = O), o;
206
+ }), g), g.$$keydown = (i) => Y(b, i), g.$$contextmenu = (i) => X(b, i), g.$$click = (i) => {
207
+ i.stopPropagation(), o.onActivate?.($(b, i.currentTarget, i));
208
+ }, g.addEventListener("blur", () => m(null)), g.addEventListener("focus", () => m(b)), g.addEventListener("pointerleave", () => m(null)), g.addEventListener("pointerenter", () => m(b)), z((i) => {
209
+ var k = u.id, h = rt().has(u.id), P = D(b), T = I(), A = I(), U = u.label;
210
+ return k !== i.e && c(x, "data-graph-object", i.e = k), h !== i.t && c(x, "data-emphasized", i.t = h), P !== i.a && c(x, "data-selected", i.a = P), T !== i.o && c(E, "d", i.o = T), A !== i.i && c(g, "d", i.i = A), U !== i.n && c(g, "aria-label", i.n = U), i;
211
211
  }, {
212
212
  e: void 0,
213
213
  t: void 0,
@@ -215,13 +215,13 @@ function Lt(i) {
215
215
  o: void 0,
216
216
  i: void 0,
217
217
  n: void 0
218
- }), b;
218
+ }), x;
219
219
  }
220
220
  });
221
221
  }
222
222
  }), null), z((l) => {
223
- var u = n().right - n().left, m = n().bottom - n().top, I = `${n().left} ${n().top} ${n().right - n().left} ${n().bottom - n().top}`, R = `${n().left}px`, b = `${n().top}px`, E = i.ariaLabel;
224
- return u !== l.e && c(d, "width", l.e = u), m !== l.t && c(d, "height", l.t = m), I !== l.a && c(d, "viewBox", l.a = I), R !== l.o && L(d, "left", l.o = R), b !== l.i && L(d, "top", l.i = b), E !== l.n && c(d, "aria-label", l.n = E), l;
223
+ var u = n().right - n().left, b = n().bottom - n().top, I = `${n().left} ${n().top} ${n().right - n().left} ${n().bottom - n().top}`, R = `${n().left}px`, x = `${n().top}px`, E = o.ariaLabel;
224
+ return u !== l.e && c(d, "width", l.e = u), b !== l.t && c(d, "height", l.t = b), I !== l.a && c(d, "viewBox", l.a = I), R !== l.o && L(d, "left", l.o = R), x !== l.i && L(d, "top", l.i = x), E !== l.n && c(d, "aria-label", l.n = E), l;
225
225
  }, {
226
226
  e: void 0,
227
227
  t: void 0,
@@ -230,50 +230,53 @@ function Lt(i) {
230
230
  i: void 0,
231
231
  n: void 0
232
232
  }), d;
233
- })(), w(Y, {
233
+ })(), w(_, {
234
234
  get each() {
235
235
  return s();
236
236
  },
237
- children: K
237
+ children: O
238
238
  })];
239
239
  }
240
- }), null), S(t, w(_, {
240
+ }), null), S(t, w(N, {
241
241
  get when() {
242
- return i.minimap;
242
+ return o.minimap;
243
243
  },
244
- children: (r) => w(ft, {
244
+ children: (r) => w(mt, {
245
245
  get layout() {
246
- return i.layout;
246
+ return o.layout;
247
247
  },
248
248
  get viewport() {
249
- return i.viewport;
249
+ return o.viewport;
250
250
  },
251
251
  get size() {
252
- return V();
252
+ return F();
253
253
  },
254
254
  get onViewportChange() {
255
- return i.onViewportChange;
255
+ return o.onViewportChange;
256
256
  },
257
257
  get onInteractionStart() {
258
- return i.onInteractionStart;
258
+ return o.onInteractionStart;
259
259
  },
260
260
  get ariaLabel() {
261
261
  return r().ariaLabel;
262
262
  },
263
263
  get nodeStyle() {
264
264
  return r().nodeStyle;
265
+ },
266
+ get edges() {
267
+ return r().edges;
265
268
  }
266
269
  })
267
- }), null), S(t, () => i.overlay, null), z((r) => {
268
- var n = `floe-graph ${i.class ?? ""}`, a = i.ariaLabel;
269
- return n !== r.e && U(t, r.e = n), a !== r.t && c(t, "aria-label", r.t = a), r;
270
+ }), null), S(t, () => o.overlay, null), z((r) => {
271
+ var n = `floe-graph ${o.class ?? ""}`, a = o.ariaLabel;
272
+ return n !== r.e && J(t, r.e = n), a !== r.t && c(t, "aria-label", r.t = a), r;
270
273
  }, {
271
274
  e: void 0,
272
275
  t: void 0
273
276
  }), t;
274
277
  })();
275
278
  }
276
- lt(["focusin", "focusout", "click", "contextmenu", "keydown"]);
279
+ dt(["focusin", "focusout", "click", "contextmenu", "keydown"]);
277
280
  export {
278
- Lt as GraphCanvas
281
+ It as GraphCanvas
279
282
  };
@@ -6,6 +6,8 @@ export interface GraphMinimapNodeStyle {
6
6
  }
7
7
  export interface GraphMinimapProps {
8
8
  layout: GraphLayout;
9
+ /** Optional overview routes independent of transient main-canvas edges. */
10
+ edges?: GraphLayout['edges'];
9
11
  viewport: GraphViewport;
10
12
  size: {
11
13
  width: number;
@@ -1,25 +1,25 @@
1
- import { insert as k, createComponent as _, effect as g, setAttribute as h, style as C, template as f, use as S, delegateEvents as z } from "solid-js/web";
2
- import { createMemo as w, For as I } from "solid-js";
3
- import { graphSectionPath as A, fitGraphViewport as D } from "./geometry.js";
4
- var L = /* @__PURE__ */ f('<svg class=floe-graph__minimap role=region tabindex=0 preserveAspectRatio="xMidYMid meet"data-floe-canvas-interactive=true><path class=floe-graph__minimap-edges></path><rect class=floe-graph__minimap-viewport>'), V = /* @__PURE__ */ f("<svg><path class=floe-graph__minimap-groups></svg>", !1, !0, !1), E = /* @__PURE__ */ f("<svg><path class=floe-graph__minimap-nodes></svg>", !1, !0, !1);
1
+ import { insert as k, createComponent as _, effect as w, setAttribute as h, style as C, template as f, use as A, delegateEvents as D } from "solid-js/web";
2
+ import { createMemo as u, For as I } from "solid-js";
3
+ import { graphSectionPath as L, fitGraphViewport as V } from "./geometry.js";
4
+ var E = /* @__PURE__ */ f('<svg class=floe-graph__minimap role=region tabindex=0 preserveAspectRatio="xMidYMid meet"data-floe-canvas-interactive=true><path class=floe-graph__minimap-edges></path><rect class=floe-graph__minimap-viewport>'), j = /* @__PURE__ */ f("<svg><path class=floe-graph__minimap-groups></svg>", !1, !0, !1), B = /* @__PURE__ */ f("<svg><path class=floe-graph__minimap-nodes></svg>", !1, !0, !1);
5
5
  function R(i) {
6
- let v, s;
7
- const u = w(() => {
6
+ let c, s;
7
+ const P = u(() => i.layout.nodes), S = u(() => i.layout.bounds), g = u(() => {
8
8
  const {
9
9
  x: e,
10
10
  y: l,
11
11
  width: d,
12
12
  height: n
13
- } = i.layout.bounds, t = Math.max(d, n, 1) * 0.04;
13
+ } = S(), t = Math.max(d, n, 1) * 0.04;
14
14
  return {
15
15
  x: e - t,
16
16
  y: l - t,
17
17
  width: d + t * 2,
18
18
  height: n + t * 2
19
19
  };
20
- }), m = w(() => {
20
+ }), m = u(() => {
21
21
  const e = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
22
- for (const n of i.layout.nodes) {
22
+ for (const n of P()) {
23
23
  const t = i.nodeStyle?.(n) ?? {}, o = n.kind === "group" ? e : l, r = JSON.stringify([t.fill ?? null, t.stroke ?? null]);
24
24
  let a = o.get(r);
25
25
  a || (a = {
@@ -42,14 +42,14 @@ function R(i) {
42
42
  "--graph-minimap-fill": e.fill,
43
43
  "--graph-minimap-stroke": e.stroke,
44
44
  "--graph-minimap-opacity": e.fill || e.stroke ? "1" : void 0
45
- }), P = w(() => i.layout.edges.flatMap((e) => e.sections.map(A)).join(" ")), y = (e) => {
46
- const l = v?.getScreenCTM();
45
+ }), z = u(() => (i.edges ?? i.layout.edges).flatMap((e) => e.sections.map(L)).join(" ")), y = (e) => {
46
+ const l = c?.getScreenCTM();
47
47
  return l ? new DOMPoint(e.clientX, e.clientY).matrixTransform(l.inverse()) : void 0;
48
48
  }, x = (e) => {
49
- s?.id === e.pointerId && (s = void 0, v?.hasPointerCapture(e.pointerId) && v.releasePointerCapture(e.pointerId));
49
+ s?.id === e.pointerId && (s = void 0, c?.hasPointerCapture(e.pointerId) && c.releasePointerCapture(e.pointerId));
50
50
  };
51
51
  return (() => {
52
- var e = L(), l = e.firstChild, d = l.nextSibling;
52
+ var e = E(), l = e.firstChild, d = l.nextSibling;
53
53
  e.$$keydown = (t) => {
54
54
  const r = {
55
55
  ArrowLeft: [1, 0],
@@ -61,7 +61,7 @@ function R(i) {
61
61
  ...i.viewport,
62
62
  x: i.viewport.x + r[0] * i.size.width * 0.2,
63
63
  y: i.viewport.y + r[1] * i.size.height * 0.2
64
- } : D(i.layout.bounds, i.size, 24)));
64
+ } : V(i.layout.bounds, i.size, 24)));
65
65
  }, e.addEventListener("lostpointercapture", () => {
66
66
  s = void 0;
67
67
  }), e.addEventListener("pointercancel", x), e.$$pointerup = x, e.$$pointermove = (t) => {
@@ -75,7 +75,7 @@ function R(i) {
75
75
  }, e.$$pointerdown = (t) => {
76
76
  if (t.button !== 0) return;
77
77
  const o = y(t);
78
- o && (t.preventDefault(), t.stopPropagation(), i.onInteractionStart?.(), v.focus({
78
+ o && (t.preventDefault(), t.stopPropagation(), i.onInteractionStart?.(), c.focus({
79
79
  preventScroll: !0
80
80
  }), t.target.matches(".floe-graph__minimap-viewport") || i.onViewportChange({
81
81
  ...i.viewport,
@@ -88,18 +88,18 @@ function R(i) {
88
88
  viewport: {
89
89
  ...i.viewport
90
90
  }
91
- }, v.setPointerCapture(t.pointerId));
91
+ }, c.setPointerCapture(t.pointerId));
92
92
  };
93
- var n = v;
94
- return typeof n == "function" ? S(n, e) : v = e, k(e, _(I, {
93
+ var n = c;
94
+ return typeof n == "function" ? A(n, e) : c = e, k(e, _(I, {
95
95
  get each() {
96
96
  return m().groups;
97
97
  },
98
98
  children: (t) => (() => {
99
- var o = V();
100
- return g((r) => {
101
- var a = t.path, c = p(t);
102
- return a !== r.e && h(o, "d", r.e = a), r.t = C(o, c, r.t), r;
99
+ var o = j();
100
+ return w((r) => {
101
+ var a = t.path, v = p(t);
102
+ return a !== r.e && h(o, "d", r.e = a), r.t = C(o, v, r.t), r;
103
103
  }, {
104
104
  e: void 0,
105
105
  t: void 0
@@ -110,18 +110,18 @@ function R(i) {
110
110
  return m().nodes;
111
111
  },
112
112
  children: (t) => (() => {
113
- var o = E();
114
- return g((r) => {
115
- var a = t.path, c = p(t);
116
- return a !== r.e && h(o, "d", r.e = a), r.t = C(o, c, r.t), r;
113
+ var o = B();
114
+ return w((r) => {
115
+ var a = t.path, v = p(t);
116
+ return a !== r.e && h(o, "d", r.e = a), r.t = C(o, v, r.t), r;
117
117
  }, {
118
118
  e: void 0,
119
119
  t: void 0
120
120
  }), o;
121
121
  })()
122
- }), d), g((t) => {
123
- var o = i.ariaLabel, r = `${u().x} ${u().y} ${u().width} ${u().height}`, a = P(), c = -i.viewport.x / i.viewport.scale, $ = -i.viewport.y / i.viewport.scale, b = i.size.width / i.viewport.scale, M = i.size.height / i.viewport.scale;
124
- return o !== t.e && h(e, "aria-label", t.e = o), r !== t.t && h(e, "viewBox", t.t = r), a !== t.a && h(l, "d", t.a = a), c !== t.o && h(d, "x", t.o = c), $ !== t.i && h(d, "y", t.i = $), b !== t.n && h(d, "width", t.n = b), M !== t.s && h(d, "height", t.s = M), t;
122
+ }), d), w((t) => {
123
+ var o = i.ariaLabel, r = `${g().x} ${g().y} ${g().width} ${g().height}`, a = z(), v = -i.viewport.x / i.viewport.scale, $ = -i.viewport.y / i.viewport.scale, b = i.size.width / i.viewport.scale, M = i.size.height / i.viewport.scale;
124
+ return o !== t.e && h(e, "aria-label", t.e = o), r !== t.t && h(e, "viewBox", t.t = r), a !== t.a && h(l, "d", t.a = a), v !== t.o && h(d, "x", t.o = v), $ !== t.i && h(d, "y", t.i = $), b !== t.n && h(d, "width", t.n = b), M !== t.s && h(d, "height", t.s = M), t;
125
125
  }, {
126
126
  e: void 0,
127
127
  t: void 0,
@@ -133,7 +133,7 @@ function R(i) {
133
133
  }), e;
134
134
  })();
135
135
  }
136
- z(["pointerdown", "pointermove", "pointerup", "keydown"]);
136
+ D(["pointerdown", "pointermove", "pointerup", "keydown"]);
137
137
  export {
138
138
  R as GraphMinimap
139
139
  };
@@ -1,6 +1,10 @@
1
- import type { GraphInput, GraphLayout, GraphLayoutOptions } from './types';
1
+ import type { GraphEdge, GraphInput, GraphLayout, GraphLayoutEdge, GraphLayoutOptions, GraphRoutingOptions } from './types';
2
2
  export interface GraphLayoutEngine {
3
3
  layout(input: GraphInput, options?: GraphLayoutOptions): Promise<GraphLayout>;
4
+ /** Route only the supplied edges; geometry and bounds remain authoritative. */
5
+ route(geometry: Pick<GraphLayout, 'nodes' | 'bounds'>, edges: readonly GraphEdge[], options?: GraphRoutingOptions, request?: {
6
+ signal?: AbortSignal;
7
+ }): Promise<readonly GraphLayoutEdge[]>;
4
8
  dispose(): void;
5
9
  }
6
10
  /** One worker per mounted graph. Dispose on unmount; failures are never hidden. */
@@ -1,39 +1,55 @@
1
1
  function w() {
2
- const t = new Worker(new URL("../../assets/layout-worker-BK6m515B.js", import.meta.url), { type: "module" });
3
- let s, u = 0;
4
- const o = /* @__PURE__ */ new Map(), n = (e) => {
5
- s = e, t.terminate();
6
- for (const r of o.values()) r.reject(e);
7
- o.clear();
2
+ const o = new Worker(new URL("../../assets/layout-worker-CFMp3t5w.js", import.meta.url), { type: "module" });
3
+ let a, d = 0;
4
+ const t = /* @__PURE__ */ new Map(), n = (e) => {
5
+ a = e, o.terminate();
6
+ for (const r of t.values())
7
+ r.cleanup(), r.reject(e);
8
+ t.clear();
8
9
  };
9
- return t.addEventListener(
10
+ o.addEventListener(
10
11
  "error",
11
12
  (e) => n(new Error(e.message || "Graph layout worker failed"))
12
- ), t.addEventListener(
13
+ ), o.addEventListener(
13
14
  "messageerror",
14
15
  () => n(new Error("Invalid graph layout worker response"))
15
- ), t.addEventListener("message", ({ data: e }) => {
16
- if (!e || !Number.isInteger(e.id) || !e.error && !e.layout) {
16
+ ), o.addEventListener("message", ({ data: e }) => {
17
+ if (!e || !Number.isInteger(e.id)) {
17
18
  n(new Error("Invalid graph layout worker response"));
18
19
  return;
19
20
  }
20
- const r = o.get(e.id);
21
- r && (o.delete(e.id), e.error ? r.reject(new Error(e.error)) : r.resolve(e.layout));
22
- }), {
23
- layout(e, r) {
24
- return s ? Promise.reject(s) : new Promise((a, l) => {
25
- const i = ++u;
26
- o.set(i, { resolve: a, reject: l });
27
- try {
28
- t.postMessage({ id: i, input: e, options: r ?? {} });
29
- } catch (p) {
30
- o.delete(i), l(p);
31
- }
32
- });
33
- },
34
- dispose() {
35
- n(new Error("Graph layout engine disposed"));
21
+ const r = t.get(e.id);
22
+ if (r) {
23
+ if (!e.error && (r.kind === "layout" ? !e.layout : !Array.isArray(e.edges))) {
24
+ n(new Error("Invalid graph layout worker response"));
25
+ return;
26
+ }
27
+ t.delete(e.id), r.cleanup(), e.error ? r.reject(new Error(e.error)) : r.resolve(r.kind === "layout" ? e.layout : e.edges);
36
28
  }
29
+ });
30
+ const p = (e, r) => a ? Promise.reject(a) : r?.aborted ? Promise.reject(new DOMException("Graph routing canceled", "AbortError")) : new Promise((l, s) => {
31
+ const i = ++d, u = () => {
32
+ t.delete(i) && (r?.removeEventListener("abort", u), o.postMessage({ id: i, cancel: !0 }), s(new DOMException("Graph routing canceled", "AbortError")));
33
+ };
34
+ t.set(i, {
35
+ kind: e.kind,
36
+ resolve: (c) => l(c),
37
+ reject: s,
38
+ cleanup: () => r?.removeEventListener("abort", u)
39
+ }), r?.addEventListener("abort", u, { once: !0 });
40
+ try {
41
+ o.postMessage({ id: i, ...e });
42
+ } catch (c) {
43
+ t.delete(i), r?.removeEventListener("abort", u), s(c);
44
+ }
45
+ });
46
+ return {
47
+ layout: (e, r = {}) => p({ kind: "layout", input: e, options: r }),
48
+ route: (e, r, l = {}, s) => p(
49
+ { kind: "route", geometry: e, edges: r, options: l },
50
+ s?.signal
51
+ ),
52
+ dispose: () => n(new Error("Graph layout engine disposed"))
37
53
  };
38
54
  }
39
55
  export {
@@ -0,0 +1,6 @@
1
+ import type { GraphGroupLayout, GraphLayoutNode, GraphLayoutOptions, GraphPoint } from './types';
2
+ /** Pack complete child subtrees in submitted order, without using edges as ranks. */
3
+ export declare function arrangeGroupMembers(members: readonly GraphLayoutNode[], rule: GraphGroupLayout, padding: NonNullable<GraphLayoutOptions['groupPadding']>, spacing: number, translate: (node: GraphLayoutNode, dx: number, dy: number) => void, origin?: GraphPoint): {
4
+ width: number;
5
+ height: number;
6
+ };