@draftably/runtime 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -2
- package/dist/LICENSE +21 -0
- package/dist/THIRD_PARTY_NOTICES +286 -0
- package/dist/assets/render.worker-BpUp6NY_.js +7618 -0
- package/dist/element.js +122 -0
- package/dist/font-data-DbrpaYkG.js +30 -0
- package/dist/fonts/inter-latin-500-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-600-normal.woff2 +0 -0
- package/dist/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/dist/fonts/source-serif-4-latin-600-normal.woff2 +0 -0
- package/dist/fonts.css +4 -0
- package/dist/index.js +9 -0
- package/dist/render-BOAZBzVa.js +7633 -0
- package/dist/types/src/dsl/cells.d.ts +91 -0
- package/dist/types/src/dsl/channels.d.ts +53 -0
- package/dist/types/src/dsl/compile.d.ts +162 -0
- package/dist/types/src/dsl/frame.d.ts +38 -0
- package/dist/types/src/dsl/lanes.d.ts +23 -0
- package/dist/types/src/dsl/legend-notes.d.ts +3 -0
- package/dist/types/src/dsl/project.d.ts +39 -0
- package/dist/types/src/dsl/syntax.d.ts +317 -0
- package/dist/types/src/engines/explorer-engine.d.ts +67 -0
- package/dist/types/src/engines/layout-engine.d.ts +120 -0
- package/dist/types/src/engines/routing-engine.d.ts +108 -0
- package/dist/types/src/engines/sculpt-engine.d.ts +71 -0
- package/dist/types/src/lib/font-data.d.ts +9 -0
- package/dist/types/src/model/appearance.d.ts +209 -0
- package/dist/types/src/model/bounds.d.ts +19 -0
- package/dist/types/src/model/colors.d.ts +22 -0
- package/dist/types/src/model/document.d.ts +24 -0
- package/dist/types/src/model/font-faces.d.ts +24 -0
- package/dist/types/src/model/fonts.d.ts +47 -0
- package/dist/types/src/model/footnote.d.ts +34 -0
- package/dist/types/src/model/frame.d.ts +71 -0
- package/dist/types/src/model/geometry.d.ts +29 -0
- package/dist/types/src/model/graph.d.ts +53 -0
- package/dist/types/src/model/heading.d.ts +38 -0
- package/dist/types/src/model/icons.d.ts +2 -0
- package/dist/types/src/model/labels.d.ts +88 -0
- package/dist/types/src/model/legend.d.ts +25 -0
- package/dist/types/src/model/link.d.ts +63 -0
- package/dist/types/src/model/markers.d.ts +47 -0
- package/dist/types/src/model/note.d.ts +75 -0
- package/dist/types/src/model/panels.d.ts +11 -0
- package/dist/types/src/model/rich-text.d.ts +24 -0
- package/dist/types/src/model/routes.d.ts +170 -0
- package/dist/types/src/model/stack.d.ts +8 -0
- package/dist/types/src/model/status.d.ts +84 -0
- package/dist/types/src/model/styles.d.ts +13 -0
- package/dist/types/src/model/surface.d.ts +31 -0
- package/dist/types/src/model/types.d.ts +277 -0
- package/dist/types/src/runtime/element.d.ts +12 -0
- package/dist/types/src/runtime/index.d.ts +5 -0
- package/dist/types/src/runtime/policy.d.ts +7 -0
- package/dist/types/src/runtime/render.d.ts +10 -0
- package/dist/types/src/runtime/svg-renderer.d.ts +38 -0
- package/dist/types/src/runtime/types.d.ts +109 -0
- package/dist/types/src/runtime/version.d.ts +2 -0
- package/dist/types/src/runtime/viewer.d.ts +84 -0
- package/dist/viewer.css +90 -0
- package/dist/viewer.js +438 -0
- package/package.json +50 -4
package/dist/viewer.js
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { r as ce, F as ee } from "./render-BOAZBzVa.js";
|
|
2
|
+
import { f as Ee, a as ke } from "./render-BOAZBzVa.js";
|
|
3
|
+
const de = "http://www.w3.org/2000/svg", le = new Set(
|
|
4
|
+
"svg title desc metadata defs style marker g a path rect ellipse circle line polyline polygon text tspan".split(
|
|
5
|
+
" "
|
|
6
|
+
)
|
|
7
|
+
), fe = new Set(
|
|
8
|
+
"aria-labelledby role id data-id data-phase data-state data-theme xmlns viewBox width height x y x1 y1 x2 y2 cx cy r rx ry d points transform fill fill-rule fill-opacity stroke stroke-opacity stroke-width stroke-linecap stroke-linejoin stroke-dasharray opacity font-family font-size font-weight text-anchor dominant-baseline dy text-decoration marker-start marker-end markerWidth markerHeight markerUnits refX refY orient class clip-path nonce href target rel".split(
|
|
9
|
+
" "
|
|
10
|
+
)
|
|
11
|
+
);
|
|
12
|
+
let me = 0;
|
|
13
|
+
function ue(y, c) {
|
|
14
|
+
const V = new y.defaultView.DOMParser().parseFromString(c, "image/svg+xml"), s = /* @__PURE__ */ new Map();
|
|
15
|
+
for (const v of Array.from(V.querySelectorAll("text[font-family]"))) {
|
|
16
|
+
const m = (v.getAttribute("font-family") ?? "").split(",")[0].trim().replace(/^['"]|['"]$/g, ""), b = v.getAttribute("font-weight") ?? "400";
|
|
17
|
+
if (!Object.values(ee).some((o) => o.family === m && String(o.weight) === b))
|
|
18
|
+
throw new Error("Runtime SVG requested an unknown bundled font face.");
|
|
19
|
+
s.set(`${m}:${b}`, { family: m, weight: b });
|
|
20
|
+
}
|
|
21
|
+
return [...s.values()];
|
|
22
|
+
}
|
|
23
|
+
function we(y, c, V) {
|
|
24
|
+
const s = new y.defaultView.DOMParser().parseFromString(c, "image/svg+xml"), v = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const m of Array.from(s.querySelectorAll("style"))) {
|
|
26
|
+
const b = m.textContent ?? "";
|
|
27
|
+
for (const [, o] of b.matchAll(/@font-face\s*\{([^{}]{1,200000})\}/g)) {
|
|
28
|
+
const l = /font-family\s*:\s*['"]([^'"]+)['"]/i.exec(o)?.[1], w = /font-weight\s*:\s*(\d{1,4})/i.exec(o)?.[1], p = /src\s*:\s*url\((data:font\/woff2;base64,[A-Za-z0-9+/=]+)\)/i.exec(o)?.[1];
|
|
29
|
+
!l || !w || !p || Object.values(ee).some((f) => f.family === l && String(f.weight) === w) && v.set(`${l}:${w}`, { family: l, weight: w, data: p });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return V.map((m) => {
|
|
33
|
+
const b = v.get(`${m.family}:${m.weight}`);
|
|
34
|
+
if (!b) throw new Error(`Embedded font ${m.family} ${m.weight} is missing.`);
|
|
35
|
+
return b;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function ge(y, c, V, s = 1e5) {
|
|
39
|
+
const v = new y.defaultView.DOMParser().parseFromString(c, "image/svg+xml");
|
|
40
|
+
if (v.querySelector("parsererror") || v.documentElement.localName !== "svg")
|
|
41
|
+
throw new Error("Runtime returned invalid SVG.");
|
|
42
|
+
const m = new Set(
|
|
43
|
+
Array.from(v.querySelectorAll("[id]"), (l) => l.getAttribute("id") ?? "")
|
|
44
|
+
);
|
|
45
|
+
let b = 0;
|
|
46
|
+
const o = (l) => {
|
|
47
|
+
if (++b > s || !le.has(l.localName))
|
|
48
|
+
throw new Error("Runtime SVG exceeded the allowed drawing vocabulary.");
|
|
49
|
+
const w = y.createElementNS(de, l.localName);
|
|
50
|
+
for (const { name: p, value: f } of Array.from(l.attributes)) {
|
|
51
|
+
if (/^on/i.test(p)) continue;
|
|
52
|
+
if (p === "href") {
|
|
53
|
+
if (l.localName !== "a") continue;
|
|
54
|
+
try {
|
|
55
|
+
const a = new URL(f, y.baseURI);
|
|
56
|
+
(a.protocol === "http:" || a.protocol === "https:") && w.setAttribute("href", a.href);
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!fe.has(p) && !/^data-[a-z0-9-]+$/.test(p)) continue;
|
|
62
|
+
const x = [...f.matchAll(/url\(#([^)]*)\)/g)].map((a) => a[1]);
|
|
63
|
+
/url\s*\(/i.test(f) && (x.length === 0 || x.some((a) => !m.has(a))) || p === "aria-labelledby" && f.split(/\s+/).some((a) => !m.has(a)) || w.setAttribute(p, f);
|
|
64
|
+
}
|
|
65
|
+
l.localName === "a" && w.getAttribute("target") === "_blank" && w.setAttribute("rel", "noopener noreferrer");
|
|
66
|
+
for (const p of Array.from(l.childNodes))
|
|
67
|
+
if (p.nodeType === 1) w.append(o(p));
|
|
68
|
+
else if (p.nodeType === 3) {
|
|
69
|
+
const f = p.nodeValue ?? "";
|
|
70
|
+
w.append(
|
|
71
|
+
y.createTextNode(
|
|
72
|
+
l.localName === "style" && V ? f.replace(/@font-face\s*\{[^{}]*\}/g, "") : f
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return w;
|
|
77
|
+
};
|
|
78
|
+
return o(v.documentElement);
|
|
79
|
+
}
|
|
80
|
+
function K(y, c, V) {
|
|
81
|
+
return {
|
|
82
|
+
ok: !1,
|
|
83
|
+
reason: y,
|
|
84
|
+
diagnostics: [{ code: c, severity: "error", message: V, itemIds: [] }]
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function ve(y, c = {}) {
|
|
88
|
+
const V = y?.ownerDocument?.defaultView;
|
|
89
|
+
if (!V || !(y instanceof V.HTMLElement))
|
|
90
|
+
throw new TypeError("host must be an HTMLElement.");
|
|
91
|
+
if (y.childNodes.length) throw new Error("Viewer host must be empty and exclusively owned.");
|
|
92
|
+
if ((c.execution ?? { mode: "worker" }).mode === "worker" && c.render?.links?.mode === "safe" && c.render.links.resolve)
|
|
93
|
+
throw new TypeError('A link resolver requires execution: { mode: "main" }.');
|
|
94
|
+
const s = y.ownerDocument, v = V, m = s.createElement("section");
|
|
95
|
+
m.className = "draft-viewer", m.setAttribute("aria-label", c.label ?? "Diagram viewer");
|
|
96
|
+
const b = s.createElement("div");
|
|
97
|
+
b.className = "draft-viewer__toolbar", b.setAttribute("role", "toolbar"), b.setAttribute("aria-label", "Diagram controls");
|
|
98
|
+
const o = s.createElement("div");
|
|
99
|
+
o.className = "draft-viewer__viewport", o.tabIndex = 0, o.setAttribute("aria-label", c.label ?? "Diagram");
|
|
100
|
+
const l = s.createElement("p");
|
|
101
|
+
l.className = "draft-viewer__status", l.setAttribute("role", "status"), l.setAttribute("aria-live", "polite");
|
|
102
|
+
const w = s.createElement("ol");
|
|
103
|
+
w.className = "draft-viewer__outline", w.setAttribute("aria-label", "Diagram outline"), m.append(b, o, l, w), y.append(m);
|
|
104
|
+
const p = `draftViewer${(++me).toString(36)}${Math.random().toString(36).slice(2, 9)}`;
|
|
105
|
+
let f = 0, x = !1, a = { centerX: 0, centerY: 0, zoom: 1 }, T = !1, u, F, B, te = 0;
|
|
106
|
+
const M = /* @__PURE__ */ new Map(), G = /* @__PURE__ */ new Map(), q = /* @__PURE__ */ new Map(), L = (e, r) => {
|
|
107
|
+
for (const t of G.get(e) ?? [])
|
|
108
|
+
try {
|
|
109
|
+
t(r);
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
}, j = (e, r) => {
|
|
113
|
+
const t = s.createElement("button");
|
|
114
|
+
t.type = "button", t.textContent = e, t.setAttribute("aria-label", e), t.addEventListener("click", r), b.append(t);
|
|
115
|
+
}, re = () => {
|
|
116
|
+
if (!u) return 1;
|
|
117
|
+
const e = o.getBoundingClientRect(), [, , r, t] = u.viewBox;
|
|
118
|
+
return Math.min(e.width / r, e.height / t);
|
|
119
|
+
}, R = () => {
|
|
120
|
+
const e = o.querySelector("svg");
|
|
121
|
+
if (!e || !u) return;
|
|
122
|
+
const [r, t] = u.viewBox, S = o.getBoundingClientRect(), g = a.zoom, n = S.width / 2 - (a.centerX - r) * g, h = S.height / 2 - (a.centerY - t) * g;
|
|
123
|
+
e.style.transformOrigin = "0 0", e.style.transform = `translate(${n}px, ${h}px) scale(${g})`, e.style.width = `${u.width}px`, e.style.height = `${u.height}px`, e.style.maxWidth = "none";
|
|
124
|
+
}, Y = (e = "fit") => {
|
|
125
|
+
if (!u) return;
|
|
126
|
+
const r = o.getBoundingClientRect();
|
|
127
|
+
if (!r.width || !r.height) return;
|
|
128
|
+
const [t, S, g, n] = u.viewBox;
|
|
129
|
+
a = {
|
|
130
|
+
centerX: t + g / 2,
|
|
131
|
+
centerY: S + n / 2,
|
|
132
|
+
zoom: Math.min(1, re() * 0.92)
|
|
133
|
+
}, T = !1, R(), L("camera", { camera: { ...a }, reason: e });
|
|
134
|
+
}, P = (e) => {
|
|
135
|
+
a.zoom = Math.max(0.02, Math.min(8, a.zoom * e)), T = !0, R(), L("camera", { camera: { ...a }, reason: "user" });
|
|
136
|
+
}, ne = () => {
|
|
137
|
+
a.zoom = 1, T = !0, R(), L("camera", { camera: { ...a }, reason: "user" });
|
|
138
|
+
};
|
|
139
|
+
c.toolbar !== !1 && (j("Zoom in", () => P(1.2)), j("Zoom out", () => P(1 / 1.2)), j("Fit diagram", () => Y()), j("Actual size", ne));
|
|
140
|
+
const J = new v.ResizeObserver(() => {
|
|
141
|
+
u && !o.getBoundingClientRect().width || (T ? R() : Y("resize"));
|
|
142
|
+
});
|
|
143
|
+
J.observe(o);
|
|
144
|
+
const X = (e, r) => {
|
|
145
|
+
l.textContent = r.map((t) => t.message).join(" "), m.classList.add("draft-viewer--stale"), L("diagnostics", { revision: e, diagnostics: r, stale: !!u });
|
|
146
|
+
}, oe = async (e, r) => {
|
|
147
|
+
const t = ue(s, e);
|
|
148
|
+
if (!t.length) return [];
|
|
149
|
+
if (!s.fonts) throw new Error("The host document cannot load diagram fonts.");
|
|
150
|
+
if (r === "host") {
|
|
151
|
+
for (const n of t) {
|
|
152
|
+
const h = `${n.weight} 12px "${n.family}"`;
|
|
153
|
+
if (!(await s.fonts.load(h)).some(
|
|
154
|
+
(E) => E.family.replace(/^['"]|['"]$/g, "") === n.family && E.weight === n.weight && E.status === "loaded"
|
|
155
|
+
) || !s.fonts.check(h))
|
|
156
|
+
throw new Error(`Host font ${n.family} ${n.weight} is unavailable.`);
|
|
157
|
+
}
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
const S = we(s, e, t), g = v.FontFace;
|
|
161
|
+
if (!g) throw new Error("The browser cannot load embedded diagram fonts.");
|
|
162
|
+
return Promise.all(
|
|
163
|
+
S.map(async (n) => {
|
|
164
|
+
const h = `${n.family}:${n.weight}`, C = M.get(h);
|
|
165
|
+
if (C?.status === "loaded" && Array.from(s.fonts).includes(C))
|
|
166
|
+
return { key: h, face: C };
|
|
167
|
+
const d = new g(n.family, `url("${n.data}")`, { weight: n.weight });
|
|
168
|
+
if (await d.load(), d.status !== "loaded")
|
|
169
|
+
throw new Error(`Embedded font ${n.family} ${n.weight} did not load.`);
|
|
170
|
+
return { key: h, face: d };
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
}, z = (e) => {
|
|
174
|
+
const r = B;
|
|
175
|
+
B = void 0, r && (v.clearTimeout(r.timer), r.cleanup(), r.finish(void 0, e ?? new Error("Viewer render was cancelled."))), F?.terminate(), F = void 0;
|
|
176
|
+
}, ae = (e, r, t) => (c.execution ?? { mode: "worker" }).mode === "main" ? ce(e, { ...r, signal: t }) : new Promise((S, g) => {
|
|
177
|
+
const n = ++te;
|
|
178
|
+
let h = !1;
|
|
179
|
+
const C = () => {
|
|
180
|
+
F && (F.removeEventListener("message", E), F.removeEventListener("error", W), F.removeEventListener("messageerror", U), t?.removeEventListener("abort", H));
|
|
181
|
+
}, d = (k, D) => {
|
|
182
|
+
if (h) return;
|
|
183
|
+
h = !0;
|
|
184
|
+
const i = B;
|
|
185
|
+
i?.id === n && (B = void 0, v.clearTimeout(i.timer), i.cleanup()), D ? g(D) : S(k);
|
|
186
|
+
}, E = (k) => {
|
|
187
|
+
k.data?.id === n && d(k.data.result);
|
|
188
|
+
}, W = (k) => {
|
|
189
|
+
k.preventDefault(), z(new Error(k.message || "Viewer render worker failed."));
|
|
190
|
+
}, U = () => z(new Error("Viewer render worker returned an unreadable result.")), H = () => z(new Error("Viewer render was aborted."));
|
|
191
|
+
try {
|
|
192
|
+
F ??= c.execution?.mode === "worker" && c.execution.createWorker ? c.execution.createWorker() : new Worker(new URL(
|
|
193
|
+
/* @vite-ignore */
|
|
194
|
+
"" + new URL("assets/render.worker-BpUp6NY_.js", import.meta.url).href,
|
|
195
|
+
import.meta.url
|
|
196
|
+
), { type: "module" }), F.addEventListener("message", E), F.addEventListener("error", W), F.addEventListener("messageerror", U), t?.addEventListener("abort", H, { once: !0 });
|
|
197
|
+
const k = c.execution?.mode === "worker" ? c.execution.timeoutMs ?? 5e3 : 5e3, D = v.setTimeout(
|
|
198
|
+
() => z(new Error("Viewer render worker timed out.")),
|
|
199
|
+
k
|
|
200
|
+
);
|
|
201
|
+
B = { id: n, timer: D, finish: d, cleanup: C }, F.postMessage({ id: n, source: e, options: r });
|
|
202
|
+
} catch (k) {
|
|
203
|
+
z(
|
|
204
|
+
k instanceof Error ? k : new Error("Viewer render worker could not start.")
|
|
205
|
+
), g(k);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
let A;
|
|
209
|
+
const ie = (e) => {
|
|
210
|
+
const r = o.querySelector("svg"), t = r?.querySelector(":scope > rect");
|
|
211
|
+
return e === o || e === r || e === t;
|
|
212
|
+
};
|
|
213
|
+
o.addEventListener(
|
|
214
|
+
"wheel",
|
|
215
|
+
(e) => {
|
|
216
|
+
e.preventDefault(), P(e.deltaY < 0 ? 1.1 : 1 / 1.1);
|
|
217
|
+
},
|
|
218
|
+
{ passive: !1 }
|
|
219
|
+
), o.addEventListener("pointerdown", (e) => {
|
|
220
|
+
!ie(e.target) || !u || (A = {
|
|
221
|
+
pointerId: e.pointerId,
|
|
222
|
+
x: e.clientX,
|
|
223
|
+
y: e.clientY,
|
|
224
|
+
centerX: a.centerX,
|
|
225
|
+
centerY: a.centerY,
|
|
226
|
+
scale: a.zoom
|
|
227
|
+
}, o.setPointerCapture(e.pointerId));
|
|
228
|
+
}), o.addEventListener("pointermove", (e) => {
|
|
229
|
+
A && (a.centerX = A.centerX - (e.clientX - A.x) / A.scale, a.centerY = A.centerY - (e.clientY - A.y) / A.scale, T = !0, R());
|
|
230
|
+
});
|
|
231
|
+
const Q = () => {
|
|
232
|
+
if (A) {
|
|
233
|
+
try {
|
|
234
|
+
o.releasePointerCapture(A.pointerId);
|
|
235
|
+
} catch {
|
|
236
|
+
}
|
|
237
|
+
A = void 0, L("camera", { camera: { ...a }, reason: "user" });
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
o.addEventListener("pointerup", Q), o.addEventListener("pointercancel", Q), o.addEventListener("click", (e) => {
|
|
241
|
+
const r = e.target instanceof v.Element ? e.target : null, t = r?.closest("a[href]");
|
|
242
|
+
if (t && o.contains(t)) {
|
|
243
|
+
const n = t.querySelector("[data-id]")?.getAttribute("data-id"), h = t.getAttribute("href");
|
|
244
|
+
n && h && L("link", {
|
|
245
|
+
itemId: n,
|
|
246
|
+
href: h,
|
|
247
|
+
target: t.getAttribute("target") === "_blank" ? "_blank" : "_self",
|
|
248
|
+
preventDefault: () => e.preventDefault()
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const S = r?.closest("[data-id]")?.getAttribute("data-id"), g = u?.items.find((n) => n.id === S);
|
|
253
|
+
g && L("itemactivate", { id: g.id, kind: g.kind, input: "pointer", revision: f });
|
|
254
|
+
}), o.addEventListener("keydown", (e) => {
|
|
255
|
+
e.target !== o || e.altKey || e.ctrlKey || e.metaKey || (e.key === "+" || e.key === "=" ? P(1.2) : e.key === "-" ? P(1 / 1.2) : e.key.toLowerCase() === "f" && Y());
|
|
256
|
+
});
|
|
257
|
+
const se = (e, r) => {
|
|
258
|
+
for (const [t, S] of q)
|
|
259
|
+
t !== e && S.resolve({ status: r, revision: t });
|
|
260
|
+
};
|
|
261
|
+
return {
|
|
262
|
+
update: (e, r = {}) => {
|
|
263
|
+
const t = ++f;
|
|
264
|
+
return x ? Promise.resolve({ status: "destroyed", revision: t }) : (se(t, "superseded"), z(new Error("Viewer update was superseded.")), new Promise((S) => {
|
|
265
|
+
let g = !1;
|
|
266
|
+
const n = (d) => {
|
|
267
|
+
if (g) return;
|
|
268
|
+
g = !0, r.signal?.removeEventListener("abort", h), q.delete(t);
|
|
269
|
+
const E = x ? { status: "destroyed", revision: t } : t !== f ? { status: "superseded", revision: t } : r.signal?.aborted ? { status: "aborted", revision: t } : d;
|
|
270
|
+
S(E);
|
|
271
|
+
}, h = () => {
|
|
272
|
+
t === f && (c.execution ?? { mode: "worker" }).mode === "worker" && z(new Error("Viewer render was aborted.")), n({ status: "aborted", revision: t });
|
|
273
|
+
};
|
|
274
|
+
if (q.set(t, { resolve: n }), r.signal?.aborted) {
|
|
275
|
+
h();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
r.signal?.addEventListener("abort", h, { once: !0 });
|
|
279
|
+
const C = {
|
|
280
|
+
...c.render ?? {},
|
|
281
|
+
target: "inline",
|
|
282
|
+
idPrefix: p,
|
|
283
|
+
fonts: c.render?.fonts ?? "embed",
|
|
284
|
+
...r.state !== void 0 ? { state: r.state } : {}
|
|
285
|
+
};
|
|
286
|
+
ae(e, C, r.signal).then(async (d) => {
|
|
287
|
+
if (x || t !== f || r.signal?.aborted) {
|
|
288
|
+
n({ status: "superseded", revision: t });
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (!d.ok) {
|
|
292
|
+
X(t, d.diagnostics), n({ status: "error", revision: t, error: d });
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
let E;
|
|
296
|
+
try {
|
|
297
|
+
E = await oe(d.value.svg, C.fonts ?? "embed");
|
|
298
|
+
} catch (i) {
|
|
299
|
+
if (x || t !== f || r.signal?.aborted) {
|
|
300
|
+
n({
|
|
301
|
+
status: r.signal?.aborted ? "aborted" : "superseded",
|
|
302
|
+
revision: t
|
|
303
|
+
});
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const $ = K(
|
|
307
|
+
"environment",
|
|
308
|
+
"DRAFT_FONT_UNAVAILABLE",
|
|
309
|
+
i instanceof Error ? i.message : "Diagram fonts are unavailable."
|
|
310
|
+
);
|
|
311
|
+
X(t, $.diagnostics), n({ status: "error", revision: t, error: $ });
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (x || t !== f || r.signal?.aborted) {
|
|
315
|
+
n({ status: "superseded", revision: t });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
let W;
|
|
319
|
+
try {
|
|
320
|
+
W = ge(s, d.value.svg, C.fonts !== "host");
|
|
321
|
+
} catch (i) {
|
|
322
|
+
const $ = i instanceof Error ? i.message : "Could not build safe SVG.", N = K("internal", "DRAFT_VIEWER_DOM", $);
|
|
323
|
+
X(t, N.diagnostics), n({ status: "error", revision: t, error: N });
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const U = [];
|
|
327
|
+
try {
|
|
328
|
+
for (const i of E)
|
|
329
|
+
M.has(i.key) || (s.fonts.add(i.face), M.set(i.key, i.face), U.push(i));
|
|
330
|
+
} catch (i) {
|
|
331
|
+
for (const { key: N, face: Z } of U)
|
|
332
|
+
s.fonts.delete(Z), M.delete(N);
|
|
333
|
+
const $ = K(
|
|
334
|
+
"environment",
|
|
335
|
+
"DRAFT_FONT_UNAVAILABLE",
|
|
336
|
+
i instanceof Error ? i.message : "Loaded fonts could not be registered."
|
|
337
|
+
);
|
|
338
|
+
X(t, $.diagnostics), n({ status: "error", revision: t, error: $ });
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const H = !!u;
|
|
342
|
+
u = d.value, o.replaceChildren(W), w.replaceChildren(
|
|
343
|
+
...u.items.map((i) => {
|
|
344
|
+
const $ = s.createElement("li"), N = s.createElement("button");
|
|
345
|
+
N.type = "button";
|
|
346
|
+
const Z = i.label.trim() || (i.kind === "edge" ? `${i.from ?? "?"} to ${i.to ?? "?"}` : i.id);
|
|
347
|
+
return N.textContent = `${i.kind}: ${Z}`, N.dataset.itemId = i.id, N.addEventListener("click", () => {
|
|
348
|
+
L("itemactivate", {
|
|
349
|
+
id: i.id,
|
|
350
|
+
kind: i.kind,
|
|
351
|
+
input: "keyboard",
|
|
352
|
+
revision: t
|
|
353
|
+
});
|
|
354
|
+
const O = Array.from(o.querySelectorAll("[data-id]")).find(
|
|
355
|
+
(_) => _.getAttribute("data-id") === i.id
|
|
356
|
+
);
|
|
357
|
+
if (O) {
|
|
358
|
+
const _ = O.getBoundingClientRect(), I = o.getBoundingClientRect();
|
|
359
|
+
(_.width || _.height) && I.width && I.height && (a = {
|
|
360
|
+
centerX: a.centerX + (_.left + _.width / 2 - (I.left + I.width / 2)) / a.zoom,
|
|
361
|
+
centerY: a.centerY + (_.top + _.height / 2 - (I.top + I.height / 2)) / a.zoom,
|
|
362
|
+
zoom: Math.max(1, a.zoom)
|
|
363
|
+
}, T = !0, R(), L("camera", { camera: { ...a }, reason: "user" }));
|
|
364
|
+
}
|
|
365
|
+
}), $.append(N), $;
|
|
366
|
+
})
|
|
367
|
+
);
|
|
368
|
+
const k = new Set(E.map((i) => i.key));
|
|
369
|
+
for (const [i, $] of M)
|
|
370
|
+
k.has(i) || (s.fonts.delete($), M.delete(i));
|
|
371
|
+
m.classList.remove("draft-viewer--stale"), l.textContent = d.diagnostics.map((i) => i.message).join(" "), !H || r.camera === "fit" ? Y() : R();
|
|
372
|
+
const D = {
|
|
373
|
+
status: "committed",
|
|
374
|
+
revision: t,
|
|
375
|
+
value: u,
|
|
376
|
+
diagnostics: d.diagnostics
|
|
377
|
+
};
|
|
378
|
+
n(D), L("render", { revision: t, value: u }), L("diagnostics", { revision: t, diagnostics: d.diagnostics, stale: !1 });
|
|
379
|
+
}).catch((d) => {
|
|
380
|
+
if (x || t !== f || r.signal?.aborted) {
|
|
381
|
+
n({
|
|
382
|
+
status: r.signal?.aborted ? "aborted" : "superseded",
|
|
383
|
+
revision: t
|
|
384
|
+
});
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const E = K(
|
|
388
|
+
"environment",
|
|
389
|
+
"DRAFT_VIEWER_WORKER",
|
|
390
|
+
d instanceof Error ? d.message : "Viewer render failed."
|
|
391
|
+
);
|
|
392
|
+
X(t, E.diagnostics), n({ status: "error", revision: t, error: E });
|
|
393
|
+
});
|
|
394
|
+
}));
|
|
395
|
+
},
|
|
396
|
+
on(e, r) {
|
|
397
|
+
if (x) return () => {
|
|
398
|
+
};
|
|
399
|
+
const t = G.get(e) ?? /* @__PURE__ */ new Set();
|
|
400
|
+
return t.add(r), G.set(e, t), () => t.delete(r);
|
|
401
|
+
},
|
|
402
|
+
getCamera: () => ({ ...a }),
|
|
403
|
+
setCamera(e) {
|
|
404
|
+
x || !Number.isFinite(e.centerX) || !Number.isFinite(e.centerY) || !Number.isFinite(e.zoom) || e.zoom <= 0 || (a = { ...e }, T = !0, R(), L("camera", { camera: { ...a }, reason: "api" }));
|
|
405
|
+
},
|
|
406
|
+
fit: () => {
|
|
407
|
+
x || Y();
|
|
408
|
+
},
|
|
409
|
+
focusItem(e) {
|
|
410
|
+
if (!u?.items.some((t) => t.id === e)) return !1;
|
|
411
|
+
const r = Array.from(w.querySelectorAll("button")).find(
|
|
412
|
+
(t) => t.dataset.itemId === e
|
|
413
|
+
);
|
|
414
|
+
return r?.focus(), !!r;
|
|
415
|
+
},
|
|
416
|
+
destroy() {
|
|
417
|
+
if (!x) {
|
|
418
|
+
if (x = !0, f++, A) {
|
|
419
|
+
try {
|
|
420
|
+
o.releasePointerCapture(A.pointerId);
|
|
421
|
+
} catch {
|
|
422
|
+
}
|
|
423
|
+
A = void 0;
|
|
424
|
+
}
|
|
425
|
+
for (const [e, r] of q)
|
|
426
|
+
r.resolve({ status: "destroyed", revision: e });
|
|
427
|
+
q.clear(), z(new Error("Viewer was destroyed."));
|
|
428
|
+
for (const e of M.values()) s.fonts.delete(e);
|
|
429
|
+
M.clear(), J.disconnect(), G.clear(), y.replaceChildren(), u = void 0;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
export {
|
|
435
|
+
Ee as fontMetricsVersion,
|
|
436
|
+
ve as mountViewer,
|
|
437
|
+
ke as runtimeVersion
|
|
438
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@draftably/runtime",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Portable native Draftably SVG rendering, validation, and optional viewer.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"sideEffects": [
|
|
9
|
+
"**/*.css",
|
|
10
|
+
"./dist/element.js"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/types/src/runtime/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./viewer": {
|
|
22
|
+
"types": "./dist/types/src/runtime/viewer.d.ts",
|
|
23
|
+
"import": "./dist/viewer.js"
|
|
24
|
+
},
|
|
25
|
+
"./element": {
|
|
26
|
+
"types": "./dist/types/src/runtime/element.d.ts",
|
|
27
|
+
"import": "./dist/element.js"
|
|
28
|
+
},
|
|
29
|
+
"./viewer.css": "./dist/viewer.css",
|
|
30
|
+
"./fonts.css": "./dist/fonts.css",
|
|
31
|
+
"./browser": {
|
|
32
|
+
"types": "./dist/types/src/runtime/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./package.json": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "node ../../scripts/build-runtime.ts"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=22.21.0"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/byronwall/draftably.git",
|
|
46
|
+
"directory": "packages/runtime"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public",
|
|
50
|
+
"registry": "https://registry.npmjs.org"
|
|
51
|
+
}
|
|
52
|
+
}
|