@brftech/filex-core 0.13.0 → 0.13.2

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.
Files changed (49) hide show
  1. package/dist/{ArchiveViewer-Brzg_0Xj.js → ArchiveViewer-CxdOyBhs.js} +35 -36
  2. package/dist/ArchiveViewer-CxdOyBhs.js.map +1 -0
  3. package/dist/{CsvViewer-T7W9mqZB.js → CsvViewer-JG3nzTgf.js} +52 -53
  4. package/dist/CsvViewer-JG3nzTgf.js.map +1 -0
  5. package/dist/{DrawioViewer-DReOOHRc.js → DrawioViewer-BEYLdtPG.js} +22 -23
  6. package/dist/{DrawioViewer-DReOOHRc.js.map → DrawioViewer-BEYLdtPG.js.map} +1 -1
  7. package/dist/{EpubViewer-yf9zJXXg.js → EpubViewer-BwUDmJm4.js} +31 -32
  8. package/dist/EpubViewer-BwUDmJm4.js.map +1 -0
  9. package/dist/{IpynbViewer-Dt_l00CD.js → IpynbViewer-CuHQoAHU.js} +35 -35
  10. package/dist/IpynbViewer-CuHQoAHU.js.map +1 -0
  11. package/dist/{MermaidViewer-Nbv27ana.js → MermaidViewer-DLmijDXo.js} +47 -48
  12. package/dist/MermaidViewer-DLmijDXo.js.map +1 -0
  13. package/dist/{PsdViewer-1nRpsuvz.js → PsdViewer-D-FM4eNi.js} +38 -39
  14. package/dist/PsdViewer-D-FM4eNi.js.map +1 -0
  15. package/dist/{TiffViewer-Djawe0Rq.js → TiffViewer-DOw4z_dO.js} +36 -37
  16. package/dist/TiffViewer-DOw4z_dO.js.map +1 -0
  17. package/dist/{Viewer3D-D7EtANiH.js → Viewer3D-CJJJgkuv.js} +15 -16
  18. package/dist/{Viewer3D-D7EtANiH.js.map → Viewer3D-CJJJgkuv.js.map} +1 -1
  19. package/dist/filex-core.js +11942 -66
  20. package/dist/filex-core.js.map +1 -1
  21. package/dist/filex-core.umd.cjs +29 -29
  22. package/dist/filex-core.umd.cjs.map +1 -1
  23. package/dist/style.css +1 -1
  24. package/package.json +1 -1
  25. package/src/components/PresenceBar.vue +13 -5
  26. package/src/components/RecentlyOpened.vue +9 -1
  27. package/src/components/StarButton.vue +9 -1
  28. package/src/components/TagPicker.vue +9 -1
  29. package/src/modals/ConvertModal.vue +10 -2
  30. package/src/modals/PermissionsModal.vue +9 -1
  31. package/src/viewers/ArchiveViewer.vue +9 -1
  32. package/src/viewers/CsvViewer.vue +9 -1
  33. package/src/viewers/DrawioViewer.vue +9 -1
  34. package/src/viewers/EpubViewer.vue +9 -1
  35. package/src/viewers/IpynbViewer.vue +9 -1
  36. package/src/viewers/MermaidViewer.vue +10 -2
  37. package/src/viewers/PdfViewer.vue +9 -1
  38. package/src/viewers/PsdViewer.vue +9 -1
  39. package/src/viewers/TiffViewer.vue +9 -1
  40. package/src/viewers/Viewer3D.vue +10 -2
  41. package/dist/ArchiveViewer-Brzg_0Xj.js.map +0 -1
  42. package/dist/CsvViewer-T7W9mqZB.js.map +0 -1
  43. package/dist/EpubViewer-yf9zJXXg.js.map +0 -1
  44. package/dist/IpynbViewer-Dt_l00CD.js.map +0 -1
  45. package/dist/MermaidViewer-Nbv27ana.js.map +0 -1
  46. package/dist/PsdViewer-1nRpsuvz.js.map +0 -1
  47. package/dist/TiffViewer-Djawe0Rq.js.map +0 -1
  48. package/dist/index-DeVgQCwW.js +0 -11951
  49. package/dist/index-DeVgQCwW.js.map +0 -1
