@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.
@@ -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-BOAZBzVa.js";
2
- import { f as Ee, a as ke } from "./render-BOAZBzVa.js";
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 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))
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(`${m}:${b}`, { family: m, weight: b });
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 m of Array.from(s.querySelectorAll("style"))) {
26
- const b = m.textContent ?? "";
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 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 });
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((m) => {
33
- const b = v.get(`${m.family}:${m.weight}`);
34
- if (!b) throw new Error(`Embedded font ${m.family} ${m.weight} is missing.`);
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 m = new Set(
43
- Array.from(v.querySelectorAll("[id]"), (l) => l.getAttribute("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 = (l) => {
47
- if (++b > s || !le.has(l.localName))
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, l.localName);
50
- for (const { name: p, value: f } of Array.from(l.attributes)) {
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 (l.localName !== "a") continue;
53
+ if (f.localName !== "a") continue;
54
54
  try {
55
- const a = new URL(f, y.baseURI);
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 = [...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);
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
- l.localName === "a" && w.getAttribute("target") === "_blank" && w.setAttribute("rel", "noopener noreferrer");
66
- for (const p of Array.from(l.childNodes))
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 f = p.nodeValue ?? "";
69
+ const m = p.nodeValue ?? "";
70
70
  w.append(
71
71
  y.createTextNode(
72
- l.localName === "style" && V ? f.replace(/@font-face\s*\{[^{}]*\}/g, "") : f
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, m = s.createElement("section");
95
- m.className = "draft-viewer", m.setAttribute("aria-label", c.label ?? "Diagram viewer");
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 l = s.createElement("p");
101
- l.className = "draft-viewer__status", l.setAttribute("role", "status"), l.setAttribute("aria-live", "polite");
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"), m.append(b, o, l, w), y.append(m);
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 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) => {
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
- }, T = !1, R(), L("camera", { camera: { ...a }, reason: e });
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)), T = !0, R(), L("camera", { camera: { ...a }, reason: "user" });
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, T = !0, R(), L("camera", { camera: { ...a }, reason: "user" });
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 || (T ? R() : Y("resize"));
141
+ u && !o.getBoundingClientRect().width || (_ ? R() : Y("resize"));
142
142
  });
143
143
  J.observe(o);
144
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 });
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 = M.get(h);
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 = 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;
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 = B;
185
- i?.id === n && (B = void 0, v.clearTimeout(i.timer), i.cleanup()), D ? g(D) : S(k);
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-BpUp6NY_.js", import.meta.url).href,
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
- B = { id: n, timer: D, finish: d, cleanup: C }, F.postMessage({ id: n, source: e, options: r });
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, T = !0, R());
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: f });
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 q)
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 = ++f;
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), 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;
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 === f && (c.execution ?? { mode: "worker" }).mode === "worker" && z(new Error("Viewer render was aborted.")), n({ status: "aborted", revision: 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 (q.set(t, { resolve: n }), r.signal?.aborted) {
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 !== f || r.signal?.aborted) {
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 !== f || r.signal?.aborted) {
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 !== f || r.signal?.aborted) {
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.", N = K("internal", "DRAFT_VIEWER_DOM", $);
323
- X(t, N.diagnostics), n({ status: "error", revision: t, error: N });
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
- M.has(i.key) || (s.fonts.add(i.face), M.set(i.key, i.face), U.push(i));
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: N, face: Z } of U)
332
- s.fonts.delete(Z), M.delete(N);
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"), N = s.createElement("button");
345
- N.type = "button";
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 N.textContent = `${i.kind}: ${Z}`, N.dataset.itemId = i.id, N.addEventListener("click", () => {
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
- (_) => _.getAttribute("data-id") === i.id
355
+ (T) => T.getAttribute("data-id") === i.id
356
356
  );
357
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,
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
- }, T = !0, R(), L("camera", { camera: { ...a }, reason: "user" }));
363
+ }, _ = !0, R(), L("camera", { camera: { ...a }, reason: "user" }));
364
364
  }
365
- }), $.append(N), $;
365
+ }), $.append(M), $;
366
366
  })
367
367
  );
368
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();
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 !== f || r.signal?.aborted) {
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 }, T = !0, R(), L("camera", { camera: { ...a }, reason: "api" }));
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, f++, A) {
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 q)
425
+ for (const [e, r] of B)
426
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;
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.1.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
+ }