@draftably/runtime 0.1.0 → 0.2.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 +16 -44
- package/dist/assets/{render.worker-BpUp6NY_.js → render.worker-fWW85Tf9.js} +2719 -2676
- package/dist/element.js +21 -12
- package/dist/{font-data-DbrpaYkG.js → font-data-tnqJ-kTK.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/{render-BOAZBzVa.js → render-ZzhO-2H6.js} +2764 -2721
- package/dist/types/src/runtime/element.d.ts +2 -0
- package/dist/types/src/runtime/viewer.d.ts +5 -0
- package/dist/viewer.css +20 -0
- package/dist/viewer.js +81 -81
- package/package.json +5 -5
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { UpdateResult, ViewerHandle, ViewerOptions } from './viewer.js';
|
|
2
2
|
export interface DraftDiagramElement extends HTMLElement {
|
|
3
3
|
source: string;
|
|
4
|
+
/** Reflects the `outline` attribute. */
|
|
5
|
+
outline: 'visible' | 'hidden' | undefined;
|
|
4
6
|
options: ViewerOptions;
|
|
5
7
|
readonly viewer?: ViewerHandle;
|
|
6
8
|
readonly updateComplete: Promise<UpdateResult | undefined>;
|
|
@@ -19,6 +19,11 @@ export type ViewerRenderOptions = Omit<CommonRenderOptions, 'signal' | 'state'>
|
|
|
19
19
|
export interface ViewerOptions {
|
|
20
20
|
label?: string;
|
|
21
21
|
toolbar?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* The keyboard and screen-reader list of items. `'hidden'` (default) keeps it for assistive tech
|
|
24
|
+
* and shows it while it holds focus; `'visible'` always shows it under the drawing.
|
|
25
|
+
*/
|
|
26
|
+
outline?: 'visible' | 'hidden';
|
|
22
27
|
execution?: ViewerExecution;
|
|
23
28
|
render?: ViewerRenderOptions;
|
|
24
29
|
}
|
package/dist/viewer.css
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
--dv-border: #cbd5e1;
|
|
3
3
|
--dv-ink: #1e293b;
|
|
4
4
|
--dv-bg: #fff;
|
|
5
|
+
position: relative;
|
|
5
6
|
display: grid;
|
|
6
7
|
grid-template-rows: auto minmax(8rem, 1fr) auto auto;
|
|
7
8
|
box-sizing: border-box;
|
|
@@ -67,6 +68,25 @@
|
|
|
67
68
|
.draft-viewer__outline:empty {
|
|
68
69
|
display: none;
|
|
69
70
|
}
|
|
71
|
+
/* A hidden outline stays in the tab order and the accessibility tree. Focus shows it over the
|
|
72
|
+
bottom of the drawing, so the viewport keeps its size. */
|
|
73
|
+
.draft-viewer--outline-hidden .draft-viewer__outline:not(:focus-within) {
|
|
74
|
+
position: absolute;
|
|
75
|
+
width: 1px;
|
|
76
|
+
height: 1px;
|
|
77
|
+
margin: -1px;
|
|
78
|
+
padding: 0;
|
|
79
|
+
overflow: hidden;
|
|
80
|
+
clip-path: inset(50%);
|
|
81
|
+
white-space: nowrap;
|
|
82
|
+
border: 0;
|
|
83
|
+
}
|
|
84
|
+
.draft-viewer--outline-hidden .draft-viewer__outline:focus-within {
|
|
85
|
+
position: absolute;
|
|
86
|
+
inset: auto 0 0;
|
|
87
|
+
background: var(--dv-bg);
|
|
88
|
+
box-shadow: 0 -4px 12px rgb(15 23 42 / 0.12);
|
|
89
|
+
}
|
|
70
90
|
.draft-viewer--stale .draft-viewer__status {
|
|
71
91
|
color: #9a3412;
|
|
72
92
|
background: #fff7ed;
|
package/dist/viewer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as ce, F as ee } from "./render-
|
|
2
|
-
import { f as Ee, a as ke } from "./render-
|
|
1
|
+
import { r as ce, F as ee } from "./render-ZzhO-2H6.js";
|
|
2
|
+
import { f as Ee, a as ke } from "./render-ZzhO-2H6.js";
|
|
3
3
|
const de = "http://www.w3.org/2000/svg", le = new Set(
|
|
4
4
|
"svg title desc metadata defs style marker g a path rect ellipse circle line polyline polygon text tspan".split(
|
|
5
5
|
" "
|
|
@@ -13,25 +13,25 @@ let me = 0;
|
|
|
13
13
|
function ue(y, c) {
|
|
14
14
|
const V = new y.defaultView.DOMParser().parseFromString(c, "image/svg+xml"), s = /* @__PURE__ */ new Map();
|
|
15
15
|
for (const v of Array.from(V.querySelectorAll("text[font-family]"))) {
|
|
16
|
-
const
|
|
17
|
-
if (!Object.values(ee).some((o) => o.family ===
|
|
16
|
+
const l = (v.getAttribute("font-family") ?? "").split(",")[0].trim().replace(/^['"]|['"]$/g, ""), b = v.getAttribute("font-weight") ?? "400";
|
|
17
|
+
if (!Object.values(ee).some((o) => o.family === l && String(o.weight) === b))
|
|
18
18
|
throw new Error("Runtime SVG requested an unknown bundled font face.");
|
|
19
|
-
s.set(`${
|
|
19
|
+
s.set(`${l}:${b}`, { family: l, weight: b });
|
|
20
20
|
}
|
|
21
21
|
return [...s.values()];
|
|
22
22
|
}
|
|
23
23
|
function we(y, c, V) {
|
|
24
24
|
const s = new y.defaultView.DOMParser().parseFromString(c, "image/svg+xml"), v = /* @__PURE__ */ new Map();
|
|
25
|
-
for (const
|
|
26
|
-
const b =
|
|
25
|
+
for (const l of Array.from(s.querySelectorAll("style"))) {
|
|
26
|
+
const b = l.textContent ?? "";
|
|
27
27
|
for (const [, o] of b.matchAll(/@font-face\s*\{([^{}]{1,200000})\}/g)) {
|
|
28
|
-
const
|
|
29
|
-
!
|
|
28
|
+
const f = /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
|
+
!f || !w || !p || Object.values(ee).some((m) => m.family === f && String(m.weight) === w) && v.set(`${f}:${w}`, { family: f, weight: w, data: p });
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
return V.map((
|
|
33
|
-
const b = v.get(`${
|
|
34
|
-
if (!b) throw new Error(`Embedded font ${
|
|
32
|
+
return V.map((l) => {
|
|
33
|
+
const b = v.get(`${l.family}:${l.weight}`);
|
|
34
|
+
if (!b) throw new Error(`Embedded font ${l.family} ${l.weight} is missing.`);
|
|
35
35
|
return b;
|
|
36
36
|
});
|
|
37
37
|
}
|
|
@@ -39,37 +39,37 @@ function ge(y, c, V, s = 1e5) {
|
|
|
39
39
|
const v = new y.defaultView.DOMParser().parseFromString(c, "image/svg+xml");
|
|
40
40
|
if (v.querySelector("parsererror") || v.documentElement.localName !== "svg")
|
|
41
41
|
throw new Error("Runtime returned invalid SVG.");
|
|
42
|
-
const
|
|
43
|
-
Array.from(v.querySelectorAll("[id]"), (
|
|
42
|
+
const l = new Set(
|
|
43
|
+
Array.from(v.querySelectorAll("[id]"), (f) => f.getAttribute("id") ?? "")
|
|
44
44
|
);
|
|
45
45
|
let b = 0;
|
|
46
|
-
const o = (
|
|
47
|
-
if (++b > s || !le.has(
|
|
46
|
+
const o = (f) => {
|
|
47
|
+
if (++b > s || !le.has(f.localName))
|
|
48
48
|
throw new Error("Runtime SVG exceeded the allowed drawing vocabulary.");
|
|
49
|
-
const w = y.createElementNS(de,
|
|
50
|
-
for (const { name: p, value:
|
|
49
|
+
const w = y.createElementNS(de, f.localName);
|
|
50
|
+
for (const { name: p, value: m } of Array.from(f.attributes)) {
|
|
51
51
|
if (/^on/i.test(p)) continue;
|
|
52
52
|
if (p === "href") {
|
|
53
|
-
if (
|
|
53
|
+
if (f.localName !== "a") continue;
|
|
54
54
|
try {
|
|
55
|
-
const a = new URL(
|
|
55
|
+
const a = new URL(m, y.baseURI);
|
|
56
56
|
(a.protocol === "http:" || a.protocol === "https:") && w.setAttribute("href", a.href);
|
|
57
57
|
} catch {
|
|
58
58
|
}
|
|
59
59
|
continue;
|
|
60
60
|
}
|
|
61
61
|
if (!fe.has(p) && !/^data-[a-z0-9-]+$/.test(p)) continue;
|
|
62
|
-
const x = [...
|
|
63
|
-
/url\s*\(/i.test(
|
|
62
|
+
const x = [...m.matchAll(/url\(#([^)]*)\)/g)].map((a) => a[1]);
|
|
63
|
+
/url\s*\(/i.test(m) && (x.length === 0 || x.some((a) => !l.has(a))) || p === "aria-labelledby" && m.split(/\s+/).some((a) => !l.has(a)) || w.setAttribute(p, m);
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
for (const p of Array.from(
|
|
65
|
+
f.localName === "a" && w.getAttribute("target") === "_blank" && w.setAttribute("rel", "noopener noreferrer");
|
|
66
|
+
for (const p of Array.from(f.childNodes))
|
|
67
67
|
if (p.nodeType === 1) w.append(o(p));
|
|
68
68
|
else if (p.nodeType === 3) {
|
|
69
|
-
const
|
|
69
|
+
const m = p.nodeValue ?? "";
|
|
70
70
|
w.append(
|
|
71
71
|
y.createTextNode(
|
|
72
|
-
|
|
72
|
+
f.localName === "style" && V ? m.replace(/@font-face\s*\{[^{}]*\}/g, "") : m
|
|
73
73
|
)
|
|
74
74
|
);
|
|
75
75
|
}
|
|
@@ -91,19 +91,19 @@ function ve(y, c = {}) {
|
|
|
91
91
|
if (y.childNodes.length) throw new Error("Viewer host must be empty and exclusively owned.");
|
|
92
92
|
if ((c.execution ?? { mode: "worker" }).mode === "worker" && c.render?.links?.mode === "safe" && c.render.links.resolve)
|
|
93
93
|
throw new TypeError('A link resolver requires execution: { mode: "main" }.');
|
|
94
|
-
const s = y.ownerDocument, v = V,
|
|
95
|
-
|
|
94
|
+
const s = y.ownerDocument, v = V, l = s.createElement("section");
|
|
95
|
+
l.className = "draft-viewer", c.outline !== "visible" && l.classList.add("draft-viewer--outline-hidden"), l.setAttribute("aria-label", c.label ?? "Diagram viewer");
|
|
96
96
|
const b = s.createElement("div");
|
|
97
97
|
b.className = "draft-viewer__toolbar", b.setAttribute("role", "toolbar"), b.setAttribute("aria-label", "Diagram controls");
|
|
98
98
|
const o = s.createElement("div");
|
|
99
99
|
o.className = "draft-viewer__viewport", o.tabIndex = 0, o.setAttribute("aria-label", c.label ?? "Diagram");
|
|
100
|
-
const
|
|
101
|
-
|
|
100
|
+
const f = s.createElement("p");
|
|
101
|
+
f.className = "draft-viewer__status", f.setAttribute("role", "status"), f.setAttribute("aria-live", "polite");
|
|
102
102
|
const w = s.createElement("ol");
|
|
103
|
-
w.className = "draft-viewer__outline", w.setAttribute("aria-label", "Diagram outline"),
|
|
103
|
+
w.className = "draft-viewer__outline", w.setAttribute("aria-label", "Diagram outline"), l.append(b, o, f, w), y.append(l);
|
|
104
104
|
const p = `draftViewer${(++me).toString(36)}${Math.random().toString(36).slice(2, 9)}`;
|
|
105
|
-
let
|
|
106
|
-
const
|
|
105
|
+
let m = 0, x = !1, a = { centerX: 0, centerY: 0, zoom: 1 }, _ = !1, u, F, q, te = 0;
|
|
106
|
+
const N = /* @__PURE__ */ new Map(), G = /* @__PURE__ */ new Map(), B = /* @__PURE__ */ new Map(), L = (e, r) => {
|
|
107
107
|
for (const t of G.get(e) ?? [])
|
|
108
108
|
try {
|
|
109
109
|
t(r);
|
|
@@ -130,19 +130,19 @@ function ve(y, c = {}) {
|
|
|
130
130
|
centerX: t + g / 2,
|
|
131
131
|
centerY: S + n / 2,
|
|
132
132
|
zoom: Math.min(1, re() * 0.92)
|
|
133
|
-
},
|
|
133
|
+
}, _ = !1, R(), L("camera", { camera: { ...a }, reason: e });
|
|
134
134
|
}, P = (e) => {
|
|
135
|
-
a.zoom = Math.max(0.02, Math.min(8, a.zoom * e)),
|
|
135
|
+
a.zoom = Math.max(0.02, Math.min(8, a.zoom * e)), _ = !0, R(), L("camera", { camera: { ...a }, reason: "user" });
|
|
136
136
|
}, ne = () => {
|
|
137
|
-
a.zoom = 1,
|
|
137
|
+
a.zoom = 1, _ = !0, R(), L("camera", { camera: { ...a }, reason: "user" });
|
|
138
138
|
};
|
|
139
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
140
|
const J = new v.ResizeObserver(() => {
|
|
141
|
-
u && !o.getBoundingClientRect().width || (
|
|
141
|
+
u && !o.getBoundingClientRect().width || (_ ? R() : Y("resize"));
|
|
142
142
|
});
|
|
143
143
|
J.observe(o);
|
|
144
144
|
const X = (e, r) => {
|
|
145
|
-
|
|
145
|
+
f.textContent = r.map((t) => t.message).join(" "), l.classList.add("draft-viewer--stale"), L("diagnostics", { revision: e, diagnostics: r, stale: !!u });
|
|
146
146
|
}, oe = async (e, r) => {
|
|
147
147
|
const t = ue(s, e);
|
|
148
148
|
if (!t.length) return [];
|
|
@@ -161,7 +161,7 @@ function ve(y, c = {}) {
|
|
|
161
161
|
if (!g) throw new Error("The browser cannot load embedded diagram fonts.");
|
|
162
162
|
return Promise.all(
|
|
163
163
|
S.map(async (n) => {
|
|
164
|
-
const h = `${n.family}:${n.weight}`, C =
|
|
164
|
+
const h = `${n.family}:${n.weight}`, C = N.get(h);
|
|
165
165
|
if (C?.status === "loaded" && Array.from(s.fonts).includes(C))
|
|
166
166
|
return { key: h, face: C };
|
|
167
167
|
const d = new g(n.family, `url("${n.data}")`, { weight: n.weight });
|
|
@@ -171,8 +171,8 @@ function ve(y, c = {}) {
|
|
|
171
171
|
})
|
|
172
172
|
);
|
|
173
173
|
}, z = (e) => {
|
|
174
|
-
const r =
|
|
175
|
-
|
|
174
|
+
const r = q;
|
|
175
|
+
q = 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
176
|
}, ae = (e, r, t) => (c.execution ?? { mode: "worker" }).mode === "main" ? ce(e, { ...r, signal: t }) : new Promise((S, g) => {
|
|
177
177
|
const n = ++te;
|
|
178
178
|
let h = !1;
|
|
@@ -181,8 +181,8 @@ function ve(y, c = {}) {
|
|
|
181
181
|
}, d = (k, D) => {
|
|
182
182
|
if (h) return;
|
|
183
183
|
h = !0;
|
|
184
|
-
const i =
|
|
185
|
-
i?.id === n && (
|
|
184
|
+
const i = q;
|
|
185
|
+
i?.id === n && (q = void 0, v.clearTimeout(i.timer), i.cleanup()), D ? g(D) : S(k);
|
|
186
186
|
}, E = (k) => {
|
|
187
187
|
k.data?.id === n && d(k.data.result);
|
|
188
188
|
}, W = (k) => {
|
|
@@ -191,14 +191,14 @@ function ve(y, c = {}) {
|
|
|
191
191
|
try {
|
|
192
192
|
F ??= c.execution?.mode === "worker" && c.execution.createWorker ? c.execution.createWorker() : new Worker(new URL(
|
|
193
193
|
/* @vite-ignore */
|
|
194
|
-
"" + new URL("assets/render.worker-
|
|
194
|
+
"" + new URL("assets/render.worker-fWW85Tf9.js", import.meta.url).href,
|
|
195
195
|
import.meta.url
|
|
196
196
|
), { type: "module" }), F.addEventListener("message", E), F.addEventListener("error", W), F.addEventListener("messageerror", U), t?.addEventListener("abort", H, { once: !0 });
|
|
197
197
|
const k = c.execution?.mode === "worker" ? c.execution.timeoutMs ?? 5e3 : 5e3, D = v.setTimeout(
|
|
198
198
|
() => z(new Error("Viewer render worker timed out.")),
|
|
199
199
|
k
|
|
200
200
|
);
|
|
201
|
-
|
|
201
|
+
q = { id: n, timer: D, finish: d, cleanup: C }, F.postMessage({ id: n, source: e, options: r });
|
|
202
202
|
} catch (k) {
|
|
203
203
|
z(
|
|
204
204
|
k instanceof Error ? k : new Error("Viewer render worker could not start.")
|
|
@@ -226,7 +226,7 @@ function ve(y, c = {}) {
|
|
|
226
226
|
scale: a.zoom
|
|
227
227
|
}, o.setPointerCapture(e.pointerId));
|
|
228
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,
|
|
229
|
+
A && (a.centerX = A.centerX - (e.clientX - A.x) / A.scale, a.centerY = A.centerY - (e.clientY - A.y) / A.scale, _ = !0, R());
|
|
230
230
|
});
|
|
231
231
|
const Q = () => {
|
|
232
232
|
if (A) {
|
|
@@ -250,28 +250,28 @@ function ve(y, c = {}) {
|
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
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:
|
|
253
|
+
g && L("itemactivate", { id: g.id, kind: g.kind, input: "pointer", revision: m });
|
|
254
254
|
}), o.addEventListener("keydown", (e) => {
|
|
255
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
256
|
});
|
|
257
257
|
const se = (e, r) => {
|
|
258
|
-
for (const [t, S] of
|
|
258
|
+
for (const [t, S] of B)
|
|
259
259
|
t !== e && S.resolve({ status: r, revision: t });
|
|
260
260
|
};
|
|
261
261
|
return {
|
|
262
262
|
update: (e, r = {}) => {
|
|
263
|
-
const t = ++
|
|
263
|
+
const t = ++m;
|
|
264
264
|
return x ? Promise.resolve({ status: "destroyed", revision: t }) : (se(t, "superseded"), z(new Error("Viewer update was superseded.")), new Promise((S) => {
|
|
265
265
|
let g = !1;
|
|
266
266
|
const n = (d) => {
|
|
267
267
|
if (g) return;
|
|
268
|
-
g = !0, r.signal?.removeEventListener("abort", h),
|
|
269
|
-
const E = x ? { status: "destroyed", revision: t } : t !==
|
|
268
|
+
g = !0, r.signal?.removeEventListener("abort", h), B.delete(t);
|
|
269
|
+
const E = x ? { status: "destroyed", revision: t } : t !== m ? { status: "superseded", revision: t } : r.signal?.aborted ? { status: "aborted", revision: t } : d;
|
|
270
270
|
S(E);
|
|
271
271
|
}, h = () => {
|
|
272
|
-
t ===
|
|
272
|
+
t === m && (c.execution ?? { mode: "worker" }).mode === "worker" && z(new Error("Viewer render was aborted.")), n({ status: "aborted", revision: t });
|
|
273
273
|
};
|
|
274
|
-
if (
|
|
274
|
+
if (B.set(t, { resolve: n }), r.signal?.aborted) {
|
|
275
275
|
h();
|
|
276
276
|
return;
|
|
277
277
|
}
|
|
@@ -284,7 +284,7 @@ function ve(y, c = {}) {
|
|
|
284
284
|
...r.state !== void 0 ? { state: r.state } : {}
|
|
285
285
|
};
|
|
286
286
|
ae(e, C, r.signal).then(async (d) => {
|
|
287
|
-
if (x || t !==
|
|
287
|
+
if (x || t !== m || r.signal?.aborted) {
|
|
288
288
|
n({ status: "superseded", revision: t });
|
|
289
289
|
return;
|
|
290
290
|
}
|
|
@@ -296,7 +296,7 @@ function ve(y, c = {}) {
|
|
|
296
296
|
try {
|
|
297
297
|
E = await oe(d.value.svg, C.fonts ?? "embed");
|
|
298
298
|
} catch (i) {
|
|
299
|
-
if (x || t !==
|
|
299
|
+
if (x || t !== m || r.signal?.aborted) {
|
|
300
300
|
n({
|
|
301
301
|
status: r.signal?.aborted ? "aborted" : "superseded",
|
|
302
302
|
revision: t
|
|
@@ -311,7 +311,7 @@ function ve(y, c = {}) {
|
|
|
311
311
|
X(t, $.diagnostics), n({ status: "error", revision: t, error: $ });
|
|
312
312
|
return;
|
|
313
313
|
}
|
|
314
|
-
if (x || t !==
|
|
314
|
+
if (x || t !== m || r.signal?.aborted) {
|
|
315
315
|
n({ status: "superseded", revision: t });
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
@@ -319,17 +319,17 @@ function ve(y, c = {}) {
|
|
|
319
319
|
try {
|
|
320
320
|
W = ge(s, d.value.svg, C.fonts !== "host");
|
|
321
321
|
} catch (i) {
|
|
322
|
-
const $ = i instanceof Error ? i.message : "Could not build safe SVG.",
|
|
323
|
-
X(t,
|
|
322
|
+
const $ = i instanceof Error ? i.message : "Could not build safe SVG.", M = K("internal", "DRAFT_VIEWER_DOM", $);
|
|
323
|
+
X(t, M.diagnostics), n({ status: "error", revision: t, error: M });
|
|
324
324
|
return;
|
|
325
325
|
}
|
|
326
326
|
const U = [];
|
|
327
327
|
try {
|
|
328
328
|
for (const i of E)
|
|
329
|
-
|
|
329
|
+
N.has(i.key) || (s.fonts.add(i.face), N.set(i.key, i.face), U.push(i));
|
|
330
330
|
} catch (i) {
|
|
331
|
-
for (const { key:
|
|
332
|
-
s.fonts.delete(Z),
|
|
331
|
+
for (const { key: M, face: Z } of U)
|
|
332
|
+
s.fonts.delete(Z), N.delete(M);
|
|
333
333
|
const $ = K(
|
|
334
334
|
"environment",
|
|
335
335
|
"DRAFT_FONT_UNAVAILABLE",
|
|
@@ -341,10 +341,10 @@ function ve(y, c = {}) {
|
|
|
341
341
|
const H = !!u;
|
|
342
342
|
u = d.value, o.replaceChildren(W), w.replaceChildren(
|
|
343
343
|
...u.items.map((i) => {
|
|
344
|
-
const $ = s.createElement("li"),
|
|
345
|
-
|
|
344
|
+
const $ = s.createElement("li"), M = s.createElement("button");
|
|
345
|
+
M.type = "button";
|
|
346
346
|
const Z = i.label.trim() || (i.kind === "edge" ? `${i.from ?? "?"} to ${i.to ?? "?"}` : i.id);
|
|
347
|
-
return
|
|
347
|
+
return M.textContent = `${i.kind}: ${Z}`, M.dataset.itemId = i.id, M.addEventListener("click", () => {
|
|
348
348
|
L("itemactivate", {
|
|
349
349
|
id: i.id,
|
|
350
350
|
kind: i.kind,
|
|
@@ -352,23 +352,23 @@ function ve(y, c = {}) {
|
|
|
352
352
|
revision: t
|
|
353
353
|
});
|
|
354
354
|
const O = Array.from(o.querySelectorAll("[data-id]")).find(
|
|
355
|
-
(
|
|
355
|
+
(T) => T.getAttribute("data-id") === i.id
|
|
356
356
|
);
|
|
357
357
|
if (O) {
|
|
358
|
-
const
|
|
359
|
-
(
|
|
360
|
-
centerX: a.centerX + (
|
|
361
|
-
centerY: a.centerY + (
|
|
358
|
+
const T = O.getBoundingClientRect(), I = o.getBoundingClientRect();
|
|
359
|
+
(T.width || T.height) && I.width && I.height && (a = {
|
|
360
|
+
centerX: a.centerX + (T.left + T.width / 2 - (I.left + I.width / 2)) / a.zoom,
|
|
361
|
+
centerY: a.centerY + (T.top + T.height / 2 - (I.top + I.height / 2)) / a.zoom,
|
|
362
362
|
zoom: Math.max(1, a.zoom)
|
|
363
|
-
},
|
|
363
|
+
}, _ = !0, R(), L("camera", { camera: { ...a }, reason: "user" }));
|
|
364
364
|
}
|
|
365
|
-
}), $.append(
|
|
365
|
+
}), $.append(M), $;
|
|
366
366
|
})
|
|
367
367
|
);
|
|
368
368
|
const k = new Set(E.map((i) => i.key));
|
|
369
|
-
for (const [i, $] of
|
|
370
|
-
k.has(i) || (s.fonts.delete($),
|
|
371
|
-
|
|
369
|
+
for (const [i, $] of N)
|
|
370
|
+
k.has(i) || (s.fonts.delete($), N.delete(i));
|
|
371
|
+
l.classList.remove("draft-viewer--stale"), f.textContent = d.diagnostics.map((i) => i.message).join(" "), !H || r.camera === "fit" ? Y() : R();
|
|
372
372
|
const D = {
|
|
373
373
|
status: "committed",
|
|
374
374
|
revision: t,
|
|
@@ -377,7 +377,7 @@ function ve(y, c = {}) {
|
|
|
377
377
|
};
|
|
378
378
|
n(D), L("render", { revision: t, value: u }), L("diagnostics", { revision: t, diagnostics: d.diagnostics, stale: !1 });
|
|
379
379
|
}).catch((d) => {
|
|
380
|
-
if (x || t !==
|
|
380
|
+
if (x || t !== m || r.signal?.aborted) {
|
|
381
381
|
n({
|
|
382
382
|
status: r.signal?.aborted ? "aborted" : "superseded",
|
|
383
383
|
revision: t
|
|
@@ -401,7 +401,7 @@ function ve(y, c = {}) {
|
|
|
401
401
|
},
|
|
402
402
|
getCamera: () => ({ ...a }),
|
|
403
403
|
setCamera(e) {
|
|
404
|
-
x || !Number.isFinite(e.centerX) || !Number.isFinite(e.centerY) || !Number.isFinite(e.zoom) || e.zoom <= 0 || (a = { ...e },
|
|
404
|
+
x || !Number.isFinite(e.centerX) || !Number.isFinite(e.centerY) || !Number.isFinite(e.zoom) || e.zoom <= 0 || (a = { ...e }, _ = !0, R(), L("camera", { camera: { ...a }, reason: "api" }));
|
|
405
405
|
},
|
|
406
406
|
fit: () => {
|
|
407
407
|
x || Y();
|
|
@@ -415,18 +415,18 @@ function ve(y, c = {}) {
|
|
|
415
415
|
},
|
|
416
416
|
destroy() {
|
|
417
417
|
if (!x) {
|
|
418
|
-
if (x = !0,
|
|
418
|
+
if (x = !0, m++, A) {
|
|
419
419
|
try {
|
|
420
420
|
o.releasePointerCapture(A.pointerId);
|
|
421
421
|
} catch {
|
|
422
422
|
}
|
|
423
423
|
A = void 0;
|
|
424
424
|
}
|
|
425
|
-
for (const [e, r] of
|
|
425
|
+
for (const [e, r] of B)
|
|
426
426
|
r.resolve({ status: "destroyed", revision: e });
|
|
427
|
-
|
|
428
|
-
for (const e of
|
|
429
|
-
|
|
427
|
+
B.clear(), z(new Error("Viewer was destroyed."));
|
|
428
|
+
for (const e of N.values()) s.fonts.delete(e);
|
|
429
|
+
N.clear(), J.disconnect(), G.clear(), y.replaceChildren(), u = void 0;
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@draftably/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Portable native Draftably SVG rendering, validation, and optional viewer.",
|
|
6
6
|
"type": "module",
|
|
@@ -34,9 +34,6 @@
|
|
|
34
34
|
},
|
|
35
35
|
"./package.json": "./package.json"
|
|
36
36
|
},
|
|
37
|
-
"scripts": {
|
|
38
|
-
"build": "node ../../scripts/build-runtime.ts"
|
|
39
|
-
},
|
|
40
37
|
"engines": {
|
|
41
38
|
"node": ">=22.21.0"
|
|
42
39
|
},
|
|
@@ -48,5 +45,8 @@
|
|
|
48
45
|
"publishConfig": {
|
|
49
46
|
"access": "public",
|
|
50
47
|
"registry": "https://registry.npmjs.org"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "node ../../scripts/build-runtime.ts"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|