@@ -1,12 +1,11 @@
1
- import { defineComponent as U, ref as n, onMounted as L, onBeforeUnmount as V, watch as F, openBlock as u, createElementBlock as i, createElementVNode as c, toDisplayString as b, Fragment as H, createCommentVNode as g } from "vue";
2
- import { _ as R } from "./index-DeVgQCwW.js";
1
+ import { defineComponent as U, ref as r, onMounted as L, onBeforeUnmount as F, watch as H, openBlock as u, createElementBlock as i, createElementVNode as c, toDisplayString as g, Fragment as R, createCommentVNode as b } from "vue";
3
2
  const S = {
4
3
  key: 0,
5
4
  class: "filex-viewer-fallback"
6
- }, z = {
5
+ }, V = {
7
6
  key: 0,
8
7
  class: "filex-viewer-epub__nav"
9
- }, A = ["disabled"], D = ["disabled"], N = {
8
+ }, z = ["disabled"], A = ["disabled"], D = {
10
9
  key: 1,
11
10
  class: "filex-viewer-epub__loading"
12
11
  }, T = /* @__PURE__ */ U({
@@ -20,11 +19,11 @@ const S = {
20
19
  authCredentials: {}
21
20
  },
22
21
  setup(k) {
23
- const r = k, x = n(null), v = n(null), o = n(null), E = n([]);
24
- n(!1);
25
- const B = n(100), s = n(!1), f = n(!0);
22
+ const n = k, x = r(null), v = r(null), o = r(null), E = r([]);
23
+ r(!1);
24
+ const B = r(100), s = r(!1), f = r(!0);
26
25
  let a = null, e = null;
27
- async function p() {
26
+ async function y() {
28
27
  f.value = !0, s.value = !1, o.value = null;
29
28
  let t = null;
30
29
  try {
@@ -33,16 +32,16 @@ const S = {
33
32
  "epubjs"
34
33
  );
35
34
  } catch {
36
- o.value = r.t ? r.t("viewer.peer_not_installed") : "EPUB viewer requires `epubjs` — install or use download.", f.value = !1;
35
+ o.value = n.t ? n.t("viewer.peer_not_installed") : "EPUB viewer requires `epubjs` — install or use download.", f.value = !1;
37
36
  return;
38
37
  }
39
38
  try {
40
39
  const l = t.default ?? t;
41
- let m = r.url;
42
- if (r.authHeaders) {
43
- const P = r.authHeaders(), d = await fetch(r.url, {
40
+ let m = n.url;
41
+ if (n.authHeaders) {
42
+ const P = n.authHeaders(), d = await fetch(n.url, {
44
43
  headers: P,
45
- credentials: r.authCredentials || "same-origin"
44
+ credentials: n.authCredentials || "same-origin"
46
45
  });
47
46
  if (!d.ok) throw new Error(`${d.status} ${d.statusText}`);
48
47
  m = await d.arrayBuffer();
@@ -63,7 +62,7 @@ const S = {
63
62
  f.value = !1;
64
63
  }
65
64
  }
66
- function y() {
65
+ function p() {
67
66
  var t;
68
67
  (t = e == null ? void 0 : e.next) == null || t.call(e);
69
68
  }
@@ -72,11 +71,11 @@ const S = {
72
71
  (t = e == null ? void 0 : e.prev) == null || t.call(e);
73
72
  }
74
73
  function h(t) {
75
- t.key === "ArrowRight" || t.key === "PageDown" ? y() : (t.key === "ArrowLeft" || t.key === "PageUp") && _();
74
+ t.key === "ArrowRight" || t.key === "PageDown" ? p() : (t.key === "ArrowLeft" || t.key === "PageUp") && _();
76
75
  }
77
76
  L(() => {
78
- p(), window.addEventListener("keydown", h);
79
- }), V(() => {
77
+ y(), window.addEventListener("keydown", h);
78
+ }), F(() => {
80
79
  var t, l;
81
80
  window.removeEventListener("keydown", h);
82
81
  try {
@@ -88,8 +87,8 @@ const S = {
88
87
  } catch {
89
88
  }
90
89
  e = null, a = null;
91
- }), F(
92
- () => r.url,
90
+ }), H(
91
+ () => n.url,
93
92
  () => {
94
93
  if (e)
95
94
  try {
@@ -101,11 +100,11 @@ const S = {
101
100
  a.destroy();
102
101
  } catch {
103
102
  }
104
- a = null, e = null, p();
103
+ a = null, e = null, y();
105
104
  }
106
105
  );
107
106
  function C(t, l) {
108
- return r.t ? r.t(t) : l;
107
+ return n.t ? n.t(t) : l;
109
108
  }
110
109
  return (t, l) => (u(), i("div", {
111
110
  ref_key: "root",
@@ -114,33 +113,33 @@ const S = {
114
113
  }, [
115
114
  o.value ? (u(), i("div", S, [
116
115
  l[0] || (l[0] = c("span", { class: "filex-viewer-fallback__icon" }, "📖", -1)),
117
- c("p", null, b(o.value), 1)
118
- ])) : (u(), i(H, { key: 1 }, [
116
+ c("p", null, g(o.value), 1)
117
+ ])) : (u(), i(R, { key: 1 }, [
119
118
  c("div", {
120
119
  ref_key: "containerRef",
121
120
  ref: v,
122
121
  class: "filex-viewer-epub__rendition"
123
122
  }, null, 512),
124
- s.value ? (u(), i("div", z, [
123
+ s.value ? (u(), i("div", V, [
125
124
  c("button", {
126
125
  type: "button",
127
126
  class: "filex-viewer-btn",
128
127
  onClick: _,
129
128
  disabled: !s.value
130
- }, "‹", 8, A),
129
+ }, "‹", 8, z),
131
130
  c("button", {
132
131
  type: "button",
133
132
  class: "filex-viewer-btn",
134
- onClick: y,
133
+ onClick: p,
135
134
  disabled: !s.value
136
- }, "›", 8, D)
137
- ])) : g("", !0),
138
- f.value ? (u(), i("div", N, b(C("viewer.loading", "Loading…")), 1)) : g("", !0)
135
+ }, "›", 8, A)
136
+ ])) : b("", !0),
137
+ f.value ? (u(), i("div", D, g(C("viewer.loading", "Loading…")), 1)) : b("", !0)
139
138
  ], 64))
140
139
  ], 512));
141
140
  }
142
- }), q = /* @__PURE__ */ R(T, [["__scopeId", "data-v-12eb7133"]]);
141
+ });
143
142
  export {
144
- q as default
143
+ T as default
145
144
  };
146
- //# sourceMappingURL=EpubViewer-yf9zJXXg.js.map
145
+ //# sourceMappingURL=EpubViewer-BwUDmJm4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EpubViewer-BwUDmJm4.js","sources":["../src/viewers/EpubViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * EpubViewer — flowable EPUB reader via `epubjs`.\n *\n * Lazy-imports `epubjs` (~80 KB gzipped). epub.js renders the publication\n * inside an iframe (default `flow: 'paginated'`), but we use it in\n * scrolled-doc mode only when the user toggles the \"fit-width\" flag — by\n * default we keep paginated since that matches reader-app expectations.\n *\n * UX:\n * - prev/next page buttons (also keyboard arrow keys via composable)\n * - collapsible TOC sidebar (built from `book.loaded.navigation`)\n * - font size +/- (Themes API)\n * - graceful fallback if peer not installed\n */\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\n\nconst props = defineProps<{\n url: string;\n mime?: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string>;\n authCredentials?: RequestCredentials;\n}>();\n\ninterface TocNode {\n href: string;\n label: string;\n subitems?: TocNode[];\n}\n\nconst root = ref<HTMLDivElement | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nconst error = ref<string | null>(null);\nconst toc = ref<TocNode[]>([]);\nconst tocOpen = ref(false);\nconst fontSize = ref(100);\nconst ready = ref(false);\nconst loading = ref(true);\n\nlet book: any = null;\nlet rendition: any = null;\n\nasync function load(): Promise<void> {\n loading.value = true;\n ready.value = false;\n error.value = null;\n let mod: any = null;\n try {\n mod = await import(/* @vite-ignore */ 'epubjs');\n } catch {\n error.value = props.t\n ? props.t('viewer.peer_not_installed')\n : 'EPUB viewer requires `epubjs` — install or use download.';\n loading.value = false;\n return;\n }\n try {\n const Epub = mod.default ?? mod;\n // epub.js wants a URL (it then fetches with XHR). When the host\n // site requires auth headers we have to load the file ourselves\n // and pass an ArrayBuffer instead.\n let source: string | ArrayBuffer = props.url;\n if (props.authHeaders) {\n const headers = props.authHeaders();\n const res = await fetch(props.url, {\n headers,\n credentials: props.authCredentials || 'same-origin',\n });\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\n source = await res.arrayBuffer();\n }\n book = Epub(source);\n if (!containerRef.value) {\n throw new Error('EPUB mount target missing');\n }\n rendition = book.renderTo(containerRef.value, {\n width: '100%',\n height: '100%',\n flow: 'paginated',\n manager: 'default',\n });\n await rendition.display();\n rendition.themes.fontSize(fontSize.value + '%');\n const nav = await book.loaded.navigation;\n toc.value = (nav?.toc ?? []) as TocNode[];\n ready.value = true;\n } catch (err) {\n error.value =\n err instanceof Error ? err.message : 'EPUB load failed';\n } finally {\n loading.value = false;\n }\n}\n\nfunction next(): void {\n rendition?.next?.();\n}\nfunction prev(): void {\n rendition?.prev?.();\n}\nfunction gotoHref(href: string): void {\n rendition?.display?.(href);\n tocOpen.value = false;\n}\nfunction bigger(): void {\n fontSize.value = Math.min(200, fontSize.value + 10);\n rendition?.themes?.fontSize(fontSize.value + '%');\n}\nfunction smaller(): void {\n fontSize.value = Math.max(60, fontSize.value - 10);\n rendition?.themes?.fontSize(fontSize.value + '%');\n}\n\nfunction onKey(ev: KeyboardEvent): void {\n if (ev.key === 'ArrowRight' || ev.key === 'PageDown') next();\n else if (ev.key === 'ArrowLeft' || ev.key === 'PageUp') prev();\n}\n\nonMounted(() => {\n load();\n window.addEventListener('keydown', onKey);\n});\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', onKey);\n try {\n rendition?.destroy?.();\n } catch {\n /* ignore */\n }\n try {\n book?.destroy?.();\n } catch {\n /* ignore */\n }\n rendition = null;\n book = null;\n});\n\nwatch(\n () => props.url,\n () => {\n if (rendition) {\n try {\n rendition.destroy();\n } catch {\n /* ignore */\n }\n }\n if (book) {\n try {\n book.destroy();\n } catch {\n /* ignore */\n }\n }\n book = null;\n rendition = null;\n load();\n },\n);\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n</script>\n\n<template>\n <div ref=\"root\" class=\"filex-viewer-epub\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">📖</span>\n <p>{{ error }}</p>\n </div>\n <template v-else>\n <div ref=\"containerRef\" class=\"filex-viewer-epub__rendition\" />\n <div v-if=\"ready\" class=\"filex-viewer-epub__nav\">\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"prev\" :disabled=\"!ready\">‹</button>\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"next\" :disabled=\"!ready\">›</button>\n </div>\n <div v-if=\"loading\" class=\"filex-viewer-epub__loading\">\n {{ tt('viewer.loading', 'Loading…') }}\n </div>\n </template>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-epub__nav {\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n gap: 8px;\n padding: 4px 8px;\n background: var(--fe-bg-elev, rgba(255, 255, 255, 0.9));\n border: 1px solid var(--fe-border, #e2e6ed);\n border-radius: 6px;\n backdrop-filter: blur(4px);\n}\n.filex-viewer-epub {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n position: relative;\n}\n.filex-viewer-epub__bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 13px;\n}\n.filex-viewer-spacer { flex: 1; }\n.filex-viewer-epub__fs {\n display: inline-block;\n min-width: 40px;\n text-align: center;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-epub__main {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n.filex-viewer-epub__rendition {\n flex: 1;\n min-height: 0;\n}\n.filex-viewer-epub__toc {\n width: 260px;\n border-right: 1px solid var(--fe-border, #e2e6ed);\n overflow-y: auto;\n padding: 12px 0;\n background: var(--fe-bg-elev, #f7f8fa);\n}\n.filex-viewer-epub__toc ul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.filex-viewer-epub__toc-link {\n display: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: 0;\n padding: 6px 14px;\n font: inherit;\n color: inherit;\n cursor: pointer;\n}\n.filex-viewer-epub__toc-link:hover {\n background: var(--fe-bg-hover, #edf0f5);\n}\n.filex-viewer-epub__toc-link.is-child {\n padding-left: 28px;\n color: var(--fe-text-muted, #5a6475);\n font-size: 12px;\n}\n.filex-viewer-epub__loading {\n position: absolute;\n inset: auto 0 0 0;\n text-align: center;\n padding: 6px;\n background: rgba(0, 0, 0, 0.05);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n.filex-viewer-btn {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-btn:hover:not(:disabled) {\n background: var(--fe-bg-hover, #edf0f5);\n}\n.filex-viewer-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n</style>\n"],"names":["props","__props","root","ref","containerRef","error","toc","fontSize","ready","loading","book","rendition","load","mod","Epub","source","headers","res","nav","err","next","_a","prev","onKey","ev","onMounted","onBeforeUnmount","_b","watch","tt","key","fallback","_createElementBlock","_openBlock","_hoisted_1","_cache","_createElementVNode","_Fragment","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_toDisplayString"],"mappings":"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"}
@@ -1,22 +1,22 @@
1
- import { defineComponent as J, ref as _, onMounted as R, onBeforeUnmount as U, watch as D, computed as q, openBlock as a, createElementBlock as r, createElementVNode as d, toDisplayString as p, Fragment as h, renderList as E, createCommentVNode as V } from "vue";
1
+ import { defineComponent as J, ref as _, onMounted as R, onBeforeUnmount as U, watch as D, computed as q, openBlock as a, createElementBlock as r, createElementVNode as d, toDisplayString as p, Fragment as h, renderList as E, createCommentVNode as B } from "vue";
2
2
  import { f as z } from "./useViewerFetch-czqbd2Lj.js";
3
- import { e as G, _ as K } from "./index-DeVgQCwW.js";
4
- const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pane" }, W = {
3
+ import { ensureHighlight as G } from "./filex-core.js";
4
+ const K = { class: "filex-viewer-ipynb" }, P = { class: "filex-viewer-ipynb__pane" }, Q = {
5
5
  key: 0,
6
6
  class: "filex-viewer-fallback"
7
- }, X = {
7
+ }, W = {
8
8
  key: 1,
9
9
  class: "filex-viewer-fallback"
10
- }, Y = { key: 2 }, Z = ["data-type"], ee = { class: "filex-viewer-ipynb__exec" }, te = { class: "filex-viewer-ipynb__src hljs" }, ne = ["innerHTML"], ae = { key: 1 }, re = {
10
+ }, X = { key: 2 }, Y = ["data-type"], Z = { class: "filex-viewer-ipynb__exec" }, ee = { class: "filex-viewer-ipynb__src hljs" }, te = ["innerHTML"], ne = { key: 1 }, ae = {
11
11
  key: 0,
12
12
  class: "filex-viewer-ipynb__outputs"
13
- }, le = ["src", "alt"], ie = ["innerHTML"], se = ["data-type"], ue = ["innerHTML"], oe = {
13
+ }, re = ["src", "alt"], le = ["innerHTML"], ie = ["data-type"], se = ["innerHTML"], ue = {
14
14
  key: 1,
15
15
  class: "filex-viewer-ipynb__md-raw"
16
- }, ce = {
16
+ }, oe = {
17
17
  key: 2,
18
18
  class: "filex-viewer-ipynb__src"
19
- }, de = /* @__PURE__ */ J({
19
+ }, _e = /* @__PURE__ */ J({
20
20
  __name: "IpynbViewer",
21
21
  props: {
22
22
  url: {},
@@ -25,10 +25,10 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
25
25
  authHeaders: { type: Function },
26
26
  authCredentials: {}
27
27
  },
28
- setup(B) {
29
- const u = B, o = _([]), M = _("python"), f = _(null), y = _(!0), w = _(/* @__PURE__ */ new Map()), k = _(/* @__PURE__ */ new Map());
28
+ setup(N) {
29
+ const u = N, o = _([]), M = _("python"), f = _(null), y = _(!0), w = _(/* @__PURE__ */ new Map()), k = _(/* @__PURE__ */ new Map());
30
30
  let v = 0, x = null, g = null;
31
- async function N() {
31
+ async function V() {
32
32
  if (g !== null) return g || null;
33
33
  try {
34
34
  const e = await import(
@@ -44,7 +44,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
44
44
  return Array.isArray(e) ? e.join("") : e ?? "";
45
45
  }
46
46
  async function H() {
47
- var i, m, C, S;
47
+ var i, m, I, S;
48
48
  y.value = !0, f.value = null, o.value = [], w.value = /* @__PURE__ */ new Map(), k.value = /* @__PURE__ */ new Map();
49
49
  const e = ++v;
50
50
  let t;
@@ -66,7 +66,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
66
66
  f.value = "Invalid notebook JSON", y.value = !1;
67
67
  return;
68
68
  }
69
- if (o.value = Array.isArray(n.cells) ? n.cells : [], M.value = ((C = (m = n.metadata) == null ? void 0 : m.kernelspec) == null ? void 0 : C.language) || "python", x = await G(), e !== v) return;
69
+ if (o.value = Array.isArray(n.cells) ? n.cells : [], M.value = ((I = (m = n.metadata) == null ? void 0 : m.kernelspec) == null ? void 0 : I.language) || "python", x = await G(), e !== v) return;
70
70
  if (x) {
71
71
  const l = x.default ?? x, b = (S = l.getLanguage) != null && S.call(l, M.value) ? M.value : null;
72
72
  o.value.forEach((j, F) => {
@@ -80,7 +80,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
80
80
  }
81
81
  });
82
82
  }
83
- const c = await N();
83
+ const c = await V();
84
84
  e === v && (c && o.value.forEach((l, b) => {
85
85
  if (l.cell_type === "markdown")
86
86
  try {
@@ -104,7 +104,7 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
104
104
  }
105
105
  return null;
106
106
  }
107
- function I(e) {
107
+ function C(e) {
108
108
  return e != null && e.data && e.data["text/html"] ? s(e.data["text/html"]).replace(/<script[\s\S]*?<\/script>/gi, "") : null;
109
109
  }
110
110
  R(H), U(() => {
@@ -116,60 +116,60 @@ const P = { class: "filex-viewer-ipynb" }, Q = { class: "filex-viewer-ipynb__pan
116
116
  function $(e, t) {
117
117
  return u.t ? u.t(e) : t;
118
118
  }
119
- return (e, t) => (a(), r("div", P, [
120
- d("div", Q, [
121
- f.value ? (a(), r("div", W, [
119
+ return (e, t) => (a(), r("div", K, [
120
+ d("div", P, [
121
+ f.value ? (a(), r("div", Q, [
122
122
  t[0] || (t[0] = d("span", { class: "filex-viewer-fallback__icon" }, "📓", -1)),
123
123
  d("p", null, p(f.value), 1)
124
- ])) : y.value ? (a(), r("div", X, [
124
+ ])) : y.value ? (a(), r("div", W, [
125
125
  t[1] || (t[1] = d("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
126
126
  d("p", null, p($("viewer.loading", "Loading…")), 1)
127
- ])) : (a(), r("div", Y, [
127
+ ])) : (a(), r("div", X, [
128
128
  (a(!0), r(h, null, E(o.value, (n, c) => (a(), r("div", {
129
129
  key: c,
130
130
  class: "filex-viewer-ipynb__cell",
131
131
  "data-type": n.cell_type
132
132
  }, [
133
133
  n.cell_type === "code" ? (a(), r(h, { key: 0 }, [
134
- d("div", ee, " In [" + p(n.execution_count ?? " ") + "]: ", 1),
135
- d("pre", te, [
134
+ d("div", Z, " In [" + p(n.execution_count ?? " ") + "]: ", 1),
135
+ d("pre", ee, [
136
136
  w.value.get(c) ? (a(), r("code", {
137
137
  key: 0,
138
138
  innerHTML: w.value.get(c)
139
- }, null, 8, ne)) : (a(), r("code", ae, p(s(n.source)), 1))
139
+ }, null, 8, te)) : (a(), r("code", ne, p(s(n.source)), 1))
140
140
  ]),
141
- n.outputs && n.outputs.length ? (a(), r("div", re, [
141
+ n.outputs && n.outputs.length ? (a(), r("div", ae, [
142
142
  (a(!0), r(h, null, E(n.outputs, (i, m) => (a(), r(h, { key: m }, [
143
143
  L(i) ? (a(), r("img", {
144
144
  key: 0,
145
145
  src: L(i) || "",
146
146
  class: "filex-viewer-ipynb__img",
147
147
  alt: `output ${m}`
148
- }, null, 8, le)) : I(i) ? (a(), r("div", {
148
+ }, null, 8, re)) : C(i) ? (a(), r("div", {
149
149
  key: 1,
150
150
  class: "filex-viewer-ipynb__html",
151
- innerHTML: I(i)
152
- }, null, 8, ie)) : T(i) ? (a(), r("pre", {
151
+ innerHTML: C(i)
152
+ }, null, 8, le)) : T(i) ? (a(), r("pre", {
153
153
  key: 2,
154
154
  class: "filex-viewer-ipynb__out",
155
155
  "data-type": i.output_type
156
- }, p(T(i)), 9, se)) : V("", !0)
156
+ }, p(T(i)), 9, ie)) : B("", !0)
157
157
  ], 64))), 128))
158
- ])) : V("", !0)
158
+ ])) : B("", !0)
159
159
  ], 64)) : n.cell_type === "markdown" ? (a(), r(h, { key: 1 }, [
160
160
  k.value.get(c) ? (a(), r("div", {
161
161
  key: 0,
162
162
  class: "filex-viewer-ipynb__md",
163
163
  innerHTML: k.value.get(c)
164
- }, null, 8, ue)) : (a(), r("pre", oe, p(s(n.source)), 1))
165
- ], 64)) : (a(), r("pre", ce, p(s(n.source)), 1))
166
- ], 8, Z))), 128))
164
+ }, null, 8, se)) : (a(), r("pre", ue, p(s(n.source)), 1))
165
+ ], 64)) : (a(), r("pre", oe, p(s(n.source)), 1))
166
+ ], 8, Y))), 128))
167
167
  ]))
168
168
  ])
169
169
  ]));
170
170
  }
171
- }), ye = /* @__PURE__ */ K(de, [["__scopeId", "data-v-eece712d"]]);
171
+ });
172
172
  export {
173
- ye as default
173
+ _e as default
174
174
  };
175
- //# sourceMappingURL=IpynbViewer-Dt_l00CD.js.map
175
+ //# sourceMappingURL=IpynbViewer-CuHQoAHU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IpynbViewer-CuHQoAHU.js","sources":["../src/viewers/IpynbViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * IpynbViewer — Jupyter notebook (.ipynb JSON) renderer.\n *\n * Pure-JS render — no peer dependency required:\n * - code cells → `<pre><code>` (highlight.js when available)\n * - markdown cells → markdown-it when available, plain `<pre>` otherwise\n * - output cells → text (stream / display_data 'text/plain'),\n * images (display_data 'image/png' base64),\n * HTML (display_data 'text/html', sanitized via\n * element-only insertion — no script tags)\n *\n * Source list / output count counters at the top so a 200-cell\n * notebook doesn't surprise the user.\n */\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { fetchViewerText } from '../composables/useViewerFetch';\nimport { ensureHighlight } from '../composables/useMonacoLoader';\n\nconst props = defineProps<{\n url: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string>;\n authCredentials?: RequestCredentials;\n}>();\n\ninterface Cell {\n cell_type: 'code' | 'markdown' | 'raw' | string;\n source: string | string[];\n outputs?: any[];\n execution_count?: number | null;\n metadata?: Record<string, unknown>;\n}\n\ninterface Notebook {\n cells: Cell[];\n metadata?: { kernelspec?: { language?: string; name?: string } };\n}\n\nconst cells = ref<Cell[]>([]);\nconst language = ref<string>('python');\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst renderedSources = ref<Map<number, string>>(new Map());\nconst renderedMarkdown = ref<Map<number, string>>(new Map());\n\nlet renderToken = 0;\nlet highlight: any = null;\nlet mdRenderer: any = null;\n\nasync function ensureMd(): Promise<any | null> {\n if (mdRenderer !== null) return mdRenderer || null;\n try {\n const mod = await import(/* @vite-ignore */ 'markdown-it');\n const Md = (mod as any).default ?? mod;\n mdRenderer = new Md({ html: false, linkify: true, breaks: true });\n return mdRenderer;\n } catch {\n mdRenderer = false;\n return null;\n }\n}\n\nfunction joinSource(source: string | string[]): string {\n return Array.isArray(source) ? source.join('') : (source ?? '');\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n cells.value = [];\n renderedSources.value = new Map();\n renderedMarkdown.value = new Map();\n const myToken = ++renderToken;\n\n let raw: string;\n try {\n raw = await fetchViewerText({\n url: props.url,\n headers: props.authHeaders?.() ?? {},\n credentials: props.authCredentials,\n });\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'fetch failed';\n loading.value = false;\n return;\n }\n\n if (myToken !== renderToken) return;\n\n let nb: Notebook;\n try {\n nb = JSON.parse(raw);\n } catch (err) {\n error.value = 'Invalid notebook JSON';\n loading.value = false;\n return;\n }\n cells.value = Array.isArray(nb.cells) ? nb.cells : [];\n language.value = nb.metadata?.kernelspec?.language || 'python';\n\n // Best-effort hljs highlight per code cell.\n highlight = (await ensureHighlight()) as any;\n if (myToken !== renderToken) return;\n if (highlight) {\n const hljs = highlight.default ?? highlight;\n const langOk = hljs.getLanguage?.(language.value) ? language.value : null;\n cells.value.forEach((cell, idx) => {\n if (cell.cell_type === 'code') {\n const text = joinSource(cell.source);\n try {\n const result = langOk\n ? hljs.highlight(text, { language: langOk, ignoreIllegals: true })\n : hljs.highlightAuto(text);\n renderedSources.value.set(idx, result.value);\n } catch {\n /* leave unrendered */\n }\n }\n });\n }\n\n const md = await ensureMd();\n if (myToken !== renderToken) return;\n if (md) {\n cells.value.forEach((cell, idx) => {\n if (cell.cell_type === 'markdown') {\n try {\n renderedMarkdown.value.set(idx, md.render(joinSource(cell.source)));\n } catch {\n /* leave plain */\n }\n }\n });\n }\n\n loading.value = false;\n}\n\nfunction outputText(out: any): string | null {\n if (!out) return null;\n if (out.output_type === 'stream') {\n return joinSource(out.text);\n }\n if (out.output_type === 'error') {\n return [out.ename, out.evalue, ...(out.traceback || [])]\n .filter(Boolean)\n .join('\\n');\n }\n if (out.output_type === 'execute_result' || out.output_type === 'display_data') {\n if (out.data?.['text/plain']) {\n return joinSource(out.data['text/plain']);\n }\n }\n return null;\n}\n\nfunction outputImage(out: any): string | null {\n if (!out?.data) return null;\n if (out.data['image/png']) return `data:image/png;base64,${out.data['image/png']}`;\n if (out.data['image/jpeg']) return `data:image/jpeg;base64,${out.data['image/jpeg']}`;\n if (out.data['image/svg+xml']) {\n const svg = joinSource(out.data['image/svg+xml']);\n return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;\n }\n return null;\n}\n\nfunction outputHtml(out: any): string | null {\n if (!out?.data) return null;\n if (out.data['text/html']) {\n const html = joinSource(out.data['text/html']);\n // Strip <script> for safety — outputs from arbitrary notebooks.\n return html.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\n }\n return null;\n}\n\nonMounted(load);\nonBeforeUnmount(() => {\n renderToken++;\n});\nwatch(() => props.url, load);\n\nconst stats = computed(() => {\n const codeCount = cells.value.filter((c) => c.cell_type === 'code').length;\n const mdCount = cells.value.filter((c) => c.cell_type === 'markdown').length;\n return { code: codeCount, md: mdCount, total: cells.value.length };\n});\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n</script>\n\n<template>\n <div class=\"filex-viewer-ipynb\">\n <div class=\"filex-viewer-ipynb__pane\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">📓</span>\n <p>{{ error }}</p>\n </div>\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <div v-else>\n <div\n v-for=\"(cell, idx) in cells\"\n :key=\"idx\"\n class=\"filex-viewer-ipynb__cell\"\n :data-type=\"cell.cell_type\"\n >\n <template v-if=\"cell.cell_type === 'code'\">\n <div class=\"filex-viewer-ipynb__exec\">\n In [{{ cell.execution_count ?? ' ' }}]:\n </div>\n <pre class=\"filex-viewer-ipynb__src hljs\"><code\n v-if=\"renderedSources.get(idx)\"\n v-html=\"renderedSources.get(idx)\"\n /><code v-else>{{ joinSource(cell.source) }}</code></pre>\n <div v-if=\"cell.outputs && cell.outputs.length\" class=\"filex-viewer-ipynb__outputs\">\n <template v-for=\"(out, j) in cell.outputs\" :key=\"j\">\n <img\n v-if=\"outputImage(out)\"\n :src=\"outputImage(out) || ''\"\n class=\"filex-viewer-ipynb__img\"\n :alt=\"`output ${j}`\"\n />\n <div\n v-else-if=\"outputHtml(out)\"\n class=\"filex-viewer-ipynb__html\"\n v-html=\"outputHtml(out)\"\n />\n <pre\n v-else-if=\"outputText(out)\"\n class=\"filex-viewer-ipynb__out\"\n :data-type=\"out.output_type\"\n >{{ outputText(out) }}</pre>\n </template>\n </div>\n </template>\n\n <template v-else-if=\"cell.cell_type === 'markdown'\">\n <div\n v-if=\"renderedMarkdown.get(idx)\"\n class=\"filex-viewer-ipynb__md\"\n v-html=\"renderedMarkdown.get(idx)\"\n />\n <pre v-else class=\"filex-viewer-ipynb__md-raw\">{{ joinSource(cell.source) }}</pre>\n </template>\n\n <template v-else>\n <pre class=\"filex-viewer-ipynb__src\">{{ joinSource(cell.source) }}</pre>\n </template>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-ipynb {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n}\n.filex-viewer-ipynb__bar {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-ipynb__lang {\n font-family: var(--fe-font-mono, monospace);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n.filex-viewer-ipynb__pane {\n flex: 1;\n overflow: auto;\n padding: 16px 24px;\n}\n.filex-viewer-ipynb__cell {\n border: 1px solid var(--fe-border, #e2e6ed);\n border-radius: 6px;\n margin-bottom: 16px;\n overflow: hidden;\n}\n.filex-viewer-ipynb__cell[data-type=\"code\"] {\n background: var(--fe-bg-elev, #f7f8fa);\n}\n.filex-viewer-ipynb__exec {\n padding: 4px 12px;\n font-family: var(--fe-font-mono, monospace);\n font-size: 11px;\n color: var(--fe-text-muted, #5a6475);\n background: rgba(0, 0, 0, 0.04);\n}\n.filex-viewer-ipynb__src {\n margin: 0;\n padding: 12px;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n overflow-x: auto;\n}\n.filex-viewer-ipynb__outputs {\n border-top: 1px dashed var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n padding: 8px 12px;\n}\n.filex-viewer-ipynb__out {\n margin: 0;\n padding: 4px 0;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n.filex-viewer-ipynb__out[data-type=\"error\"] {\n color: var(--fe-danger, #dc2626);\n}\n.filex-viewer-ipynb__img {\n display: block;\n max-width: 100%;\n height: auto;\n margin: 8px 0;\n}\n.filex-viewer-ipynb__html {\n font-size: 13px;\n}\n.filex-viewer-ipynb__md {\n padding: 12px 16px;\n font-size: 14px;\n line-height: 1.6;\n}\n.filex-viewer-ipynb__md-raw {\n padding: 12px;\n margin: 0;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n white-space: pre-wrap;\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n</style>\n"],"names":["props","__props","cells","ref","language","error","loading","renderedSources","renderedMarkdown","renderToken","highlight","mdRenderer","ensureMd","mod","Md","joinSource","source","load","myToken","raw","fetchViewerText","_a","err","nb","_c","_b","ensureHighlight","hljs","langOk","_d","cell","idx","text","result","md","outputText","out","outputImage","svg","outputHtml","onMounted","onBeforeUnmount","watch","computed","codeCount","c","mdCount","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_cache","_hoisted_4","_hoisted_5","_Fragment","_renderList","_hoisted_7","_hoisted_8","_hoisted_10","_toDisplayString","_hoisted_11","j","_hoisted_14","_hoisted_16","_hoisted_17"],"mappings":"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"}
@@ -1,13 +1,12 @@
1
- import { defineComponent as L, ref as u, onMounted as T, onBeforeUnmount as $, openBlock as _, createElementBlock as x, createElementVNode as c, toDisplayString as k, createCommentVNode as B, withDirectives as H, normalizeStyle as Y, vShow as q } from "vue";
1
+ import { defineComponent as T, ref as u, onMounted as V, onBeforeUnmount as $, openBlock as h, createElementBlock as x, createElementVNode as c, toDisplayString as k, createCommentVNode as B, withDirectives as H, normalizeStyle as Y, vShow as q } from "vue";
2
2
  import { f as z } from "./useViewerFetch-czqbd2Lj.js";
3
- import { _ as F } from "./index-DeVgQCwW.js";
4
- const I = { class: "filex-viewer-mermaid" }, K = {
3
+ const F = { class: "filex-viewer-mermaid" }, K = {
5
4
  key: 0,
6
5
  class: "filex-viewer-fallback"
7
6
  }, N = {
8
7
  key: 1,
9
8
  class: "filex-viewer-fallback"
10
- }, U = /* @__PURE__ */ L({
9
+ }, X = /* @__PURE__ */ T({
11
10
  __name: "MermaidViewer",
12
11
  props: {
13
12
  url: {},
@@ -18,17 +17,17 @@ const I = { class: "filex-viewer-mermaid" }, K = {
18
17
  authCredentials: {}
19
18
  },
20
19
  setup(M) {
21
- const a = M, d = u(null), n = u(null), s = u(!0), m = u(1), v = u(0), p = u(0);
22
- let y = !1, l = null, f = 0, i = null;
20
+ const r = M, d = u(null), a = u(null), s = u(!0), m = u(1), v = u(0), y = u(0);
21
+ let p = !1, l = null, f = 0, i = null;
23
22
  async function P() {
24
23
  var e, t;
25
24
  if (i) return i;
26
25
  try {
27
- const r = await import(
26
+ const n = await import(
28
27
  /* @vite-ignore */
29
28
  "mermaid"
30
29
  );
31
- return i = r.default ?? r, (t = i.initialize) == null || t.call(i, {
30
+ return i = n.default ?? n, (t = i.initialize) == null || t.call(i, {
32
31
  startOnLoad: !1,
33
32
  securityLevel: "strict",
34
33
  theme: (e = window.matchMedia) != null && e.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "default"
@@ -37,92 +36,92 @@ const I = { class: "filex-viewer-mermaid" }, K = {
37
36
  return null;
38
37
  }
39
38
  }
40
- async function b() {
39
+ async function C() {
41
40
  var g;
42
- s.value = !0, n.value = null;
41
+ s.value = !0, a.value = null;
43
42
  const e = ++f, t = await P();
44
43
  if (e !== f) return;
45
44
  if (!t) {
46
- n.value = a.t ? a.t("viewer.peer_not_installed") : "Mermaid viewer requires `mermaid` — install or use download.", s.value = !1;
45
+ a.value = r.t ? r.t("viewer.peer_not_installed") : "Mermaid viewer requires `mermaid` — install or use download.", s.value = !1;
47
46
  return;
48
47
  }
49
- let r;
48
+ let n;
50
49
  try {
51
- r = await z({
52
- url: a.url,
53
- headers: ((g = a.authHeaders) == null ? void 0 : g.call(a)) ?? {},
54
- credentials: a.authCredentials
50
+ n = await z({
51
+ url: r.url,
52
+ headers: ((g = r.authHeaders) == null ? void 0 : g.call(r)) ?? {},
53
+ credentials: r.authCredentials
55
54
  });
56
55
  } catch (o) {
57
- n.value = o instanceof Error ? o.message : "fetch failed", s.value = !1;
56
+ a.value = o instanceof Error ? o.message : "fetch failed", s.value = !1;
58
57
  return;
59
58
  }
60
59
  if (e === f)
61
60
  try {
62
- const o = `filex-mermaid-${Date.now()}`, { svg: V } = await t.render(o, r);
61
+ const o = `filex-mermaid-${Date.now()}`, { svg: L } = await t.render(o, n);
63
62
  if (e !== f) return;
64
63
  if (d.value) {
65
- d.value.innerHTML = V;
64
+ d.value.innerHTML = L;
66
65
  const w = d.value.querySelector("svg");
67
66
  w && (w.style.maxWidth = "100%", w.style.height = "auto");
68
67
  }
69
68
  } catch (o) {
70
- n.value = o instanceof Error ? o.message : "render failed";
69
+ a.value = o instanceof Error ? o.message : "render failed";
71
70
  } finally {
72
71
  s.value = !1;
73
72
  }
74
73
  }
75
- function C(e) {
74
+ function D(e) {
76
75
  if (!e.ctrlKey && !e.metaKey) return;
77
76
  e.preventDefault();
78
- const r = -e.deltaY > 0 ? 1.1 : 1 / 1.1;
79
- m.value = Math.max(0.2, Math.min(8, m.value * r));
80
- }
81
- function D(e) {
82
- var t, r;
83
- y = !0, l = { x: e.clientX, y: e.clientY, tx: v.value, ty: p.value }, (r = (t = e.target).setPointerCapture) == null || r.call(t, e.pointerId);
77
+ const n = -e.deltaY > 0 ? 1.1 : 1 / 1.1;
78
+ m.value = Math.max(0.2, Math.min(8, m.value * n));
84
79
  }
85
80
  function E(e) {
86
- !y || !l || (v.value = l.tx + (e.clientX - l.x), p.value = l.ty + (e.clientY - l.y));
81
+ var t, n;
82
+ p = !0, l = { x: e.clientX, y: e.clientY, tx: v.value, ty: y.value }, (n = (t = e.target).setPointerCapture) == null || n.call(t, e.pointerId);
83
+ }
84
+ function S(e) {
85
+ !p || !l || (v.value = l.tx + (e.clientX - l.x), y.value = l.ty + (e.clientY - l.y));
87
86
  }
88
- function h() {
89
- y = !1, l = null;
87
+ function _() {
88
+ p = !1, l = null;
90
89
  }
91
- T(b), $(() => {
90
+ V(C), $(() => {
92
91
  f++;
93
92
  });
94
- function S(e, t) {
95
- return a.t ? a.t(e) : t;
93
+ function b(e, t) {
94
+ return r.t ? r.t(e) : t;
96
95
  }
97
- return (e, t) => (_(), x("div", I, [
96
+ return (e, t) => (h(), x("div", F, [
98
97
  c("div", {
99
98
  class: "filex-viewer-mermaid__pane",
100
- onWheel: C,
101
- onPointerdown: D,
102
- onPointermove: E,
103
- onPointerup: h,
104
- onPointercancel: h
99
+ onWheel: D,
100
+ onPointerdown: E,
101
+ onPointermove: S,
102
+ onPointerup: _,
103
+ onPointercancel: _
105
104
  }, [
106
- n.value ? (_(), x("div", K, [
105
+ a.value ? (h(), x("div", K, [
107
106
  t[0] || (t[0] = c("span", { class: "filex-viewer-fallback__icon" }, "📊", -1)),
108
- c("p", null, k(n.value), 1)
109
- ])) : s.value ? (_(), x("div", N, [
107
+ c("p", null, k(a.value), 1)
108
+ ])) : s.value ? (h(), x("div", N, [
110
109
  t[1] || (t[1] = c("span", { class: "filex-viewer-fallback__icon" }, "⏳", -1)),
111
- c("p", null, k(S("viewer.loading", "Loading…")), 1)
110
+ c("p", null, k(b("viewer.loading", "Loading…")), 1)
112
111
  ])) : B("", !0),
113
112
  H(c("div", {
114
113
  ref_key: "surface",
115
114
  ref: d,
116
115
  class: "filex-viewer-mermaid__surface",
117
- style: Y({ transform: `translate(${v.value}px, ${p.value}px) scale(${m.value})` })
116
+ style: Y({ transform: `translate(${v.value}px, ${y.value}px) scale(${m.value})` })
118
117
  }, null, 4), [
119
- [q, !s.value && !n.value]
118
+ [q, !s.value && !a.value]
120
119
  ])
121
120
  ], 32)
122
121
  ]));
123
122
  }
124
- }), j = /* @__PURE__ */ F(U, [["__scopeId", "data-v-939eea2b"]]);
123
+ });
125
124
  export {
126
- j as default
125
+ X as default
127
126
  };
128
- //# sourceMappingURL=MermaidViewer-Nbv27ana.js.map
127
+ //# sourceMappingURL=MermaidViewer-DLmijDXo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MermaidViewer-DLmijDXo.js","sources":["../src/viewers/MermaidViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * MermaidViewer — render a `.mmd` / `.mermaid` source file.\n *\n * Lazy-imports the `mermaid` library (~150 KB gzipped). Source text is\n * fetched from `props.url` (with the auth headers from PreviewModal),\n * then rendered to SVG via `mermaid.render('id', src)`. The resulting\n * SVG node is inserted into a wrapper that supports pan + scale via\n * pure CSS transforms (no extra panzoom dep).\n */\nimport { onBeforeUnmount, onMounted, ref } from 'vue';\nimport { fetchViewerText } from '../composables/useViewerFetch';\n\nconst props = defineProps<{\n url: string;\n mime?: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string>;\n authCredentials?: RequestCredentials;\n}>();\n\nconst surface = ref<HTMLDivElement | null>(null);\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst scale = ref(1);\nconst tx = ref(0);\nconst ty = ref(0);\n\nlet dragging = false;\nlet dragStart: { x: number; y: number; tx: number; ty: number } | null = null;\nlet renderToken = 0;\n\nlet cachedMermaid: any = null;\nasync function ensureMermaid(): Promise<any | null> {\n if (cachedMermaid) return cachedMermaid;\n try {\n const mod = await import(/* @vite-ignore */ 'mermaid');\n cachedMermaid = mod.default ?? mod;\n cachedMermaid.initialize?.({\n startOnLoad: false,\n securityLevel: 'strict',\n theme: window.matchMedia?.('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'default',\n });\n return cachedMermaid;\n } catch {\n return null;\n }\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n const myToken = ++renderToken;\n\n const mermaid = await ensureMermaid();\n if (myToken !== renderToken) return;\n if (!mermaid) {\n error.value = props.t\n ? props.t('viewer.peer_not_installed')\n : 'Mermaid viewer requires `mermaid` — install or use download.';\n loading.value = false;\n return;\n }\n\n let src: string;\n try {\n src = await fetchViewerText({\n url: props.url,\n headers: props.authHeaders?.() ?? {},\n credentials: props.authCredentials,\n });\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'fetch failed';\n loading.value = false;\n return;\n }\n\n if (myToken !== renderToken) return;\n\n try {\n const id = `filex-mermaid-${Date.now()}`;\n const { svg } = await mermaid.render(id, src);\n if (myToken !== renderToken) return;\n if (surface.value) {\n surface.value.innerHTML = svg;\n const svgEl = surface.value.querySelector('svg');\n if (svgEl) {\n svgEl.style.maxWidth = '100%';\n svgEl.style.height = 'auto';\n }\n }\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'render failed';\n } finally {\n loading.value = false;\n }\n}\n\nfunction zoomIn(): void {\n scale.value = Math.min(8, scale.value * 1.25);\n}\nfunction zoomOut(): void {\n scale.value = Math.max(0.2, scale.value / 1.25);\n}\nfunction reset(): void {\n scale.value = 1;\n tx.value = 0;\n ty.value = 0;\n}\n\nfunction onWheel(ev: WheelEvent): void {\n if (!ev.ctrlKey && !ev.metaKey) return;\n ev.preventDefault();\n const delta = -ev.deltaY;\n const factor = delta > 0 ? 1.1 : 1 / 1.1;\n scale.value = Math.max(0.2, Math.min(8, scale.value * factor));\n}\n\nfunction onPointerDown(ev: PointerEvent): void {\n dragging = true;\n dragStart = { x: ev.clientX, y: ev.clientY, tx: tx.value, ty: ty.value };\n (ev.target as HTMLElement).setPointerCapture?.(ev.pointerId);\n}\nfunction onPointerMove(ev: PointerEvent): void {\n if (!dragging || !dragStart) return;\n tx.value = dragStart.tx + (ev.clientX - dragStart.x);\n ty.value = dragStart.ty + (ev.clientY - dragStart.y);\n}\nfunction onPointerUp(): void {\n dragging = false;\n dragStart = null;\n}\n\nonMounted(load);\nonBeforeUnmount(() => {\n renderToken++;\n});\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n</script>\n\n<template>\n <div class=\"filex-viewer-mermaid\">\n <div\n class=\"filex-viewer-mermaid__pane\"\n @wheel=\"onWheel\"\n @pointerdown=\"onPointerDown\"\n @pointermove=\"onPointerMove\"\n @pointerup=\"onPointerUp\"\n @pointercancel=\"onPointerUp\"\n >\n <div\n v-if=\"error\"\n class=\"filex-viewer-fallback\"\n >\n <span class=\"filex-viewer-fallback__icon\">📊</span>\n <p>{{ error }}</p>\n </div>\n <div\n v-else-if=\"loading\"\n class=\"filex-viewer-fallback\"\n >\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <div\n v-show=\"!loading && !error\"\n ref=\"surface\"\n class=\"filex-viewer-mermaid__surface\"\n :style=\"{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }\"\n />\n </div>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-mermaid {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n}\n.filex-viewer-mermaid__bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 13px;\n}\n.filex-viewer-mermaid__zoom {\n min-width: 50px;\n text-align: center;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n}\n.filex-viewer-mermaid__pane {\n flex: 1;\n overflow: hidden;\n position: relative;\n cursor: grab;\n background: var(--fe-bg-elev, #f7f8fa);\n touch-action: none;\n}\n.filex-viewer-mermaid__pane:active {\n cursor: grabbing;\n}\n.filex-viewer-mermaid__surface {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n transform-origin: center center;\n transition: transform 0.05s linear;\n user-select: none;\n}\n.filex-viewer-mermaid__surface svg {\n max-width: 90%;\n max-height: 90%;\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n.filex-viewer-btn {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-btn:hover:not(:disabled) {\n background: var(--fe-bg-hover, #edf0f5);\n}\n</style>\n"],"names":["props","__props","surface","ref","error","loading","scale","tx","ty","dragging","dragStart","renderToken","cachedMermaid","ensureMermaid","mod","_b","_a","load","myToken","mermaid","src","fetchViewerText","err","id","svg","svgEl","onWheel","ev","factor","onPointerDown","onPointerMove","onPointerUp","onMounted","onBeforeUnmount","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_hoisted_3","_normalizeStyle","_vShow"],"mappings":";;;;;;;;;;;;;;;;;;;AAaA,UAAMA,IAAQC,GASRC,IAAUC,EAA2B,IAAI,GACzCC,IAAQD,EAAmB,IAAI,GAC/BE,IAAUF,EAAI,EAAI,GAClBG,IAAQH,EAAI,CAAC,GACbI,IAAKJ,EAAI,CAAC,GACVK,IAAKL,EAAI,CAAC;AAEhB,QAAIM,IAAW,IACXC,IAAqE,MACrEC,IAAc,GAEdC,IAAqB;AACzB,mBAAeC,IAAqC;;AAClD,UAAID,EAAe,QAAOA;AAC1B,UAAI;AACF,cAAME,IAAM,MAAM;AAAA;AAAA,UAA0B;AAAA,QAAA;AAC5C,eAAAF,IAAgBE,EAAI,WAAWA,IAC/BC,IAAAH,EAAc,eAAd,QAAAG,EAAA,KAAAH,GAA2B;AAAA,UACzB,aAAa;AAAA,UACb,eAAe;AAAA,UACf,QAAOI,IAAA,OAAO,eAAP,QAAAA,EAAA,aAAoB,gCAAgC,UACvD,SACA;AAAA,QAAA,IAECJ;AAAA,MACT,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAEA,mBAAeK,IAAsB;;AACnC,MAAAZ,EAAQ,QAAQ,IAChBD,EAAM,QAAQ;AACd,YAAMc,IAAU,EAAEP,GAEZQ,IAAU,MAAMN,EAAA;AACtB,UAAIK,MAAYP,EAAa;AAC7B,UAAI,CAACQ,GAAS;AACZ,QAAAf,EAAM,QAAQJ,EAAM,IAChBA,EAAM,EAAE,2BAA2B,IACnC,gEACJK,EAAQ,QAAQ;AAChB;AAAA,MACF;AAEA,UAAIe;AACJ,UAAI;AACF,QAAAA,IAAM,MAAMC,EAAgB;AAAA,UAC1B,KAAKrB,EAAM;AAAA,UACX,WAASgB,IAAAhB,EAAM,gBAAN,gBAAAgB,EAAA,KAAAhB,OAAyB,CAAA;AAAA,UAClC,aAAaA,EAAM;AAAA,QAAA,CACpB;AAAA,MACH,SAASsB,GAAK;AACZ,QAAAlB,EAAM,QAAQkB,aAAe,QAAQA,EAAI,UAAU,gBACnDjB,EAAQ,QAAQ;AAChB;AAAA,MACF;AAEA,UAAIa,MAAYP;AAEhB,YAAI;AACF,gBAAMY,IAAK,iBAAiB,KAAK,IAAA,CAAK,IAChC,EAAE,KAAAC,EAAA,IAAQ,MAAML,EAAQ,OAAOI,GAAIH,CAAG;AAC5C,cAAIF,MAAYP,EAAa;AAC7B,cAAIT,EAAQ,OAAO;AACjB,YAAAA,EAAQ,MAAM,YAAYsB;AAC1B,kBAAMC,IAAQvB,EAAQ,MAAM,cAAc,KAAK;AAC/C,YAAIuB,MACFA,EAAM,MAAM,WAAW,QACvBA,EAAM,MAAM,SAAS;AAAA,UAEzB;AAAA,QACF,SAASH,GAAK;AACZ,UAAAlB,EAAM,QAAQkB,aAAe,QAAQA,EAAI,UAAU;AAAA,QACrD,UAAA;AACE,UAAAjB,EAAQ,QAAQ;AAAA,QAClB;AAAA,IACF;AAcA,aAASqB,EAAQC,GAAsB;AACrC,UAAI,CAACA,EAAG,WAAW,CAACA,EAAG,QAAS;AAChC,MAAAA,EAAG,eAAA;AAEH,YAAMC,IADQ,CAACD,EAAG,SACK,IAAI,MAAM,IAAI;AACrC,MAAArB,EAAM,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,GAAGA,EAAM,QAAQsB,CAAM,CAAC;AAAA,IAC/D;AAEA,aAASC,EAAcF,GAAwB;;AAC7C,MAAAlB,IAAW,IACXC,IAAY,EAAE,GAAGiB,EAAG,SAAS,GAAGA,EAAG,SAAS,IAAIpB,EAAG,OAAO,IAAIC,EAAG,MAAA,IAChEO,KAAAC,IAAAW,EAAG,QAAuB,sBAA1B,QAAAZ,EAAA,KAAAC,GAA8CW,EAAG;AAAA,IACpD;AACA,aAASG,EAAcH,GAAwB;AAC7C,MAAI,CAAClB,KAAY,CAACC,MAClBH,EAAG,QAAQG,EAAU,MAAMiB,EAAG,UAAUjB,EAAU,IAClDF,EAAG,QAAQE,EAAU,MAAMiB,EAAG,UAAUjB,EAAU;AAAA,IACpD;AACA,aAASqB,IAAoB;AAC3B,MAAAtB,IAAW,IACXC,IAAY;AAAA,IACd;AAEA,IAAAsB,EAAUf,CAAI,GACdgB,EAAgB,MAAM;AACpB,MAAAtB;AAAA,IACF,CAAC;AAED,aAASuB,EAAGC,GAAaC,GAA0B;AACjD,aAAOpC,EAAM,IAAIA,EAAM,EAAEmC,CAAG,IAAIC;AAAA,IAClC;sBAIEC,EAAA,GAAAC,EA8BM,OA9BNC,GA8BM;AAAA,MA7BJC,EA4BM,OAAA;AAAA,QA3BJ,OAAM;AAAA,QACL,SAAAd;AAAA,QACA,eAAaG;AAAA,QACb,eAAaC;AAAA,QACb,aAAWC;AAAA,QACX,iBAAeA;AAAA,MAAA;QAGR3B,EAAA,SADRiC,EAAA,GAAAC,EAMM,OANNG,GAMM;AAAA,UAFJC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAF,EAAmD,QAAA,EAA7C,OAAM,8BAAA,GAA8B,MAAE,EAAA;AAAA,UAC5CA,EAAkB,aAAZpC,EAAA,KAAK,GAAA,CAAA;AAAA,QAAA,MAGAC,EAAA,SADbgC,KAAAC,EAMM,OANNK,GAMM;AAAA,UAFJD,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAF,EAAkD,QAAA,EAA5C,OAAM,8BAAA,GAA8B,KAAC,EAAA;AAAA,UAC3CA,EAA6C,aAAvCN,EAAE,kBAAA,UAAA,CAAA,GAAA,CAAA;AAAA,QAAA;UAEVM,EAKE,OAAA;AAAA,mBAHI;AAAA,UAAJ,KAAItC;AAAA,UACJ,OAAM;AAAA,UACL,OAAK0C,EAAA,EAAA,WAAA,aAA4BrC,EAAA,KAAE,OAAOC,EAAA,KAAE,aAAaF,EAAA,KAAK,KAAA;AAAA,QAAA;UAHtD,CAAAuC,GAAA,CAAAxC,EAAA,UAAYD,EAAA,KAAK;AAAA,QAAA;;;;;"}