@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.
- package/dist/assets/layout-worker-CFMp3t5w.js +1952 -0
- package/dist/components/graph/GraphCanvas.d.ts +1 -1
- package/dist/components/graph/GraphCanvas.js +107 -104
- package/dist/components/graph/GraphMinimap.d.ts +2 -0
- package/dist/components/graph/GraphMinimap.js +30 -30
- package/dist/components/graph/engine.d.ts +5 -1
- package/dist/components/graph/engine.js +42 -26
- package/dist/components/graph/group-layout.d.ts +6 -0
- package/dist/components/graph/layout.d.ts +3 -1
- package/dist/components/graph/routing.d.ts +1 -1
- package/dist/components/graph/types.d.ts +11 -0
- package/package.json +1 -1
- package/dist/assets/layout-worker-BK6m515B.js +0 -1875
|
@@ -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
|
|
2
|
-
import { createUniqueId as
|
|
3
|
-
import { InfiniteCanvas as
|
|
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
|
|
6
|
-
import { GraphMinimap as
|
|
7
|
-
var
|
|
8
|
-
function
|
|
9
|
-
const
|
|
10
|
-
let
|
|
11
|
-
const [
|
|
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
|
-
}),
|
|
15
|
-
const t =
|
|
16
|
-
return t?.kind === "node" ?
|
|
17
|
-
}),
|
|
18
|
-
const t =
|
|
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 =
|
|
21
|
-
return r ?
|
|
22
|
-
}),
|
|
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
|
-
} =
|
|
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
|
-
},
|
|
36
|
-
const e =
|
|
37
|
-
if (!e) return
|
|
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
|
|
45
|
-
},
|
|
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(
|
|
48
|
-
label:
|
|
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
|
-
}))),
|
|
56
|
-
const e =
|
|
57
|
-
return e ?
|
|
55
|
+
}))), ot = (t) => {
|
|
56
|
+
const e = H(t);
|
|
57
|
+
return e ? K().filter(({
|
|
58
58
|
edge: r,
|
|
59
59
|
segments: n
|
|
60
|
-
}) => r.id ===
|
|
61
|
-
},
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
if (!
|
|
83
|
-
const t = () =>
|
|
84
|
-
width:
|
|
85
|
-
height:
|
|
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(
|
|
89
|
+
e.observe(f), st(() => e.disconnect());
|
|
90
90
|
});
|
|
91
|
-
const
|
|
91
|
+
const O = (t) => {
|
|
92
92
|
const e = {
|
|
93
93
|
kind: "node",
|
|
94
94
|
id: t.id
|
|
95
95
|
}, r = {
|
|
96
|
-
selected: () =>
|
|
97
|
-
openMenu: (n) =>
|
|
96
|
+
selected: () => D(e),
|
|
97
|
+
openMenu: (n) => X(e, n)
|
|
98
98
|
};
|
|
99
99
|
return (() => {
|
|
100
|
-
var n =
|
|
101
|
-
return n.$$keydown = (a) =>
|
|
102
|
-
a.target.closest("button, a, input, select, textarea, [data-floe-canvas-interactive]") || (a.stopPropagation(),
|
|
103
|
-
}, n.$$focusout = () =>
|
|
104
|
-
var a = it(() => !!(t.kind === "group" &&
|
|
105
|
-
return () => a() ?
|
|
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 =
|
|
108
|
-
return y !== a.e &&
|
|
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 =
|
|
123
|
-
t.$$keydown = (r) =>
|
|
124
|
-
var e =
|
|
125
|
-
return typeof e == "function" ?
|
|
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
|
|
127
|
+
return o.viewport;
|
|
128
128
|
},
|
|
129
129
|
minScale: 0.1,
|
|
130
130
|
maxScale: 3,
|
|
131
131
|
get ariaLabel() {
|
|
132
|
-
return
|
|
132
|
+
return o.ariaLabel;
|
|
133
133
|
},
|
|
134
134
|
get onViewportChange() {
|
|
135
|
-
return
|
|
135
|
+
return o.onViewportChange;
|
|
136
136
|
},
|
|
137
|
-
onViewportInteractionStart: () =>
|
|
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]") ||
|
|
140
|
+
!(r.target instanceof Element) || r.target.closest("[data-graph-object]") || o.onActivate?.($(null, f, r));
|
|
141
141
|
},
|
|
142
|
-
onCanvasContextMenu: (r) =>
|
|
142
|
+
onCanvasContextMenu: (r) => o.onContextMenu?.({
|
|
143
143
|
object: null,
|
|
144
|
-
owner:
|
|
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 =
|
|
152
|
-
const d =
|
|
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
|
-
} =
|
|
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 =
|
|
167
|
-
return [w(
|
|
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:
|
|
171
|
+
children: O
|
|
172
172
|
}), (() => {
|
|
173
|
-
var d =
|
|
174
|
-
return c(M, "id",
|
|
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,
|
|
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 !
|
|
187
|
+
return !q() || q().has(u.id);
|
|
188
188
|
},
|
|
189
189
|
get children() {
|
|
190
|
-
var
|
|
191
|
-
return c(E, "marker-end", `url(#${
|
|
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: (
|
|
196
|
-
var k =
|
|
197
|
-
return S(k, () => u.label), z((
|
|
198
|
-
var P = /^\d+$/.test(u.label), T =
|
|
199
|
-
return P !==
|
|
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
|
-
}),
|
|
207
|
-
|
|
208
|
-
},
|
|
209
|
-
var k = u.id,
|
|
210
|
-
return k !==
|
|
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
|
-
}),
|
|
218
|
+
}), x;
|
|
219
219
|
}
|
|
220
220
|
});
|
|
221
221
|
}
|
|
222
222
|
}), null), z((l) => {
|
|
223
|
-
var u = n().right - n().left,
|
|
224
|
-
return u !== l.e && c(d, "width", l.e = u),
|
|
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(
|
|
233
|
+
})(), w(_, {
|
|
234
234
|
get each() {
|
|
235
235
|
return s();
|
|
236
236
|
},
|
|
237
|
-
children:
|
|
237
|
+
children: O
|
|
238
238
|
})];
|
|
239
239
|
}
|
|
240
|
-
}), null), S(t, w(
|
|
240
|
+
}), null), S(t, w(N, {
|
|
241
241
|
get when() {
|
|
242
|
-
return
|
|
242
|
+
return o.minimap;
|
|
243
243
|
},
|
|
244
|
-
children: (r) => w(
|
|
244
|
+
children: (r) => w(mt, {
|
|
245
245
|
get layout() {
|
|
246
|
-
return
|
|
246
|
+
return o.layout;
|
|
247
247
|
},
|
|
248
248
|
get viewport() {
|
|
249
|
-
return
|
|
249
|
+
return o.viewport;
|
|
250
250
|
},
|
|
251
251
|
get size() {
|
|
252
|
-
return
|
|
252
|
+
return F();
|
|
253
253
|
},
|
|
254
254
|
get onViewportChange() {
|
|
255
|
-
return
|
|
255
|
+
return o.onViewportChange;
|
|
256
256
|
},
|
|
257
257
|
get onInteractionStart() {
|
|
258
|
-
return
|
|
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, () =>
|
|
268
|
-
var n = `floe-graph ${
|
|
269
|
-
return n !== r.e &&
|
|
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
|
-
|
|
279
|
+
dt(["focusin", "focusout", "click", "contextmenu", "keydown"]);
|
|
277
280
|
export {
|
|
278
|
-
|
|
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
|
|
2
|
-
import { createMemo as
|
|
3
|
-
import { graphSectionPath as
|
|
4
|
-
var
|
|
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
|
|
7
|
-
const u =
|
|
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
|
-
} =
|
|
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 =
|
|
20
|
+
}), m = u(() => {
|
|
21
21
|
const e = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
|
|
22
|
-
for (const n of
|
|
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
|
-
}),
|
|
46
|
-
const l =
|
|
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,
|
|
49
|
+
s?.id === e.pointerId && (s = void 0, c?.hasPointerCapture(e.pointerId) && c.releasePointerCapture(e.pointerId));
|
|
50
50
|
};
|
|
51
51
|
return (() => {
|
|
52
|
-
var e =
|
|
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
|
-
} :
|
|
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?.(),
|
|
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
|
-
},
|
|
91
|
+
}, c.setPointerCapture(t.pointerId));
|
|
92
92
|
};
|
|
93
|
-
var n =
|
|
94
|
-
return typeof n == "function" ?
|
|
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 =
|
|
100
|
-
return
|
|
101
|
-
var a = t.path,
|
|
102
|
-
return a !== r.e && h(o, "d", r.e = a), r.t = C(o,
|
|
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 =
|
|
114
|
-
return
|
|
115
|
-
var a = t.path,
|
|
116
|
-
return a !== r.e && h(o, "d", r.e = a), r.t = C(o,
|
|
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),
|
|
123
|
-
var o = i.ariaLabel, r = `${
|
|
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),
|
|
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
|
-
|
|
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
|
|
3
|
-
let
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
for (const r of
|
|
7
|
-
|
|
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
|
-
|
|
10
|
+
o.addEventListener(
|
|
10
11
|
"error",
|
|
11
12
|
(e) => n(new Error(e.message || "Graph layout worker failed"))
|
|
12
|
-
),
|
|
13
|
+
), o.addEventListener(
|
|
13
14
|
"messageerror",
|
|
14
15
|
() => n(new Error("Invalid graph layout worker response"))
|
|
15
|
-
),
|
|
16
|
-
if (!e || !Number.isInteger(e.id)
|
|
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 =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
};
|