@floegence/floe-webapp-core 0.86.16 → 0.86.19
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.
|
@@ -1153,7 +1153,7 @@ ${T}`;
|
|
|
1153
1153
|
w(`Module.instantiateWasm callback failed with error: ${f}`), u(f);
|
|
1154
1154
|
}
|
|
1155
1155
|
});
|
|
1156
|
-
Fe ??= o.locateFile ? o.locateFile ? o.locateFile("libavoid.wasm", N) : N + "libavoid.wasm" : new URL("" + new URL("../libavoid.wasm", import.meta.url).href, import.meta.url).href;
|
|
1156
|
+
Fe ??= o.locateFile ? o.locateFile ? o.locateFile("libavoid.wasm", N) : N + "libavoid.wasm" : new URL("" + new URL("../libavoid.wasm?no-inline", import.meta.url).href, import.meta.url).href;
|
|
1157
1157
|
try {
|
|
1158
1158
|
var a = await cr(n);
|
|
1159
1159
|
return t(a);
|
|
@@ -1186,7 +1186,7 @@ ${T}`;
|
|
|
1186
1186
|
} });
|
|
1187
1187
|
return C;
|
|
1188
1188
|
};
|
|
1189
|
-
})(), Zr = Xr, Xt = Kr(Zr), Qr = "" + new URL("../libavoid.wasm", import.meta.url).href;
|
|
1189
|
+
})(), Zr = Xr, Xt = Kr(Zr), Qr = "" + new URL("../libavoid.wasm?no-inline", import.meta.url).href;
|
|
1190
1190
|
let Zt;
|
|
1191
1191
|
const Qt = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, Ee = ["NORTH", "EAST", "SOUTH", "WEST"], de = (s) => s.delete();
|
|
1192
1192
|
async function pt(s, l = {}) {
|
|
@@ -1849,11 +1849,7 @@ function sn(s, l) {
|
|
|
1849
1849
|
}
|
|
1850
1850
|
const cn = new qr({
|
|
1851
1851
|
workerFactory: () => {
|
|
1852
|
-
const s = new Worker(new URL(
|
|
1853
|
-
/* @vite-ignore */
|
|
1854
|
-
"" + new URL("elk-worker-CrDP6jPz.js", import.meta.url).href,
|
|
1855
|
-
import.meta.url
|
|
1856
|
-
), { type: "module" });
|
|
1852
|
+
const s = new Worker(new URL("elk-worker-CrDP6jPz.js", import.meta.url), { type: "module" });
|
|
1857
1853
|
return s.addEventListener("error", (l) => {
|
|
1858
1854
|
throw new Error(l.message || "Graph ELK worker failed");
|
|
1859
1855
|
}), s.addEventListener("messageerror", () => {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
function w() {
|
|
2
|
-
const t = new Worker(new URL(
|
|
3
|
-
/* @vite-ignore */
|
|
4
|
-
"" + new URL("../../assets/layout-worker-BK6m515B.js", import.meta.url).href,
|
|
5
|
-
import.meta.url
|
|
6
|
-
), { type: "module" });
|
|
2
|
+
const t = new Worker(new URL("../../assets/layout-worker-BK6m515B.js", import.meta.url), { type: "module" });
|
|
7
3
|
let s, u = 0;
|
|
8
4
|
const o = /* @__PURE__ */ new Map(), n = (e) => {
|
|
9
5
|
s = e, t.terminate();
|
package/dist/remote-input.d.ts
CHANGED
|
@@ -23,8 +23,8 @@ export interface RemoteInputOptions<T> {
|
|
|
23
23
|
export interface RemoteInputController<T> {
|
|
24
24
|
readonly element: HTMLTextAreaElement;
|
|
25
25
|
bindTarget(target: T | null): void;
|
|
26
|
-
/** Physical
|
|
27
|
-
setTextInputMode(mode: 'physical' | 'text'): void;
|
|
26
|
+
/** Physical-only bypasses the local editor and input method entirely. */
|
|
27
|
+
setTextInputMode(mode: 'physical' | 'text' | 'physical-only'): void;
|
|
28
28
|
setAnchor(clientX: number, clientY: number): void;
|
|
29
29
|
focus(): void;
|
|
30
30
|
setKeyboardVisible(visible: boolean): void;
|
package/dist/remote-input.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
function
|
|
2
|
-
const { surface:
|
|
3
|
-
if (!
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
let
|
|
7
|
-
const
|
|
1
|
+
function O(a) {
|
|
2
|
+
const { surface: c } = a, k = c.ownerDocument, u = k.defaultView;
|
|
3
|
+
if (!u) throw new Error("Remote input requires an attached document");
|
|
4
|
+
const l = k.createElement("textarea");
|
|
5
|
+
l.className = "floe-remote-input", l.setAttribute("aria-label", a.label), l.setAttribute("autocorrect", "off"), l.autocomplete = "off", l.autocapitalize = "off", l.spellcheck = !1, l.wrap = "off", l.disabled = !0, l.tabIndex = -1, k.body.append(l);
|
|
6
|
+
let i = null, M = 0, d = !1, V = !1, o = null, K = !1, f = null, r = "physical", D = !1;
|
|
7
|
+
const x = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Set(), T = /* @__PURE__ */ new Set(), S = /* @__PURE__ */ new Set();
|
|
8
8
|
let $ = null;
|
|
9
|
-
const
|
|
10
|
-
function s(e, t,
|
|
11
|
-
const
|
|
12
|
-
e.addEventListener(t,
|
|
9
|
+
const I = [];
|
|
10
|
+
function s(e, t, n) {
|
|
11
|
+
const m = n;
|
|
12
|
+
e.addEventListener(t, m), I.push(() => e.removeEventListener(t, m));
|
|
13
13
|
}
|
|
14
|
-
const
|
|
14
|
+
const w = (e) => e.code || e.key, C = (e, t) => ({
|
|
15
15
|
key: e.key,
|
|
16
16
|
code: e.code,
|
|
17
17
|
pressed: t,
|
|
@@ -22,147 +22,165 @@ function j(n) {
|
|
|
22
22
|
altKey: e.altKey,
|
|
23
23
|
metaKey: e.metaKey
|
|
24
24
|
});
|
|
25
|
-
function
|
|
26
|
-
|
|
25
|
+
function L(e) {
|
|
26
|
+
V !== e && (V = e, a.onKeyboardVisibilityChange?.(e));
|
|
27
27
|
}
|
|
28
|
-
function
|
|
29
|
-
const e =
|
|
30
|
-
|
|
31
|
-
const B =
|
|
32
|
-
|
|
28
|
+
function h() {
|
|
29
|
+
const e = c.getBoundingClientRect(), t = u.visualViewport, n = Math.max(e.left, t?.offsetLeft ?? 0), m = Math.max(e.top, t?.offsetTop ?? 0), g = Math.min(e.right, (t?.offsetLeft ?? 0) + (t?.width ?? u.innerWidth)), j = Math.min(e.bottom, (t?.offsetTop ?? 0) + (t?.height ?? u.innerHeight)), q = Math.max(1, Math.min(320, g - n - 8));
|
|
30
|
+
l.style.maxWidth = `${q}px`;
|
|
31
|
+
const B = l.getBoundingClientRect(), G = $?.x ?? n + 12, H = $?.y ?? m + 12;
|
|
32
|
+
l.style.left = `${Math.max(n, Math.min(G, g - B.width - 4))}px`, l.style.top = `${Math.max(m, Math.min(H, j - B.height - 4))}px`;
|
|
33
33
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
34
|
+
function p() {
|
|
35
|
+
l.value = "", delete l.dataset.composing, f = null;
|
|
36
36
|
}
|
|
37
|
-
function
|
|
38
|
-
const e =
|
|
39
|
-
|
|
37
|
+
function z() {
|
|
38
|
+
const e = i, t = y.size > 0;
|
|
39
|
+
y.clear(), x.clear(), T.clear(), e !== null && t && a.release(e);
|
|
40
40
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
41
|
+
function b() {
|
|
42
|
+
M++, o && (o.cancelled = !0), K = !0, p(), z(), o && k.activeElement === l && l.blur();
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
!e ||
|
|
44
|
+
function A(e) {
|
|
45
|
+
!e || i === null || d || r === "physical-only" || (r === "text" && y.size && (y.clear(), T.clear(), a.release(i)), a.commitText(e, i));
|
|
46
46
|
}
|
|
47
|
-
function
|
|
48
|
-
if (
|
|
47
|
+
function E(e) {
|
|
48
|
+
if (i !== null) {
|
|
49
49
|
if (!/^(Shift|Control|Alt|Meta)(Left|Right)$/.test(e.code))
|
|
50
|
-
for (const [t,
|
|
50
|
+
for (const [t, n] of [
|
|
51
51
|
["Shift", e.shiftKey],
|
|
52
52
|
["Control", e.ctrlKey],
|
|
53
53
|
["Alt", e.altKey],
|
|
54
54
|
["Meta", e.metaKey]
|
|
55
55
|
]) {
|
|
56
|
-
if (!
|
|
57
|
-
const
|
|
58
|
-
|
|
56
|
+
if (!n || [...y].some((g) => g === `${t}Left` || g === `${t}Right`)) continue;
|
|
57
|
+
const m = [...x.values()].find((g) => g.code === `${t}Left` || g.code === `${t}Right`) ?? { ...e, key: t, code: `${t}Left`, pressed: !0, repeat: !1, location: 1 };
|
|
58
|
+
y.add(m.code), x.has(m.code) || T.add(m.code), a.sendKey(m, i);
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
y.add(e.code || e.key), a.sendKey(e, i);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
function D(e) {
|
|
64
|
-
if (l === null) return;
|
|
65
|
-
const t = { key: e, code: e, pressed: !0, repeat: !1, shiftKey: !1, ctrlKey: !1, altKey: !1, metaKey: !1, location: 0 }, r = l;
|
|
66
|
-
n.sendKey(t, r), l === r && n.sendKey({ ...t, pressed: !1 }, r);
|
|
67
|
-
}
|
|
68
63
|
function F(e) {
|
|
69
|
-
if (
|
|
70
|
-
|
|
64
|
+
if (i === null) return;
|
|
65
|
+
const t = { key: e, code: e, pressed: !0, repeat: !1, shiftKey: !1, ctrlKey: !1, altKey: !1, metaKey: !1, location: 0 }, n = i;
|
|
66
|
+
a.sendKey(t, n), i === n && a.sendKey({ ...t, pressed: !1 }, n);
|
|
67
|
+
}
|
|
68
|
+
function P(e) {
|
|
69
|
+
if (i === null || d || r === "physical-only") {
|
|
70
|
+
p();
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
|
-
if (o?.cancelled || o && o.epoch !==
|
|
74
|
-
|
|
73
|
+
if (o?.cancelled || o && o.epoch !== M) {
|
|
74
|
+
p();
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
if (e.isComposing) {
|
|
78
|
-
o ??= { epoch:
|
|
78
|
+
o ??= { epoch: M, committed: !1, cancelled: !1 }, l.dataset.composing = "true", h();
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
if (o) {
|
|
82
|
-
!o.committed &&
|
|
82
|
+
!o.committed && l.value && (o.committed = !0, A(l.value)), p();
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
85
|
+
if (K || e.inputType === "insertFromComposition") {
|
|
86
|
+
K = !1, p();
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
|
-
const t =
|
|
90
|
-
|
|
89
|
+
const t = l.value;
|
|
90
|
+
r === "physical" && f && t === f.key && !f.altKey && t.length === 1 ? E(f) : A(t), p();
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
if (!(
|
|
94
|
-
if (e.stopPropagation(),
|
|
95
|
-
|
|
92
|
+
function N(e) {
|
|
93
|
+
if (!(i === null || d) && e.currentTarget === c == (r === "physical-only")) {
|
|
94
|
+
if (e.stopPropagation(), r === "physical-only") {
|
|
95
|
+
e.preventDefault(), S.delete(w(e)), e.code && !a.clipboard?.(e, i) && E(C(e, !0));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (o?.cancelled && !e.isComposing && e.key !== "Process" && e.keyCode !== 229 && (o = null), e.isComposing || o || e.key === "Process" || e.keyCode === 229) {
|
|
99
|
+
S.add(w(e)), f = null;
|
|
96
100
|
return;
|
|
97
101
|
}
|
|
98
|
-
if (
|
|
99
|
-
|
|
102
|
+
if (S.delete(w(e)), K = !1, a.clipboard?.(e, i)) {
|
|
103
|
+
f = null;
|
|
100
104
|
return;
|
|
101
105
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
106
|
+
if (r === "text" && /^(Shift|Control|Alt|Meta)(Left|Right)$/.test(e.code)) {
|
|
107
|
+
x.set(w(e), C(e, !0));
|
|
104
108
|
return;
|
|
105
109
|
}
|
|
106
110
|
if (e.key === "Dead" || e.key === "Unidentified") {
|
|
107
|
-
|
|
111
|
+
f = null;
|
|
108
112
|
return;
|
|
109
113
|
}
|
|
110
114
|
if (Array.from(e.key).length === 1 && !e.metaKey && (!e.ctrlKey || e.getModifierState("AltGraph"))) {
|
|
111
|
-
|
|
115
|
+
f = C(e, !0);
|
|
112
116
|
return;
|
|
113
117
|
}
|
|
114
|
-
e.preventDefault(),
|
|
118
|
+
e.preventDefault(), E(C(e, !0));
|
|
115
119
|
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
}
|
|
121
|
+
function W(e) {
|
|
122
|
+
if (e.currentTarget === c == (r === "physical-only") && (e.stopPropagation(), f = null, x.delete(w(e)), !S.delete(w(e)) && (i !== null && y.delete(w(e)) && a.sendKey(C(e, !1), i), i !== null && ![...y].some((t) => !/^(Shift|Control|Alt|Meta)(Left|Right)$/.test(t))))) {
|
|
123
|
+
for (const t of T)
|
|
124
|
+
y.delete(t), a.sendKey({ ...C(e, !1), code: t, key: t.replace(/Left$/, ""), location: 1 }, i);
|
|
125
|
+
T.clear();
|
|
121
126
|
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
}
|
|
128
|
+
for (const e of [l, c])
|
|
129
|
+
s(e, "keydown", N), s(e, "keyup", W);
|
|
130
|
+
s(l, "beforeinput", (e) => {
|
|
131
|
+
if (i === null || d || r === "physical-only") {
|
|
132
|
+
e.preventDefault(), p();
|
|
125
133
|
return;
|
|
126
134
|
}
|
|
127
135
|
if (e.isComposing || o || e.inputType === "insertCompositionText" || e.inputType === "deleteCompositionText" || e.inputType === "insertFromComposition") return;
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
}), s(
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
K = !1;
|
|
137
|
+
const n = { deleteContentBackward: "Backspace", deleteContentForward: "Delete", insertLineBreak: "Enter", insertParagraph: "Enter" }[e.inputType];
|
|
138
|
+
n && (e.preventDefault(), p(), F(n));
|
|
139
|
+
}), s(l, "input", P), s(l, "compositionstart", () => {
|
|
140
|
+
if (r === "physical-only") {
|
|
141
|
+
p();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
o = { epoch: M, committed: !1, cancelled: i === null }, K = !1, f = null, l.dataset.composing = "true", h();
|
|
145
|
+
}), s(l, "compositionend", (e) => {
|
|
134
146
|
const t = o;
|
|
135
|
-
o = null,
|
|
136
|
-
}), s(
|
|
137
|
-
|
|
138
|
-
}), s(c, "blur",
|
|
139
|
-
|
|
147
|
+
o = null, K = !0, p(), t && !t.cancelled && !t.committed && t.epoch === M && A(e.data);
|
|
148
|
+
}), s(l, "blur", () => {
|
|
149
|
+
b(), L(!1);
|
|
150
|
+
}), s(c, "blur", () => {
|
|
151
|
+
r === "physical-only" && b();
|
|
152
|
+
}), s(u, "blur", b), s(u, "pagehide", b), s(u, "resize", h), u.visualViewport && (s(u.visualViewport, "resize", h), s(u.visualViewport, "scroll", h));
|
|
153
|
+
function R() {
|
|
154
|
+
i === null || d || (r === "physical-only" ? (c.hasAttribute("tabindex") || (c.tabIndex = -1, D = !0), c.focus({ preventScroll: !0 })) : (l.focus({ preventScroll: !0 }), h()));
|
|
155
|
+
}
|
|
156
|
+
return h(), {
|
|
157
|
+
element: l,
|
|
140
158
|
bindTarget(e) {
|
|
141
|
-
|
|
159
|
+
d || Object.is(i, e) || (b(), i = e, l.disabled = e === null || r === "physical-only");
|
|
142
160
|
},
|
|
143
161
|
setTextInputMode(e) {
|
|
144
|
-
|
|
162
|
+
if (d || e === r) return;
|
|
163
|
+
const t = k.activeElement === l || k.activeElement === c;
|
|
164
|
+
b(), r = e, l.disabled = i === null || e === "physical-only", e === "physical-only" && L(!1), t && R();
|
|
145
165
|
},
|
|
146
166
|
setAnchor(e, t) {
|
|
147
|
-
!Number.isFinite(e) || !Number.isFinite(t) || ($ = { x: e, y: t },
|
|
148
|
-
},
|
|
149
|
-
focus() {
|
|
150
|
-
l === null || f || (i.focus({ preventScroll: !0 }), p());
|
|
167
|
+
!Number.isFinite(e) || !Number.isFinite(t) || ($ = { x: e, y: t }, h());
|
|
151
168
|
},
|
|
169
|
+
focus: R,
|
|
152
170
|
setKeyboardVisible(e) {
|
|
153
|
-
e &&
|
|
171
|
+
e && i !== null && !d ? (R(), L(r !== "physical-only")) : ((r === "physical-only" ? c : l).blur(), L(!1));
|
|
154
172
|
},
|
|
155
|
-
release:
|
|
156
|
-
reset:
|
|
173
|
+
release: z,
|
|
174
|
+
reset: b,
|
|
157
175
|
dispose() {
|
|
158
|
-
if (!
|
|
159
|
-
|
|
160
|
-
for (const e of
|
|
161
|
-
|
|
176
|
+
if (!d) {
|
|
177
|
+
b(), d = !0, i = null;
|
|
178
|
+
for (const e of I) e();
|
|
179
|
+
D && c.removeAttribute("tabindex"), l.remove(), L(!1);
|
|
162
180
|
}
|
|
163
181
|
}
|
|
164
182
|
};
|
|
165
183
|
}
|
|
166
184
|
export {
|
|
167
|
-
|
|
185
|
+
O as createRemoteInput
|
|
168
186
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floegence/floe-webapp-core",
|
|
3
|
-
"version": "0.86.
|
|
3
|
+
"version": "0.86.19",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -139,17 +139,23 @@
|
|
|
139
139
|
"types": "./dist/graph.d.ts",
|
|
140
140
|
"import": "./dist/graph.js"
|
|
141
141
|
},
|
|
142
|
-
"./graph.css": "./dist/graph.css"
|
|
142
|
+
"./graph.css": "./dist/graph.css",
|
|
143
|
+
"./graph-assets": {
|
|
144
|
+
"types": "./scripts/graph-assets.d.mts",
|
|
145
|
+
"import": "./scripts/graph-assets.mjs"
|
|
146
|
+
}
|
|
143
147
|
},
|
|
144
148
|
"files": [
|
|
145
149
|
"dist",
|
|
146
150
|
"scripts/pdf-assets.mjs",
|
|
147
|
-
"scripts/pdf-assets.d.mts"
|
|
151
|
+
"scripts/pdf-assets.d.mts",
|
|
152
|
+
"scripts/graph-assets.mjs",
|
|
153
|
+
"scripts/graph-assets.d.mts"
|
|
148
154
|
],
|
|
149
155
|
"scripts": {
|
|
150
156
|
"dev": "node ./scripts/dev.mjs",
|
|
151
157
|
"build": "pnpm clean && pnpm build:shell-theme-css && vite build && tsc -p tsconfig.build.json && pnpm build:styles && pnpm build:assets",
|
|
152
|
-
"build:assets": "node ./scripts/copy-style-assets.mjs && node ./scripts/build-pdf-styles.mjs",
|
|
158
|
+
"build:assets": "node ./scripts/normalize-graph-worker-urls.mjs && node ./scripts/copy-style-assets.mjs && node ./scripts/build-pdf-styles.mjs",
|
|
153
159
|
"build:shell-theme-css": "node ./scripts/generate-shell-theme-css.mjs",
|
|
154
160
|
"build:styles": "vite build -c vite.styles.config.ts",
|
|
155
161
|
"typecheck": "tsc --noEmit",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Vite build plugin for offline file-origin hosts. Requires local file read
|
|
2
|
+
* access and CSP blob: permissions for scripts, workers, and connections. */
|
|
3
|
+
export declare function graphBlobWorkersPlugin(): {
|
|
4
|
+
name: string;
|
|
5
|
+
apply: 'build';
|
|
6
|
+
transform(this: { emitFile(asset: {type: 'asset'; fileName: string; source: Uint8Array}): string }, code: string, id: string): string | undefined;
|
|
7
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { URL } from 'node:url';
|
|
3
|
+
|
|
4
|
+
/** Vite build adapter for offline file-origin hosts. Layout and ELK remain
|
|
5
|
+
* unchanged published modules; the raw LGPL WASM stays independently replaceable.
|
|
6
|
+
* The host must grant local read access and allow blob workers/scripts/connects.
|
|
7
|
+
*/
|
|
8
|
+
export function graphBlobWorkersPlugin() {
|
|
9
|
+
const root = new URL('../dist/', import.meta.url);
|
|
10
|
+
const engine = readFileSync(new URL('components/graph/engine.js', root), 'utf8');
|
|
11
|
+
const entry = /new URL\("(\.\.\/\.\.\/assets\/[^"\n]+)", import\.meta\.url\)/.exec(engine)?.[1];
|
|
12
|
+
if (!entry) throw new Error('Unsupported graph layout worker entry');
|
|
13
|
+
const layoutURL = new URL(entry, new URL('components/graph/', root));
|
|
14
|
+
let layout = readFileSync(layoutURL, 'utf8');
|
|
15
|
+
const child = /new URL\("([^"\n]*elk-worker[^"\n]+)", import\.meta\.url\)/.exec(layout)?.[1];
|
|
16
|
+
if (!child) throw new Error('Unsupported graph ELK worker entry');
|
|
17
|
+
const elk = readFileSync(new URL(child, layoutURL), 'utf8');
|
|
18
|
+
// Every package-owned resource URL is substituted by a local blob URL.
|
|
19
|
+
layout = layout.replaceAll(`new URL("${child}", import.meta.url)`, 'new URL(__floeElkURL)');
|
|
20
|
+
layout = layout.replaceAll(/new URL\("[^"\n]*libavoid\.wasm(?:\?no-inline)?", import\.meta\.url\)/g, 'new URL(__floeWasmURL)');
|
|
21
|
+
const bootstrap = `
|
|
22
|
+
const queue = [];
|
|
23
|
+
self.onmessage = async ({data}) => {
|
|
24
|
+
if (!data.__floeGraphWasm) { queue.push(data); return; }
|
|
25
|
+
const __floeWasmURL = URL.createObjectURL(new Blob([data.__floeGraphWasm], {type:'application/wasm'}));
|
|
26
|
+
const __floeElkURL = URL.createObjectURL(new Blob([${JSON.stringify(elk)}], {type:'text/javascript'}));
|
|
27
|
+
const source = 'const __floeElkURL=' + JSON.stringify(__floeElkURL) + ',__floeWasmURL=' + JSON.stringify(__floeWasmURL) + ';\\n' + ${JSON.stringify(layout)};
|
|
28
|
+
try { await import(URL.createObjectURL(new Blob([source], {type:'text/javascript'}))); }
|
|
29
|
+
catch (error) { setTimeout(() => { throw error; }); return; }
|
|
30
|
+
for (const data of queue) self.onmessage({data});
|
|
31
|
+
queue.length = 0;
|
|
32
|
+
};
|
|
33
|
+
`;
|
|
34
|
+
return {
|
|
35
|
+
name: 'floe-graph-blob-workers',
|
|
36
|
+
apply: 'build',
|
|
37
|
+
transform(code, id) {
|
|
38
|
+
if (!id.endsWith('/components/graph/engine.js')) return;
|
|
39
|
+
const expression = /new Worker\(new URL\([\s\S]*?\), \{ type: "module" \}\)/;
|
|
40
|
+
if (!expression.test(code)) throw new Error('Unsupported graph layout worker factory');
|
|
41
|
+
const asset = this.emitFile({ type: 'asset', fileName: 'assets/libavoid.wasm', source: readFileSync(new URL('libavoid.wasm', root)) });
|
|
42
|
+
const factory = `(() => {
|
|
43
|
+
const url = URL.createObjectURL(new Blob([${JSON.stringify(bootstrap)}], {type:'text/javascript'}));
|
|
44
|
+
const worker = new Worker(url, {type:'module'});
|
|
45
|
+
URL.revokeObjectURL(url);
|
|
46
|
+
const request = new XMLHttpRequest();
|
|
47
|
+
request.open('GET', import.meta.ROLLUP_FILE_URL_${asset});
|
|
48
|
+
request.responseType = 'arraybuffer';
|
|
49
|
+
const fail = () => worker.dispatchEvent(new ErrorEvent('error', {message:'Unable to read graph routing WASM'}));
|
|
50
|
+
request.onload = () => {
|
|
51
|
+
if ((request.status === 0 || request.status === 200) && request.response?.byteLength) {
|
|
52
|
+
worker.postMessage({__floeGraphWasm:request.response}, [request.response]);
|
|
53
|
+
} else fail();
|
|
54
|
+
};
|
|
55
|
+
request.onerror = fail;
|
|
56
|
+
request.send();
|
|
57
|
+
const terminate = worker.terminate.bind(worker);
|
|
58
|
+
worker.terminate = () => { request.abort(); terminate(); };
|
|
59
|
+
return worker;
|
|
60
|
+
})()`;
|
|
61
|
+
return code.replace(expression, () => factory);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|