@floegence/floe-webapp-core 0.82.0 → 0.83.1
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/_virtual/_commonjs-dynamic-modules.js +6 -0
- package/dist/_virtual/_commonjsHelpers.js +6 -0
- package/dist/_virtual/elk-api.js +7 -0
- package/dist/_virtual/elk-api2.js +4 -0
- package/dist/assets/elk-worker-CrDP6jPz.js +47082 -0
- package/dist/components/chat/blocks/MarkdownMedia.d.ts +1 -0
- package/dist/components/chat/blocks/MarkdownMedia.js +104 -106
- package/dist/components/graph/GraphCanvas.d.ts +27 -0
- package/dist/components/graph/GraphCanvas.js +178 -0
- package/dist/components/graph/engine.d.ts +7 -0
- package/dist/components/graph/engine.js +35 -0
- package/dist/components/graph/geometry.d.ts +8 -0
- package/dist/components/graph/geometry.js +35 -0
- package/dist/components/graph/layout.d.ts +5 -0
- package/dist/components/graph/layout.js +121 -0
- package/dist/components/graph/types.d.ts +72 -0
- package/dist/components/ui/InfiniteCanvas.d.ts +1 -1
- package/dist/components/ui/InfiniteCanvas.js +58 -55
- package/dist/graph.css +93 -0
- package/dist/graph.d.ts +4 -0
- package/dist/graph.js +10 -0
- package/dist/licenses/elkjs.txt +263 -0
- package/dist/licenses/graph-notice.txt +5 -0
- package/dist/node_modules/.pnpm/elkjs@0.12.0/node_modules/elkjs/lib/elk-api.js +186 -0
- package/package.json +8 -2
|
@@ -35,6 +35,7 @@ export interface ResolvedMarkdownMedia {
|
|
|
35
35
|
export interface MarkdownMediaProps {
|
|
36
36
|
source: MarkdownMediaSource;
|
|
37
37
|
labels: MarkdownMediaLabels;
|
|
38
|
+
/** Replace this callback when its authorization or resource context changes. Reads inside it do not trigger reloads. */
|
|
38
39
|
resolve?: (source: MarkdownMediaSource, signal: AbortSignal) => Promise<ResolvedMarkdownMedia>;
|
|
39
40
|
class?: string;
|
|
40
41
|
}
|
|
@@ -1,141 +1,139 @@
|
|
|
1
|
-
import { use as
|
|
2
|
-
import { createSignal as
|
|
3
|
-
import { FloatingWindow as
|
|
4
|
-
import { Refresh as
|
|
5
|
-
import { cn as
|
|
6
|
-
import { sandboxedMarkdownHtml as
|
|
7
|
-
var
|
|
8
|
-
async function
|
|
9
|
-
const f =
|
|
1
|
+
import { use as B, insert as o, createComponent as i, effect as u, setAttribute as n, memo as R, className as P, template as h, delegateEvents as Q } from "solid-js/web";
|
|
2
|
+
import { createSignal as M, onMount as X, onCleanup as D, createMemo as Y, createEffect as Z, on as q, Switch as N, Match as k, Show as E } from "solid-js";
|
|
3
|
+
import { FloatingWindow as p } from "../../ui/FloatingWindow.js";
|
|
4
|
+
import { Refresh as ee, FolderOpen as re, Eye as te, Maximize as ae, ExternalLink as le } from "../../icons/index.js";
|
|
5
|
+
import { cn as ne } from "../../../utils/cn.js";
|
|
6
|
+
import { sandboxedMarkdownHtml as V, safeMarkdownMediaURL as ie } from "../markdown/media.js";
|
|
7
|
+
var oe = /* @__PURE__ */ h("<span class=chat-media-placeholder role=status>"), se = /* @__PURE__ */ h("<span class=chat-media-placeholder role=status><span></span><button type=button class=chat-media-retry>"), ce = /* @__PURE__ */ h("<button type=button class=chat-media-image-button><img class=chat-media-image loading=lazy decoding=async referrerpolicy=no-referrer>", !0, !1, !1), de = /* @__PURE__ */ h("<video class=chat-media-video controls playsinline preload=metadata>"), ve = /* @__PURE__ */ h("<audio class=chat-media-audio controls preload=metadata>"), ue = /* @__PURE__ */ h("<iframe class=chat-media-html sandbox=allow-scripts referrerpolicy=no-referrer>"), z = /* @__PURE__ */ h("<button type=button class=chat-media-action>"), he = /* @__PURE__ */ h("<div class=chat-media-preview-content><img referrerpolicy=no-referrer class=chat-media-full-image>"), me = /* @__PURE__ */ h("<span><span class=chat-media-viewport></span><span class=chat-media-header><span class=chat-media-heading><span class=chat-media-kind></span><span class=chat-media-title></span></span><span class=chat-media-actions>"), ge = /* @__PURE__ */ h('<a class=chat-media-action target=_blank rel="noopener noreferrer">');
|
|
8
|
+
async function fe(a) {
|
|
9
|
+
const f = ie(a.src ?? "");
|
|
10
10
|
if (!f || a.kind === "html") throw new Error("A host resolver is required");
|
|
11
11
|
return {
|
|
12
12
|
src: f,
|
|
13
13
|
openURL: f
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
const
|
|
17
|
-
let f,
|
|
18
|
-
const [
|
|
19
|
-
|
|
16
|
+
const Me = (a) => {
|
|
17
|
+
let f, I;
|
|
18
|
+
const [W, O] = M(!1);
|
|
19
|
+
X(() => {
|
|
20
20
|
if (typeof IntersectionObserver > "u") {
|
|
21
|
-
|
|
21
|
+
O(!0);
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
24
|
+
const s = new IntersectionObserver((c) => {
|
|
25
|
+
c.some((L) => L.isIntersecting) && (O(!0), s.disconnect());
|
|
26
26
|
}, {
|
|
27
27
|
rootMargin: "400px"
|
|
28
28
|
});
|
|
29
|
-
|
|
29
|
+
s.observe(f), D(() => s.disconnect());
|
|
30
30
|
});
|
|
31
|
-
const [
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
31
|
+
const [m, U] = M(), [j, T] = M(), [y, $] = M("loading"), [G, J] = M(0), [x, C] = M(!1), g = () => a.source.title || a.labels[a.source.kind], K = Y(() => a.source), H = () => m()?.preview?.label || a.labels.previewImage || a.labels.expand, A = (s) => {
|
|
32
|
+
I = s.currentTarget;
|
|
33
|
+
const c = m()?.preview;
|
|
34
|
+
c ? c.onSelect() : C(!0);
|
|
35
35
|
};
|
|
36
|
-
return
|
|
37
|
-
if (!
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (i.html.length > 1e6) throw new Error("HTML preview is too large");
|
|
44
|
-
d.signal.aborted || R(N(i.html));
|
|
36
|
+
return Z(q([W, K, () => a.resolve, G], ([s, c, L]) => {
|
|
37
|
+
if (!s) return;
|
|
38
|
+
const _ = L ?? fe, v = new AbortController();
|
|
39
|
+
D(() => v.abort()), U(void 0), T(void 0), $("loading"), C(!1), (async () => {
|
|
40
|
+
if (c.kind === "html" && c.html !== void 0) {
|
|
41
|
+
if (c.html.length > 1e6) throw new Error("HTML preview is too large");
|
|
42
|
+
v.signal.aborted || T(V(c.html));
|
|
45
43
|
} else {
|
|
46
|
-
const b = await
|
|
47
|
-
if (
|
|
48
|
-
if (
|
|
44
|
+
const b = await _(c, v.signal);
|
|
45
|
+
if (v.signal.aborted) return;
|
|
46
|
+
if (c.kind === "html") {
|
|
49
47
|
if (!b.loadHTML) throw new Error("HTML loader is required");
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
52
|
-
if (
|
|
53
|
-
|
|
48
|
+
const w = await b.loadHTML(v.signal);
|
|
49
|
+
if (v.signal.aborted) return;
|
|
50
|
+
if (w.length > 1e6) throw new Error("HTML preview is too large");
|
|
51
|
+
T(V(w));
|
|
54
52
|
} else if (!b.src) throw new Error("Media URL is required");
|
|
55
|
-
|
|
53
|
+
U(b);
|
|
56
54
|
}
|
|
57
|
-
|
|
55
|
+
v.signal.aborted || $("ready");
|
|
58
56
|
})().catch(() => {
|
|
59
|
-
|
|
57
|
+
v.signal.aborted || $("error");
|
|
60
58
|
});
|
|
61
|
-
}), (() => {
|
|
62
|
-
var
|
|
63
|
-
return typeof
|
|
59
|
+
})), (() => {
|
|
60
|
+
var s = me(), c = s.firstChild, L = c.nextSibling, _ = L.firstChild, v = _.firstChild, b = v.nextSibling, w = _.nextSibling, F = f;
|
|
61
|
+
return typeof F == "function" ? B(F, s) : f = s, o(c, i(N, {
|
|
64
62
|
get children() {
|
|
65
|
-
return [
|
|
63
|
+
return [i(k, {
|
|
66
64
|
get when() {
|
|
67
|
-
return
|
|
65
|
+
return y() === "loading";
|
|
68
66
|
},
|
|
69
67
|
get children() {
|
|
70
|
-
var e =
|
|
71
|
-
return
|
|
68
|
+
var e = oe();
|
|
69
|
+
return o(e, () => a.labels.loading), e;
|
|
72
70
|
}
|
|
73
|
-
}),
|
|
71
|
+
}), i(k, {
|
|
74
72
|
get when() {
|
|
75
|
-
return
|
|
73
|
+
return y() === "error";
|
|
76
74
|
},
|
|
77
75
|
get children() {
|
|
78
|
-
var e =
|
|
79
|
-
return
|
|
76
|
+
var e = se(), r = e.firstChild, t = r.nextSibling;
|
|
77
|
+
return o(r, () => a.labels.unavailable), t.$$click = () => J((l) => l + 1), o(t, i(ee, {}), null), o(t, () => a.labels.retry, null), e;
|
|
80
78
|
}
|
|
81
|
-
}),
|
|
79
|
+
}), i(k, {
|
|
82
80
|
get when() {
|
|
83
|
-
return
|
|
81
|
+
return y() === "ready";
|
|
84
82
|
},
|
|
85
83
|
get children() {
|
|
86
|
-
return
|
|
84
|
+
return i(N, {
|
|
87
85
|
get children() {
|
|
88
|
-
return [
|
|
86
|
+
return [i(k, {
|
|
89
87
|
get when() {
|
|
90
88
|
return a.source.kind === "image";
|
|
91
89
|
},
|
|
92
90
|
get children() {
|
|
93
|
-
var e =
|
|
94
|
-
return e.$$click =
|
|
95
|
-
var l = `${
|
|
96
|
-
return l !== t.e && n(e, "aria-label", t.e = l),
|
|
91
|
+
var e = ce(), r = e.firstChild;
|
|
92
|
+
return e.$$click = A, r.addEventListener("error", () => $("error")), u((t) => {
|
|
93
|
+
var l = `${H()}: ${g()}`, d = m()?.src, S = g();
|
|
94
|
+
return l !== t.e && n(e, "aria-label", t.e = l), d !== t.t && n(r, "src", t.t = d), S !== t.a && n(r, "alt", t.a = S), t;
|
|
97
95
|
}, {
|
|
98
96
|
e: void 0,
|
|
99
97
|
t: void 0,
|
|
100
98
|
a: void 0
|
|
101
99
|
}), e;
|
|
102
100
|
}
|
|
103
|
-
}),
|
|
101
|
+
}), i(k, {
|
|
104
102
|
get when() {
|
|
105
103
|
return a.source.kind === "video";
|
|
106
104
|
},
|
|
107
105
|
get children() {
|
|
108
|
-
var e =
|
|
109
|
-
return e.addEventListener("error", () =>
|
|
110
|
-
var t =
|
|
106
|
+
var e = de();
|
|
107
|
+
return e.addEventListener("error", () => $("error")), u((r) => {
|
|
108
|
+
var t = m()?.src, l = g();
|
|
111
109
|
return t !== r.e && n(e, "src", r.e = t), l !== r.t && n(e, "aria-label", r.t = l), r;
|
|
112
110
|
}, {
|
|
113
111
|
e: void 0,
|
|
114
112
|
t: void 0
|
|
115
113
|
}), e;
|
|
116
114
|
}
|
|
117
|
-
}),
|
|
115
|
+
}), i(k, {
|
|
118
116
|
get when() {
|
|
119
117
|
return a.source.kind === "audio";
|
|
120
118
|
},
|
|
121
119
|
get children() {
|
|
122
|
-
var e =
|
|
123
|
-
return e.addEventListener("error", () =>
|
|
124
|
-
var t =
|
|
120
|
+
var e = ve();
|
|
121
|
+
return e.addEventListener("error", () => $("error")), u((r) => {
|
|
122
|
+
var t = m()?.src, l = g();
|
|
125
123
|
return t !== r.e && n(e, "src", r.e = t), l !== r.t && n(e, "aria-label", r.t = l), r;
|
|
126
124
|
}, {
|
|
127
125
|
e: void 0,
|
|
128
126
|
t: void 0
|
|
129
127
|
}), e;
|
|
130
128
|
}
|
|
131
|
-
}),
|
|
129
|
+
}), i(k, {
|
|
132
130
|
get when() {
|
|
133
131
|
return a.source.kind === "html";
|
|
134
132
|
},
|
|
135
133
|
get children() {
|
|
136
134
|
var e = ue();
|
|
137
135
|
return u((r) => {
|
|
138
|
-
var t =
|
|
136
|
+
var t = g(), l = j();
|
|
139
137
|
return t !== r.e && n(e, "title", r.e = t), l !== r.t && n(e, "srcdoc", r.t = l), r;
|
|
140
138
|
}, {
|
|
141
139
|
e: void 0,
|
|
@@ -148,80 +146,80 @@ const xe = (a) => {
|
|
|
148
146
|
}
|
|
149
147
|
})];
|
|
150
148
|
}
|
|
151
|
-
})),
|
|
149
|
+
})), o(v, () => a.labels[a.source.kind]), o(b, g), o(w, i(E, {
|
|
152
150
|
get when() {
|
|
153
|
-
return
|
|
151
|
+
return R(() => y() === "ready")() && m()?.reveal;
|
|
154
152
|
},
|
|
155
153
|
children: (e) => (() => {
|
|
156
|
-
var r =
|
|
157
|
-
return r.$$click = () => e().onSelect(),
|
|
158
|
-
var l = e().label,
|
|
159
|
-
return l !== t.e && n(r, "aria-label", t.e = l),
|
|
154
|
+
var r = z();
|
|
155
|
+
return r.$$click = () => e().onSelect(), o(r, i(re, {})), u((t) => {
|
|
156
|
+
var l = e().label, d = e().label;
|
|
157
|
+
return l !== t.e && n(r, "aria-label", t.e = l), d !== t.t && n(r, "title", t.t = d), t;
|
|
160
158
|
}, {
|
|
161
159
|
e: void 0,
|
|
162
160
|
t: void 0
|
|
163
161
|
}), r;
|
|
164
162
|
})()
|
|
165
|
-
}), null),
|
|
163
|
+
}), null), o(w, i(E, {
|
|
166
164
|
get when() {
|
|
167
|
-
return
|
|
165
|
+
return R(() => y() === "ready")() && a.source.kind === "image";
|
|
168
166
|
},
|
|
169
167
|
get children() {
|
|
170
|
-
var e =
|
|
171
|
-
return e.$$click =
|
|
172
|
-
var t =
|
|
168
|
+
var e = z();
|
|
169
|
+
return e.$$click = A, o(e, i(te, {})), u((r) => {
|
|
170
|
+
var t = H(), l = H();
|
|
173
171
|
return t !== r.e && n(e, "aria-label", r.e = t), l !== r.t && n(e, "title", r.t = l), r;
|
|
174
172
|
}, {
|
|
175
173
|
e: void 0,
|
|
176
174
|
t: void 0
|
|
177
175
|
}), e;
|
|
178
176
|
}
|
|
179
|
-
}), null),
|
|
177
|
+
}), null), o(w, i(E, {
|
|
180
178
|
get when() {
|
|
181
|
-
return
|
|
179
|
+
return R(() => y() === "ready")() && a.source.kind === "html";
|
|
182
180
|
},
|
|
183
181
|
get children() {
|
|
184
|
-
var e =
|
|
185
|
-
return e.$$click = () =>
|
|
186
|
-
var t =
|
|
187
|
-
return t !== r.e && n(e, "aria-label", r.e = t), l !== r.t && n(e, "title", r.t = l),
|
|
182
|
+
var e = z();
|
|
183
|
+
return e.$$click = () => C(!x()), o(e, i(ae, {})), u((r) => {
|
|
184
|
+
var t = x() ? a.labels.collapse : a.labels.expand, l = x() ? a.labels.collapse : a.labels.expand, d = x();
|
|
185
|
+
return t !== r.e && n(e, "aria-label", r.e = t), l !== r.t && n(e, "title", r.t = l), d !== r.a && n(e, "aria-expanded", r.a = d), r;
|
|
188
186
|
}, {
|
|
189
187
|
e: void 0,
|
|
190
188
|
t: void 0,
|
|
191
189
|
a: void 0
|
|
192
190
|
}), e;
|
|
193
191
|
}
|
|
194
|
-
}), null),
|
|
192
|
+
}), null), o(w, i(E, {
|
|
195
193
|
get when() {
|
|
196
|
-
return
|
|
194
|
+
return R(() => a.source.kind !== "image" && !m()?.reveal)() && m()?.openURL;
|
|
197
195
|
},
|
|
198
196
|
children: (e) => (() => {
|
|
199
|
-
var r =
|
|
200
|
-
return
|
|
201
|
-
var l = e(),
|
|
202
|
-
return l !== t.e && n(r, "href", t.e = l),
|
|
197
|
+
var r = ge();
|
|
198
|
+
return o(r, i(le, {})), u((t) => {
|
|
199
|
+
var l = e(), d = a.labels.open, S = a.labels.open;
|
|
200
|
+
return l !== t.e && n(r, "href", t.e = l), d !== t.t && n(r, "aria-label", t.t = d), S !== t.a && n(r, "title", t.a = S), t;
|
|
203
201
|
}, {
|
|
204
202
|
e: void 0,
|
|
205
203
|
t: void 0,
|
|
206
204
|
a: void 0
|
|
207
205
|
}), r;
|
|
208
206
|
})()
|
|
209
|
-
}), null), s
|
|
207
|
+
}), null), o(s, i(E, {
|
|
210
208
|
get when() {
|
|
211
209
|
return a.source.kind === "image";
|
|
212
210
|
},
|
|
213
211
|
get children() {
|
|
214
|
-
return
|
|
212
|
+
return i(p, {
|
|
215
213
|
get open() {
|
|
216
|
-
return
|
|
214
|
+
return x();
|
|
217
215
|
},
|
|
218
216
|
onOpenChange: (e) => {
|
|
219
|
-
|
|
217
|
+
C(e), e || I?.focus({
|
|
220
218
|
preventScroll: !0
|
|
221
219
|
});
|
|
222
220
|
},
|
|
223
221
|
get title() {
|
|
224
|
-
return
|
|
222
|
+
return g();
|
|
225
223
|
},
|
|
226
224
|
get labels() {
|
|
227
225
|
return {
|
|
@@ -241,12 +239,12 @@ const xe = (a) => {
|
|
|
241
239
|
compactBelow: 640,
|
|
242
240
|
class: "chat-media-preview-window",
|
|
243
241
|
get children() {
|
|
244
|
-
var e =
|
|
245
|
-
return
|
|
242
|
+
var e = he(), r = e.firstChild;
|
|
243
|
+
return B((t) => queueMicrotask(() => t.closest('[role="dialog"]')?.focus({
|
|
246
244
|
preventScroll: !0
|
|
247
245
|
})), e), u((t) => {
|
|
248
|
-
var l =
|
|
249
|
-
return l !== t.e && n(r, "src", t.e = l),
|
|
246
|
+
var l = m()?.src, d = g();
|
|
247
|
+
return l !== t.e && n(r, "src", t.e = l), d !== t.t && n(r, "alt", t.t = d), t;
|
|
250
248
|
}, {
|
|
251
249
|
e: void 0,
|
|
252
250
|
t: void 0
|
|
@@ -255,16 +253,16 @@ const xe = (a) => {
|
|
|
255
253
|
});
|
|
256
254
|
}
|
|
257
255
|
}), null), u((e) => {
|
|
258
|
-
var r =
|
|
259
|
-
return r !== e.e &&
|
|
256
|
+
var r = ne("chat-media", x() && a.source.kind === "html" && "chat-media-expanded", a.class), t = a.source.kind, l = g();
|
|
257
|
+
return r !== e.e && P(s, e.e = r), t !== e.t && n(s, "data-media-kind", e.t = t), l !== e.a && n(b, "title", e.a = l), e;
|
|
260
258
|
}, {
|
|
261
259
|
e: void 0,
|
|
262
260
|
t: void 0,
|
|
263
261
|
a: void 0
|
|
264
|
-
}),
|
|
262
|
+
}), s;
|
|
265
263
|
})();
|
|
266
264
|
};
|
|
267
|
-
|
|
265
|
+
Q(["click"]);
|
|
268
266
|
export {
|
|
269
|
-
|
|
267
|
+
Me as MarkdownMedia
|
|
270
268
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type JSX } from 'solid-js';
|
|
2
|
+
import type { GraphLayout, GraphLayoutNode, GraphObjectEvent, GraphObjectRef, GraphViewport } from './types';
|
|
3
|
+
export interface GraphNodeRenderContext {
|
|
4
|
+
selected: () => boolean;
|
|
5
|
+
/** Use on a touch-accessible menu trigger; floating UI remains host-owned. */
|
|
6
|
+
openMenu: (event: MouseEvent) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface GraphCanvasProps {
|
|
9
|
+
layout: GraphLayout;
|
|
10
|
+
viewport: GraphViewport;
|
|
11
|
+
onViewportChange: (viewport: GraphViewport) => void;
|
|
12
|
+
ariaLabel: string;
|
|
13
|
+
renderNode: (node: GraphLayoutNode, context: GraphNodeRenderContext) => JSX.Element;
|
|
14
|
+
renderGroup?: (node: GraphLayoutNode, context: GraphNodeRenderContext) => JSX.Element;
|
|
15
|
+
selected?: GraphObjectRef | null;
|
|
16
|
+
/** Undefined follows pointer/focus. Null explicitly clears highlighting. */
|
|
17
|
+
highlight?: GraphObjectRef | null;
|
|
18
|
+
onActivate?: (event: GraphObjectEvent) => void;
|
|
19
|
+
onContextMenu?: (event: GraphObjectEvent) => void;
|
|
20
|
+
onHover?: (object: GraphObjectRef | null) => void;
|
|
21
|
+
onInteractionStart?: () => void;
|
|
22
|
+
/** Overlay content should use shared SurfaceFloatingLayer for point placement. */
|
|
23
|
+
overlay?: JSX.Element;
|
|
24
|
+
class?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Controlled graph surface. Hosts own documents and selection; Floe owns geometry and input. */
|
|
27
|
+
export declare function GraphCanvas(props: GraphCanvasProps): JSX.Element;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { insert as w, createComponent as y, setAttribute as c, effect as C, className as N, template as M, memo as Q, setStyleProperty as E, use as Z, delegateEvents as p } from "solid-js/web";
|
|
2
|
+
import { createUniqueId as ee, createSignal as V, createMemo as k, onMount as te, For as P, Show as ne, onCleanup as re } from "solid-js";
|
|
3
|
+
import { InfiniteCanvas as ae } from "../ui/InfiniteCanvas.js";
|
|
4
|
+
import { resolveSurfaceInteractionTargetRole as ie } from "../ui/localInteractionSurface.js";
|
|
5
|
+
import { graphRelatedEdges as B, graphSectionPath as oe } from "./geometry.js";
|
|
6
|
+
var le = /* @__PURE__ */ M("<div data-floe-canvas-pan-surface=true role=group tabindex=0>"), ce = /* @__PURE__ */ M("<div role=region tabindex=0>"), de = /* @__PURE__ */ M('<svg class=floe-graph__edges width=1 height=1><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>'), ue = /* @__PURE__ */ M("<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);
|
|
7
|
+
function me(i) {
|
|
8
|
+
const T = `graph-arrow-${ee()}`;
|
|
9
|
+
let u;
|
|
10
|
+
const [F, W] = V(null), [q, K] = V({
|
|
11
|
+
width: 0,
|
|
12
|
+
height: 0
|
|
13
|
+
}), A = () => i.highlight === void 0 ? F() : i.highlight, O = k(() => new Map(i.layout.nodes.map((e) => [e.id, e]))), U = k(() => {
|
|
14
|
+
const e = A();
|
|
15
|
+
return e?.kind === "node" ? B(i.layout, e.id) : new Set(e ? [e.id] : []);
|
|
16
|
+
}), R = k(() => {
|
|
17
|
+
const e = A();
|
|
18
|
+
if (e?.kind !== "node") return null;
|
|
19
|
+
const t = O().get(e.id), r = t?.kind === "group" ? t.id : t?.parentId;
|
|
20
|
+
return r ? B(i.layout, r) : null;
|
|
21
|
+
}), S = (e) => i.selected?.kind === e.kind && i.selected.id === e.id, J = (e) => {
|
|
22
|
+
const {
|
|
23
|
+
width: t,
|
|
24
|
+
height: r
|
|
25
|
+
} = q();
|
|
26
|
+
if (!t || !r) return i.layout.nodes;
|
|
27
|
+
const a = -e.x / e.scale - 240, n = -e.y / e.scale - 240, x = a + t / e.scale + 480, l = n + r / e.scale + 480;
|
|
28
|
+
return i.layout.nodes.filter((d) => d.id === i.selected?.id || d.x + d.width >= a && d.x <= x && d.y + d.height >= n && d.y <= l);
|
|
29
|
+
}, s = (e) => {
|
|
30
|
+
W(e), i.onHover?.(e);
|
|
31
|
+
}, m = (e, t, r) => {
|
|
32
|
+
const a = t.getBoundingClientRect();
|
|
33
|
+
return {
|
|
34
|
+
object: e,
|
|
35
|
+
owner: t,
|
|
36
|
+
position: r && (r.clientX !== 0 || r.clientY !== 0) ? {
|
|
37
|
+
x: r.clientX,
|
|
38
|
+
y: r.clientY
|
|
39
|
+
} : {
|
|
40
|
+
x: a.left + a.width / 2,
|
|
41
|
+
y: a.top + Math.min(32, a.height / 2)
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}, L = (e, t) => {
|
|
45
|
+
i.onContextMenu && (t.preventDefault(), t.stopPropagation(), i.onContextMenu(m(e, t.currentTarget, t)));
|
|
46
|
+
}, _ = (e, t) => {
|
|
47
|
+
t.target === t.currentTarget && (t.key === "ContextMenu" || t.shiftKey && t.key === "F10" ? (t.preventDefault(), t.stopPropagation(), i.onContextMenu?.(m(e, t.currentTarget))) : t.key === "Enter" ? (t.preventDefault(), t.stopPropagation(), i.onActivate?.(m(e, t.currentTarget))) : t.key === "Escape" && (s(null), i.onActivate?.(m(null, u))));
|
|
48
|
+
};
|
|
49
|
+
te(() => {
|
|
50
|
+
if (!u) return;
|
|
51
|
+
const e = () => K({
|
|
52
|
+
width: u.clientWidth,
|
|
53
|
+
height: u.clientHeight
|
|
54
|
+
});
|
|
55
|
+
e();
|
|
56
|
+
const t = new ResizeObserver(e);
|
|
57
|
+
t.observe(u), re(() => t.disconnect());
|
|
58
|
+
});
|
|
59
|
+
const j = (e) => {
|
|
60
|
+
const t = {
|
|
61
|
+
kind: "node",
|
|
62
|
+
id: e.id
|
|
63
|
+
}, r = {
|
|
64
|
+
selected: () => S(t),
|
|
65
|
+
openMenu: (a) => L(t, a)
|
|
66
|
+
};
|
|
67
|
+
return (() => {
|
|
68
|
+
var a = le();
|
|
69
|
+
return a.$$keydown = (n) => _(t, n), a.$$contextmenu = (n) => L(t, n), a.$$click = (n) => {
|
|
70
|
+
n.target.closest("button, a, input, select, textarea, [data-floe-canvas-interactive]") || (n.stopPropagation(), i.onActivate?.(m(t, n.currentTarget, n)));
|
|
71
|
+
}, a.$$focusout = () => s(null), a.$$focusin = () => s(t), a.addEventListener("pointerleave", () => s(null)), a.addEventListener("pointerenter", () => s(t)), w(a, (() => {
|
|
72
|
+
var n = Q(() => !!(e.kind === "group" && i.renderGroup));
|
|
73
|
+
return () => n() ? i.renderGroup(e, r) : i.renderNode(e, r);
|
|
74
|
+
})()), C((n) => {
|
|
75
|
+
var x = e.kind === "group" ? "floe-graph__group" : "floe-graph__node", l = e.id, d = S(t), $ = `${e.x}px`, h = `${e.y}px`, g = `${e.width}px`, b = `${e.height}px`, v = e.label;
|
|
76
|
+
return x !== n.e && N(a, n.e = x), l !== n.t && c(a, "data-graph-object", n.t = l), d !== n.a && c(a, "data-selected", n.a = d), $ !== n.o && E(a, "left", n.o = $), h !== n.i && E(a, "top", n.i = h), g !== n.n && E(a, "width", n.n = g), b !== n.s && E(a, "height", n.s = b), v !== n.h && c(a, "aria-label", n.h = v), n;
|
|
77
|
+
}, {
|
|
78
|
+
e: void 0,
|
|
79
|
+
t: void 0,
|
|
80
|
+
a: void 0,
|
|
81
|
+
o: void 0,
|
|
82
|
+
i: void 0,
|
|
83
|
+
n: void 0,
|
|
84
|
+
s: void 0,
|
|
85
|
+
h: void 0
|
|
86
|
+
}), a;
|
|
87
|
+
})();
|
|
88
|
+
};
|
|
89
|
+
return (() => {
|
|
90
|
+
var e = ce();
|
|
91
|
+
e.$$keydown = (r) => _(null, r);
|
|
92
|
+
var t = u;
|
|
93
|
+
return typeof t == "function" ? Z(t, e) : u = e, w(e, y(ae, {
|
|
94
|
+
get viewport() {
|
|
95
|
+
return i.viewport;
|
|
96
|
+
},
|
|
97
|
+
minScale: 0.1,
|
|
98
|
+
maxScale: 3,
|
|
99
|
+
get ariaLabel() {
|
|
100
|
+
return i.ariaLabel;
|
|
101
|
+
},
|
|
102
|
+
get onViewportChange() {
|
|
103
|
+
return i.onViewportChange;
|
|
104
|
+
},
|
|
105
|
+
onViewportInteractionStart: () => i.onInteractionStart?.(),
|
|
106
|
+
resolveTargetRole: (r) => (r.target instanceof Element ? r.target : null)?.closest('button, a, input, select, textarea, [data-floe-canvas-interactive="true"]') ? "local_surface" : ie(r),
|
|
107
|
+
onCanvasPointerDown: (r) => {
|
|
108
|
+
!(r.target instanceof Element) || r.target.closest("[data-graph-object]") || i.onActivate?.(m(null, u, r));
|
|
109
|
+
},
|
|
110
|
+
onCanvasContextMenu: (r) => i.onContextMenu?.({
|
|
111
|
+
object: null,
|
|
112
|
+
owner: u,
|
|
113
|
+
position: {
|
|
114
|
+
x: r.clientX,
|
|
115
|
+
y: r.clientY
|
|
116
|
+
}
|
|
117
|
+
}),
|
|
118
|
+
children: (r) => {
|
|
119
|
+
const a = k(() => J(r())), n = k(() => a().filter((l) => l.kind === "group")), x = k(() => a().filter((l) => l.kind !== "group"));
|
|
120
|
+
return [y(P, {
|
|
121
|
+
get each() {
|
|
122
|
+
return n();
|
|
123
|
+
},
|
|
124
|
+
children: j
|
|
125
|
+
}), (() => {
|
|
126
|
+
var l = de(), d = l.firstChild, $ = d.firstChild;
|
|
127
|
+
return c($, "id", T), w(l, y(P, {
|
|
128
|
+
get each() {
|
|
129
|
+
return i.layout.edges;
|
|
130
|
+
},
|
|
131
|
+
children: (h) => {
|
|
132
|
+
const g = {
|
|
133
|
+
kind: "edge",
|
|
134
|
+
id: h.id
|
|
135
|
+
}, b = () => h.sections.map(oe).join(" ");
|
|
136
|
+
return y(ne, {
|
|
137
|
+
get when() {
|
|
138
|
+
return !R() || R().has(h.id);
|
|
139
|
+
},
|
|
140
|
+
get children() {
|
|
141
|
+
var v = ue(), I = v.firstChild, f = I.nextSibling;
|
|
142
|
+
return c(I, "marker-end", `url(#${T})`), f.$$keydown = (o) => _(g, o), f.$$contextmenu = (o) => L(g, o), f.$$click = (o) => {
|
|
143
|
+
o.stopPropagation(), i.onActivate?.(m(g, o.currentTarget, o));
|
|
144
|
+
}, f.addEventListener("blur", () => s(null)), f.addEventListener("focus", () => s(g)), f.addEventListener("pointerleave", () => s(null)), f.addEventListener("pointerenter", () => s(g)), C((o) => {
|
|
145
|
+
var z = h.id, D = U().has(h.id), H = S(g), X = b(), Y = b(), G = h.label;
|
|
146
|
+
return z !== o.e && c(v, "data-graph-object", o.e = z), D !== o.t && c(v, "data-emphasized", o.t = D), H !== o.a && c(v, "data-selected", o.a = H), X !== o.o && c(I, "d", o.o = X), Y !== o.i && c(f, "d", o.i = Y), G !== o.n && c(f, "aria-label", o.n = G), o;
|
|
147
|
+
}, {
|
|
148
|
+
e: void 0,
|
|
149
|
+
t: void 0,
|
|
150
|
+
a: void 0,
|
|
151
|
+
o: void 0,
|
|
152
|
+
i: void 0,
|
|
153
|
+
n: void 0
|
|
154
|
+
}), v;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}), null), C(() => c(l, "aria-label", i.ariaLabel)), l;
|
|
159
|
+
})(), y(P, {
|
|
160
|
+
get each() {
|
|
161
|
+
return x();
|
|
162
|
+
},
|
|
163
|
+
children: j
|
|
164
|
+
})];
|
|
165
|
+
}
|
|
166
|
+
}), null), w(e, () => i.overlay, null), C((r) => {
|
|
167
|
+
var a = `floe-graph ${i.class ?? ""}`, n = i.ariaLabel;
|
|
168
|
+
return a !== r.e && N(e, r.e = a), n !== r.t && c(e, "aria-label", r.t = n), r;
|
|
169
|
+
}, {
|
|
170
|
+
e: void 0,
|
|
171
|
+
t: void 0
|
|
172
|
+
}), e;
|
|
173
|
+
})();
|
|
174
|
+
}
|
|
175
|
+
p(["focusin", "focusout", "click", "contextmenu", "keydown"]);
|
|
176
|
+
export {
|
|
177
|
+
me as GraphCanvas
|
|
178
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GraphInput, GraphLayout, GraphLayoutOptions } from './types';
|
|
2
|
+
export interface GraphLayoutEngine {
|
|
3
|
+
layout(input: GraphInput, options?: GraphLayoutOptions): Promise<GraphLayout>;
|
|
4
|
+
dispose(): void;
|
|
5
|
+
}
|
|
6
|
+
/** One worker per mounted graph. Dispose on unmount; failures are never hidden. */
|
|
7
|
+
export declare function createGraphLayoutEngine(): GraphLayoutEngine;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import m from "../../_virtual/elk-api.js";
|
|
2
|
+
import { computeGraphLayout as u } from "./layout.js";
|
|
3
|
+
function c() {
|
|
4
|
+
const r = new Worker(new URL(
|
|
5
|
+
/* @vite-ignore */
|
|
6
|
+
"" + new URL("../../assets/elk-worker-CrDP6jPz.js", import.meta.url).href,
|
|
7
|
+
import.meta.url
|
|
8
|
+
), { type: "module" }), p = new m({ workerFactory: () => r });
|
|
9
|
+
let o;
|
|
10
|
+
const t = /* @__PURE__ */ new Set(), n = (e) => {
|
|
11
|
+
o = e, r.terminate();
|
|
12
|
+
for (const a of t) a.reject(e);
|
|
13
|
+
t.clear();
|
|
14
|
+
};
|
|
15
|
+
return r.addEventListener(
|
|
16
|
+
"error",
|
|
17
|
+
(e) => n(new Error(e.message || "Graph layout worker failed"))
|
|
18
|
+
), r.addEventListener(
|
|
19
|
+
"messageerror",
|
|
20
|
+
() => n(new Error("Invalid graph layout worker response"))
|
|
21
|
+
), {
|
|
22
|
+
layout(e, a) {
|
|
23
|
+
return o ? Promise.reject(o) : new Promise((l, s) => {
|
|
24
|
+
const i = { reject: s };
|
|
25
|
+
t.add(i), u(e, a ?? {}, p).then(l, s).finally(() => t.delete(i));
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
dispose() {
|
|
29
|
+
n(new Error("Graph layout engine disposed"));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
c as createGraphLayoutEngine
|
|
35
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GraphBounds, GraphLayout, GraphPoint, GraphViewport } from './types';
|
|
2
|
+
export declare function graphSectionPath(points: readonly GraphPoint[]): string;
|
|
3
|
+
export declare function fitGraphViewport(bounds: GraphBounds, size: {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
}, padding?: number): GraphViewport;
|
|
7
|
+
/** Includes descendants so highlighting a group traces all of its direct routes. */
|
|
8
|
+
export declare function graphRelatedEdges(layout: GraphLayout, nodeId: string): ReadonlySet<string>;
|