@floegence/floe-webapp-core 0.86.74 → 0.86.75

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,10 @@
1
1
  import { type Component } from 'solid-js';
2
+ import { type DiagramLabels } from '../../../diagrams/Diagram';
3
+ import '../../../styles/diagrams.css';
2
4
  export interface MermaidBlockProps {
3
5
  content: string;
4
6
  class?: string;
7
+ labels?: DiagramLabels;
5
8
  }
9
+ /** Existing public component, now backed by the shared diagram surface. */
6
10
  export declare const MermaidBlock: Component<MermaidBlockProps>;
@@ -1,200 +1,25 @@
1
- import { insert as a, memo as k, createComponent as u, effect as D, className as ae, Portal as ce, setStyleProperty as W, template as o, delegateEvents as se } from "solid-js/web";
2
- import { createSignal as h, createEffect as O, onCleanup as R, Show as de } from "solid-js";
3
- import { cn as ue } from "../../../utils/cn.js";
4
- import { renderMermaid as me } from "../hooks/useMermaid.js";
5
- import { lockBodyStyle as he } from "../../../utils/bodyStyleLock.js";
6
- import { deferNonBlocking as pe } from "../../../utils/defer.js";
7
- var fe = /* @__PURE__ */ o("<div>"), ge = /* @__PURE__ */ o("<div class=chat-image-dialog-backdrop>"), ye = /* @__PURE__ */ o('<div class=chat-image-dialog><div class=chat-image-dialog-toolbar><button type=button class=chat-image-dialog-btn title="Zoom out (-)"></button><span class=chat-image-dialog-scale>%</span><button type=button class=chat-image-dialog-btn title="Zoom in (+)"></button><button type=button class=chat-image-dialog-btn title="Reset (0)"></button><div class=chat-image-dialog-separator></div><button type=button class=chat-image-dialog-btn title="Close (Esc)"></button></div><div class=chat-image-dialog-content style=touch-action:none><div class=chat-mermaid-dialog-svg></div></div><div class=chat-image-dialog-hint>Scroll/pinch to zoom · Drag to pan · Press Esc to close'), ve = /* @__PURE__ */ o("<div class=chat-mermaid-loading><span>Rendering diagram..."), xe = /* @__PURE__ */ o("<div class=chat-mermaid-error><span>"), $e = /* @__PURE__ */ o('<div class="chat-mermaid-content chat-mermaid-clickable">'), be = /* @__PURE__ */ o('<svg class="animate-spin h-5 w-5"viewBox="0 0 24 24"fill=none><circle class=opacity-25 cx=12 cy=12 r=10 stroke=currentColor stroke-width=4></circle><path class=opacity-75 fill=currentColor d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z">'), ke = /* @__PURE__ */ o('<svg width=16 height=16 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><circle cx=12 cy=12 r=10></circle><line x1=12 y1=8 x2=12 y2=12></line><line x1=12 y1=16 x2=12.01 y2=16>'), _e = /* @__PURE__ */ o('<svg width=20 height=20 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><line x1=18 y1=6 x2=6 y2=18></line><line x1=6 y1=6 x2=18 y2=18>'), we = /* @__PURE__ */ o('<svg width=20 height=20 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><circle cx=11 cy=11 r=8></circle><line x1=21 y1=21 x2=16.65 y2=16.65></line><line x1=11 y1=8 x2=11 y2=14></line><line x1=8 y1=11 x2=14 y2=11>'), Ce = /* @__PURE__ */ o('<svg width=20 height=20 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><circle cx=11 cy=11 r=8></circle><line x1=21 y1=21 x2=16.65 y2=16.65></line><line x1=8 y1=11 x2=14 y2=11>'), Se = /* @__PURE__ */ o('<svg width=20 height=20 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5">');
8
- const Xe = (T) => {
9
- const [$, X] = h(null), [_, Y] = h(null), [j, b] = h(!0), [w, F] = h(!1), [r, C] = h(1), [y, v] = h({
10
- x: 0,
11
- y: 0
12
- }), [G, d] = h(!1);
13
- let S = 0, p = null, I = {
14
- x: 0,
15
- y: 0
16
- };
17
- const i = /* @__PURE__ */ new Map();
18
- let c = null, s = null, f = 0, x = 1;
19
- const J = 0.5, Q = 5, Z = 0.25, ee = (e) => Math.max(J, Math.min(e, Q)), M = (e) => {
20
- const t = ee(e);
21
- C(t), t <= 1 && (v({
22
- x: 0,
23
- y: 0
24
- }), d(!1));
25
- };
26
- O(() => {
27
- const e = ++S, t = T.content;
28
- if (!t) {
29
- X(null), b(!1);
30
- return;
31
- }
32
- b(!0), Y(null), pe(() => {
33
- me(t).then((n) => {
34
- e === S && (X(n), b(!1));
35
- }).catch((n) => {
36
- e === S && (Y(n.message || "Failed to render diagram"), b(!1));
37
- });
38
- });
39
- });
40
- const te = () => {
41
- C(1), v({
42
- x: 0,
43
- y: 0
44
- }), F(!0);
45
- }, E = () => {
46
- F(!1);
47
- }, L = () => {
48
- M(r() + Z);
49
- }, z = () => {
50
- M(r() - Z);
51
- }, N = () => {
52
- C(1), v({
53
- x: 0,
54
- y: 0
55
- }), d(!1);
56
- }, ne = (e) => {
57
- e.preventDefault(), e.deltaY < 0 ? L() : z();
58
- }, ie = (e) => {
59
- if (e.pointerType === "mouse" && e.button !== 0) return;
60
- e.preventDefault();
61
- const t = e.currentTarget;
62
- i.set(e.pointerId, {
63
- x: e.clientX,
64
- y: e.clientY
65
- });
66
- try {
67
- t.setPointerCapture(e.pointerId);
68
- } catch {
69
- }
70
- if (i.size === 1) {
71
- c = {
72
- x: e.clientX,
73
- y: e.clientY
74
- }, s = {
75
- ...y()
76
- }, d(r() > 1);
77
- return;
78
- }
79
- if (i.size === 2) {
80
- const [n, l] = Array.from(i.values());
81
- f = Math.hypot(n.x - l.x, n.y - l.y), x = r(), c = null, s = null, d(!1);
82
- }
83
- }, re = (e) => {
84
- if (i.has(e.pointerId)) {
85
- if (i.set(e.pointerId, {
86
- x: e.clientX,
87
- y: e.clientY
88
- }), i.size === 2) {
89
- const [t, n] = Array.from(i.values()), l = Math.hypot(t.x - n.x, t.y - n.y);
90
- f > 0 && M(x * (l / f));
91
- return;
92
- }
93
- if (!(i.size !== 1 || r() <= 1) && (d(!0), (!c || !s) && (c = {
94
- x: e.clientX,
95
- y: e.clientY
96
- }, s = {
97
- ...y()
98
- }), I = {
99
- x: s.x + (e.clientX - c.x),
100
- y: s.y + (e.clientY - c.y)
101
- }, p === null)) {
102
- if (typeof requestAnimationFrame > "u") {
103
- v(I);
104
- return;
105
- }
106
- p = requestAnimationFrame(() => {
107
- p = null, !(i.size !== 1 || r() <= 1) && v(I);
108
- });
109
- }
110
- }
111
- }, q = (e) => {
112
- i.delete(e.pointerId);
113
- try {
114
- e.currentTarget.releasePointerCapture(e.pointerId);
115
- } catch {
116
- }
117
- if (i.size === 0) {
118
- d(!1), c = null, s = null, f = 0, x = r();
119
- return;
120
- }
121
- if (i.size === 1) {
122
- const t = Array.from(i.values())[0];
123
- c = {
124
- x: t.x,
125
- y: t.y
126
- }, s = {
127
- ...y()
128
- }, d(r() > 1), f = 0, x = r();
129
- return;
130
- }
131
- if (i.size === 2) {
132
- const [t, n] = Array.from(i.values());
133
- f = Math.hypot(t.x - n.x, t.y - n.y), x = r(), c = null, s = null, d(!1);
134
- }
135
- };
136
- return R(() => {
137
- p !== null && typeof cancelAnimationFrame < "u" && (cancelAnimationFrame(p), p = null), i.clear();
138
- }), O(() => {
139
- if (!w()) return;
140
- const e = (t) => {
141
- t.key === "Escape" ? E() : t.key === "+" || t.key === "=" ? L() : t.key === "-" ? z() : t.key === "0" && N();
142
- };
143
- document.addEventListener("keydown", e), R(() => document.removeEventListener("keydown", e));
144
- }), O(() => {
145
- if (!w()) return;
146
- const e = he({
147
- overflow: "hidden"
148
- });
149
- R(e);
150
- }), [(() => {
151
- var e = fe();
152
- return a(e, (() => {
153
- var t = k(() => !!j());
154
- return () => t() && (() => {
155
- var n = ve(), l = n.firstChild;
156
- return a(n, u(Ie, {}), l), n;
157
- })();
158
- })(), null), a(e, (() => {
159
- var t = k(() => !!_());
160
- return () => t() && (() => {
161
- var n = xe(), l = n.firstChild;
162
- return a(n, u(Me, {}), l), a(l, _), n;
163
- })();
164
- })(), null), a(e, (() => {
165
- var t = k(() => !!($() && !_()));
166
- return () => t() && (() => {
167
- var n = $e();
168
- return n.$$click = te, D(() => n.innerHTML = $()), n;
169
- })();
170
- })(), null), D(() => ae(e, ue("chat-mermaid-block", T.class))), e;
171
- })(), u(de, {
172
- get when() {
173
- return k(() => !!w())() && $();
174
- },
175
- get children() {
176
- return u(ce, {
177
- get children() {
178
- return [(() => {
179
- var e = ge();
180
- return e.$$click = E, e;
181
- })(), (() => {
182
- var e = ye(), t = e.firstChild, n = t.firstChild, l = n.nextSibling, le = l.firstChild, A = l.nextSibling, P = A.nextSibling, oe = P.nextSibling, H = oe.nextSibling, g = t.nextSibling, B = g.firstChild;
183
- return n.$$click = z, a(n, u(ze, {})), a(l, () => Math.round(r() * 100), le), A.$$click = L, a(A, u(Le, {})), P.$$click = N, a(P, u(Ae, {})), H.$$click = E, a(H, u(Ee, {})), g.addEventListener("pointercancel", q), g.$$pointerup = q, g.$$pointermove = re, g.$$pointerdown = ie, g.addEventListener("wheel", ne), D((m) => {
184
- var K = `translate(${y().x}px, ${y().y}px) scale(${r()})`, U = r() > 1 ? G() ? "grabbing" : "grab" : "default", V = $();
185
- return K !== m.e && W(B, "transform", m.e = K), U !== m.t && W(B, "cursor", m.t = U), V !== m.a && (B.innerHTML = m.a = V), m;
186
- }, {
187
- e: void 0,
188
- t: void 0,
189
- a: void 0
190
- }), e;
191
- })()];
192
- }
193
- });
194
- }
195
- })];
196
- }, Ie = () => be(), Me = () => ke(), Ee = () => _e(), Le = () => we(), ze = () => Ce(), Ae = () => Se();
197
- se(["click", "pointerdown", "pointermove", "pointerup"]);
1
+ import { createComponent as a } from "solid-js/web";
2
+ import "solid-js";
3
+ import { Diagram as m, diagramLabelsEnUS as n } from "../../../diagrams/Diagram.js";
4
+ import { renderMermaid as o } from "../hooks/useMermaid.js";
5
+ /* empty css */
6
+ const i = (e, r) => o(e, "default", r).then((t) => ({
7
+ svg: t,
8
+ width: 0,
9
+ height: 0,
10
+ type: "mermaid"
11
+ })), u = (e) => a(m, {
12
+ get source() {
13
+ return e.content;
14
+ },
15
+ get class() {
16
+ return e.class;
17
+ },
18
+ get labels() {
19
+ return e.labels ?? n;
20
+ },
21
+ render: i
22
+ });
198
23
  export {
199
- Xe as MermaidBlock
24
+ u as MermaidBlock
200
25
  };
@@ -1,10 +1,11 @@
1
+ import { type DiagramRenderOptions } from '../../../diagrams/render';
1
2
  /**
2
3
  * Configure the Mermaid worker.
3
4
  * Call this during app initialization to enable worker mode.
4
5
  */
5
6
  export declare function configureMermaidWorker(worker: Worker): Promise<void>;
6
7
  /**
7
- * Configure a synchronous Mermaid renderer (fallback).
8
+ * Configure an explicit host Mermaid renderer.
8
9
  * If you don't use a worker, pass a Mermaid instance directly.
9
10
  */
10
11
  export declare function configureSyncMermaid(mermaid: {
@@ -12,7 +13,7 @@ export declare function configureSyncMermaid(mermaid: {
12
13
  svg: string;
13
14
  }>;
14
15
  }): void;
15
- export declare function renderMermaid(content: string, theme?: string): Promise<string>;
16
+ export declare function renderMermaid(content: string, theme?: string, options?: DiagramRenderOptions): Promise<string>;
16
17
  export declare function useMermaid(): {
17
18
  render: (content: string, theme?: string) => Promise<string>;
18
19
  isLoading: import("solid-js").Accessor<boolean>;
@@ -1,76 +1,79 @@
1
1
  import { secureRandomUUID as w } from "../../../utils/secureRandom.js";
2
- import { createSignal as M } from "solid-js";
3
- let a = null, f = !1, c = null;
4
- const l = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), k = 200;
5
- let u = null, p = 0;
6
- function v(n) {
7
- return a = n, c = new Promise((o) => {
2
+ import { createSignal as y } from "solid-js";
3
+ import { sanitizeDiagramSvg as m, renderDiagram as k } from "../../../diagrams/render.js";
4
+ let a = null, f = !1, d = null;
5
+ const c = /* @__PURE__ */ new Map();
6
+ let l = null, p = 0;
7
+ function D(r) {
8
+ return a = r, d = new Promise((o) => {
8
9
  a.onmessage = (e) => {
9
10
  if ("type" in e.data && e.data.type === "ready") {
10
11
  f = !0, o();
11
12
  return;
12
13
  }
13
- const { id: i, svg: d, error: t } = e.data, r = l.get(i);
14
- r && (l.delete(i), t ? r.reject(new Error(t)) : r.resolve(d));
14
+ const { id: s, svg: n, error: t } = e.data, i = c.get(s);
15
+ i && (c.delete(s), t ? i.reject(new Error(t)) : i.resolve(n));
15
16
  }, a.onerror = (e) => {
16
17
  console.error("Mermaid worker error:", e);
17
18
  };
18
- }), c;
19
+ }), d;
19
20
  }
20
- function I(n) {
21
- u = n;
21
+ function R(r) {
22
+ l = r;
22
23
  }
23
- async function h() {
24
- return a ? f ? !0 : c ? (await c, !0) : !1 : !1;
24
+ async function M() {
25
+ return a ? f ? !0 : d ? (await d, !0) : !1 : !1;
25
26
  }
26
- async function W(n, o = "default") {
27
- const e = `${o}:${n}`, i = s.get(e);
28
- if (i) return i;
29
- if (await h() && a)
30
- return new Promise((t, r) => {
31
- const m = w();
32
- l.set(m, {
27
+ async function v(r, o = "default", e = {}) {
28
+ if (await M() && a)
29
+ return new Promise((n, t) => {
30
+ const i = w();
31
+ c.set(i, {
33
32
  resolve: (g) => {
34
- if (s.size >= k) {
35
- const y = s.keys().next().value;
36
- y && s.delete(y);
33
+ try {
34
+ n(m(g, e.document));
35
+ } catch (u) {
36
+ t(u instanceof Error ? u : new Error(String(u)));
37
37
  }
38
- s.set(e, g), t(g);
39
38
  },
40
- reject: r
41
- }), a.postMessage({ id: m, content: n, theme: o });
39
+ reject: t
40
+ }), a.postMessage({ id: i, content: r, theme: o });
42
41
  });
43
- if (u)
42
+ if (l)
44
43
  try {
45
- const t = `mermaid-sync-${p++}`, { svg: r } = await u.render(t, n);
46
- return s.set(e, r), r;
47
- } catch (t) {
48
- const r = t instanceof Error ? t.message : "Failed to render diagram";
49
- throw new Error(r);
44
+ const n = `mermaid-sync-${p++}`, { svg: t } = await l.render(n, r);
45
+ return m(t, e.document);
46
+ } catch (n) {
47
+ const t = n instanceof Error ? n.message : "Failed to render diagram";
48
+ throw new Error(t);
50
49
  }
51
- throw new Error("Mermaid renderer not configured. Call configureMermaidWorker() or configureSyncMermaid() first.");
50
+ return (await k(r, e)).svg;
52
51
  }
53
- function R() {
54
- const [n, o] = M(!1);
52
+ function S() {
53
+ const [r, o] = y(!1);
55
54
  return {
56
- render: async (i, d) => {
55
+ render: async (s, n) => {
57
56
  o(!0);
58
57
  try {
59
- return await W(i, d);
58
+ return await v(s, n);
60
59
  } finally {
61
60
  o(!1);
62
61
  }
63
62
  },
64
- isLoading: n
63
+ isLoading: r
65
64
  };
66
65
  }
67
- function S() {
68
- a && (a.terminate(), a = null, f = !1, c = null, l.clear()), s.clear();
66
+ function I() {
67
+ if (a) {
68
+ a.terminate(), a = null, f = !1, d = null;
69
+ for (const r of c.values()) r.reject(new Error("Diagram worker terminated."));
70
+ c.clear();
71
+ }
69
72
  }
70
73
  export {
71
- v as configureMermaidWorker,
72
- I as configureSyncMermaid,
73
- W as renderMermaid,
74
- S as terminateMermaidWorker,
75
- R as useMermaid
74
+ D as configureMermaidWorker,
75
+ R as configureSyncMermaid,
76
+ v as renderMermaid,
77
+ I as terminateMermaidWorker,
78
+ S as useMermaid
76
79
  };
@@ -0,0 +1,2 @@
1
+ /** A matching CommonMark fence, independent of whether streaming has ended. */
2
+ export declare function isClosedMarkdownFence(raw: string): boolean;
@@ -0,0 +1,14 @@
1
+ function r(s) {
2
+ const e = s.replace(/\r\n?/g, `
3
+ `).split(`
4
+ `), t = e[0]?.match(/^[ ]{0,3}(\x60{3,}|~{3,})/);
5
+ if (!t) return !1;
6
+ const c = t[1];
7
+ return e.slice(1).some((o) => {
8
+ const n = o.match(/^[ ]{0,3}(\x60+|~+)[ \t]*$/)?.[1];
9
+ return !!n && n[0] === c[0] && n.length >= c.length;
10
+ });
11
+ }
12
+ export {
13
+ r as isClosedMarkdownFence
14
+ };
@@ -0,0 +1,30 @@
1
+ import { type Component } from 'solid-js';
2
+ import { type DiagramRenderOptions, type DiagramRenderResult } from './render';
3
+ export interface DiagramLabels {
4
+ diagram: string;
5
+ loading: string;
6
+ unavailable: string;
7
+ retry: string;
8
+ source: string;
9
+ preview: string;
10
+ copy: string;
11
+ copied: string;
12
+ copyFailed: string;
13
+ expand: string;
14
+ close: string;
15
+ zoomIn: string;
16
+ zoomOut: string;
17
+ fit: string;
18
+ }
19
+ export declare const diagramLabelsEnUS: DiagramLabels;
20
+ export interface DiagramProps {
21
+ source: string;
22
+ labels: DiagramLabels;
23
+ class?: string;
24
+ onCopy?: (source: string) => Promise<void>;
25
+ onOpenLink?: (href: string) => void | Promise<void>;
26
+ /** Explicit renderer injection for existing hosts; never an error fallback. */
27
+ render?: (source: string, options: DiagramRenderOptions) => Promise<DiagramRenderResult>;
28
+ }
29
+ /** Shared diagram controls. The host owns source identity, localization and navigation. */
30
+ export declare const Diagram: Component<DiagramProps>;
@@ -0,0 +1,224 @@
1
+ import { insert as d, memo as V, createComponent as y, mergeProps as H, effect as N, setAttribute as D, className as J, template as S, use as G, setStyleProperty as U, delegateEvents as K } from "solid-js/web";
2
+ import { createSignal as m, onCleanup as Z, Show as O, createMemo as Q, createEffect as j, onMount as X, on as Y } from "solid-js";
3
+ import { Dialog as p } from "../components/ui/Dialog.js";
4
+ import { renderDiagram as ee, sanitizeDiagramSvg as te } from "./render.js";
5
+ var ne = /* @__PURE__ */ S("<div class=floe-diagram-viewport data-floe-workbench-text-selection-surface=true><div class=floe-diagram-svg>"), oe = /* @__PURE__ */ S("<div class=floe-diagram-status role=status>"), re = /* @__PURE__ */ S("<div class=floe-diagram-error role=alert><strong></strong><pre></pre><pre><code>"), ie = /* @__PURE__ */ S("<button type=button>"), ae = /* @__PURE__ */ S("<pre class=floe-diagram-source data-floe-workbench-text-selection-surface=true><code>"), le = /* @__PURE__ */ S("<div class=floe-diagram><div class=floe-diagram-toolbar><button type=button>−</button><button type=button></button><button type=button>+"), se = /* @__PURE__ */ S("<section><div class=floe-diagram-toolbar><button type=button></button><button type=button></button><span class=floe-diagram-feedback role=status></span><button type=button>⤢</button></div><div>");
6
+ const me = {
7
+ diagram: "Diagram",
8
+ loading: "Rendering diagram…",
9
+ unavailable: "Diagram unavailable",
10
+ retry: "Retry",
11
+ source: "Source",
12
+ preview: "Preview",
13
+ copy: "Copy source",
14
+ copied: "Copied",
15
+ copyFailed: "Could not copy",
16
+ expand: "Expand diagram",
17
+ close: "Close",
18
+ zoomIn: "Zoom in",
19
+ zoomOut: "Zoom out",
20
+ fit: "Fit"
21
+ }, B = (e) => {
22
+ let s;
23
+ const [A, R] = m(!1), [T, I] = m(0), [v, P] = m(0), [x, $] = m("loading"), [W, w] = m(""), L = Q(() => e.source);
24
+ j(() => e.onStatus?.(x())), X(() => {
25
+ const o = new ResizeObserver((n) => {
26
+ const l = Math.round(n[0]?.contentRect.width ?? s.clientWidth);
27
+ l > 0 && I(l);
28
+ });
29
+ o.observe(s);
30
+ const r = new IntersectionObserver((n) => {
31
+ n.some((l) => l.isIntersecting) && (R(!0), r.disconnect());
32
+ }, {
33
+ rootMargin: "200px"
34
+ });
35
+ r.observe(s);
36
+ const c = s.ownerDocument.fonts, i = () => P((n) => n + 1);
37
+ c?.addEventListener("loadingdone", i), Z(() => {
38
+ o.disconnect(), r.disconnect(), c?.removeEventListener("loadingdone", i);
39
+ });
40
+ }), j(Y([L, T, A, v, () => e.revision], ([o, r, c]) => {
41
+ if (!c || !r) return;
42
+ const i = new AbortController(), n = s.ownerDocument, l = getComputedStyle(s);
43
+ $("loading"), w("");
44
+ const g = (u) => {
45
+ if (i.signal.aborted || !s.isConnected) return;
46
+ const b = n.getSelection();
47
+ for (let C = 0; b && C < b.rangeCount; C++)
48
+ if (b.getRangeAt(C).intersectsNode(s)) {
49
+ const t = () => {
50
+ n.removeEventListener("selectionchange", t), g(u);
51
+ };
52
+ n.addEventListener("selectionchange", t, {
53
+ once: !0,
54
+ signal: i.signal
55
+ });
56
+ return;
57
+ }
58
+ const f = n.createElement("template");
59
+ f.innerHTML = te(u.svg, n);
60
+ const M = f.content.querySelector("svg");
61
+ M && e.expanded && (M.style.maxWidth = "none"), s.replaceChildren(f.content), $("ready");
62
+ };
63
+ (e.render ?? ee)(o, {
64
+ signal: i.signal,
65
+ maxWidth: r,
66
+ document: n,
67
+ fontFamily: l.fontFamily,
68
+ fontFamilyMono: l.getPropertyValue("--font-mono").trim() || "monospace",
69
+ fontSize: parseFloat(l.fontSize) || 16,
70
+ links: !!e.onOpenLink
71
+ }).then(g).catch((u) => {
72
+ i.signal.aborted || (s.replaceChildren(), w(u instanceof Error ? u.message : String(u)), $("error"));
73
+ }), Z(() => i.abort());
74
+ }));
75
+ const z = (o) => {
76
+ const r = o.target instanceof Element ? o.target.closest("a") : null;
77
+ if (!r) return;
78
+ o.preventDefault();
79
+ const c = r.getAttribute("href");
80
+ !c || !/^(?:https?:\/\/|mailto:)/i.test(c) || !e.onOpenLink || Promise.resolve(e.onOpenLink(c)).catch(() => {
81
+ w(e.labels.unavailable), $("error");
82
+ });
83
+ };
84
+ return [(() => {
85
+ var o = ne(), r = o.firstChild;
86
+ r.$$click = z;
87
+ var c = s;
88
+ return typeof c == "function" ? G(c, r) : s = r, N((i) => {
89
+ var n = e.expanded ? "true" : void 0, l = e.expanded ? "auto" : "hidden", g = !!e.expanded, u = x() === "loading", b = e.scale ?? 1;
90
+ return n !== i.e && D(o, "data-floe-local-interaction-surface", i.e = n), l !== i.t && U(o, "overflow", i.t = l), g !== i.a && r.classList.toggle("floe-diagram-zoomed", i.a = g), u !== i.o && D(r, "aria-busy", i.o = u), b !== i.i && U(r, "--floe-diagram-scale", i.i = b), i;
91
+ }, {
92
+ e: void 0,
93
+ t: void 0,
94
+ a: void 0,
95
+ o: void 0,
96
+ i: void 0
97
+ }), o;
98
+ })(), y(O, {
99
+ get when() {
100
+ return x() === "loading";
101
+ },
102
+ get children() {
103
+ var o = oe();
104
+ return d(o, () => e.labels.loading), o;
105
+ }
106
+ }), y(O, {
107
+ get when() {
108
+ return x() === "error";
109
+ },
110
+ get children() {
111
+ var o = re(), r = o.firstChild, c = r.nextSibling, i = c.nextSibling, n = i.firstChild;
112
+ return d(r, () => e.labels.unavailable), d(c, W), d(n, () => e.source), o;
113
+ }
114
+ })];
115
+ }, fe = (e) => {
116
+ const [s, A] = m(!1), [R, T] = m(!1), [I, v] = m(1), [P, x] = m(0), [$, W] = m("loading"), [w, L] = m("idle");
117
+ let z, o = !1, r;
118
+ Z(() => {
119
+ o = !0, clearTimeout(z);
120
+ });
121
+ const c = async () => {
122
+ try {
123
+ await (e.onCopy ? e.onCopy(e.source) : navigator.clipboard.writeText(e.source)), o || L("copied");
124
+ } catch {
125
+ o || L("error");
126
+ }
127
+ o || (clearTimeout(z), z = setTimeout(() => L("idle"), 1600));
128
+ }, i = (n) => {
129
+ const l = typeof document < "u" ? document.activeElement : null, g = l instanceof Element && !!l.closest('[role="dialog"]');
130
+ T(n), !n && g && r?.isConnected && r.focus({
131
+ preventScroll: !0
132
+ });
133
+ };
134
+ return (() => {
135
+ var n = se(), l = n.firstChild, g = l.firstChild, u = g.nextSibling, b = u.nextSibling, f = b.nextSibling, M = l.nextSibling;
136
+ g.$$click = () => A((t) => !t), d(g, (() => {
137
+ var t = V(() => !!s());
138
+ return () => t() ? e.labels.preview : e.labels.source;
139
+ })()), u.$$click = () => {
140
+ c();
141
+ }, d(u, () => e.labels.copy), d(b, (() => {
142
+ var t = V(() => w() === "copied");
143
+ return () => t() ? e.labels.copied : V(() => w() === "error")() ? e.labels.copyFailed : "";
144
+ })()), d(l, y(O, {
145
+ get when() {
146
+ return $() === "error";
147
+ },
148
+ get children() {
149
+ var t = ie();
150
+ return t.$$click = () => x((h) => h + 1), d(t, () => e.labels.retry), t;
151
+ }
152
+ }), f), f.$$click = () => {
153
+ v(1), T(!0);
154
+ };
155
+ var C = r;
156
+ return typeof C == "function" ? G(C, f) : r = f, d(M, y(B, H(e, {
157
+ get revision() {
158
+ return P();
159
+ },
160
+ onStatus: W
161
+ }))), d(n, y(O, {
162
+ get when() {
163
+ return s();
164
+ },
165
+ get children() {
166
+ var t = ae(), h = t.firstChild;
167
+ return d(h, () => e.source), t;
168
+ }
169
+ }), null), d(n, y(p, {
170
+ get open() {
171
+ return R();
172
+ },
173
+ onOpenChange: i,
174
+ get title() {
175
+ return e.labels.diagram;
176
+ },
177
+ get closeLabel() {
178
+ return e.labels.close;
179
+ },
180
+ class: "floe-diagram-dialog",
181
+ get children() {
182
+ var t = le(), h = t.firstChild, k = h.firstChild, _ = k.nextSibling, F = _.nextSibling;
183
+ return t.$$keydown = (a) => {
184
+ a.target instanceof Element && a.target.closest("button,input,textarea") || ((a.key === "+" || a.key === "=") && (a.preventDefault(), v((E) => Math.min(4, E + 0.25))), a.key === "-" && (a.preventDefault(), v((E) => Math.max(0.5, E - 0.25))), a.key === "0" && (a.preventDefault(), v(1)));
185
+ }, k.$$click = () => v((a) => Math.max(0.5, a - 0.25)), _.$$click = () => v(1), d(_, () => e.labels.fit), F.$$click = () => v((a) => Math.min(4, a + 0.25)), d(t, y(O, {
186
+ get when() {
187
+ return R();
188
+ },
189
+ get children() {
190
+ return y(B, H(e, {
191
+ expanded: !0,
192
+ get scale() {
193
+ return I();
194
+ },
195
+ get revision() {
196
+ return P();
197
+ }
198
+ }));
199
+ }
200
+ }), null), N((a) => {
201
+ var E = e.labels.zoomOut, q = e.labels.zoomIn;
202
+ return E !== a.e && D(k, "aria-label", a.e = E), q !== a.t && D(F, "aria-label", a.t = q), a;
203
+ }, {
204
+ e: void 0,
205
+ t: void 0
206
+ }), t;
207
+ }
208
+ }), null), N((t) => {
209
+ var h = "floe-diagram " + (e.class ?? ""), k = s(), _ = $() !== "ready", F = e.labels.expand, a = s();
210
+ return h !== t.e && J(n, t.e = h), k !== t.t && D(g, "aria-pressed", t.t = k), _ !== t.a && (f.disabled = t.a = _), F !== t.o && D(f, "aria-label", t.o = F), a !== t.i && (M.hidden = t.i = a), t;
211
+ }, {
212
+ e: void 0,
213
+ t: void 0,
214
+ a: void 0,
215
+ o: void 0,
216
+ i: void 0
217
+ }), n;
218
+ })();
219
+ };
220
+ K(["click", "keydown"]);
221
+ export {
222
+ fe as Diagram,
223
+ me as diagramLabelsEnUS
224
+ };
@@ -0,0 +1,27 @@
1
+ export type DiagramErrorCode = 'syntax' | 'semantic' | 'limit' | 'unsupported-diagram' | 'unavailable';
2
+ export declare class DiagramError extends Error {
3
+ readonly code: DiagramErrorCode;
4
+ readonly line: number;
5
+ readonly column: number;
6
+ constructor(code: DiagramErrorCode, message: string, line?: number, column?: number);
7
+ }
8
+ export interface DiagramRenderOptions {
9
+ signal?: AbortSignal;
10
+ /** The owner supplies actual local CSS width, never transformed screen width. */
11
+ maxWidth?: number;
12
+ fontFamily?: string;
13
+ fontFamilyMono?: string;
14
+ fontSize?: number;
15
+ document?: Document;
16
+ /** Links remain inert unless the host explicitly owns navigation. */
17
+ links?: boolean;
18
+ }
19
+ export interface DiagramRenderResult {
20
+ svg: string;
21
+ width: number;
22
+ height: number;
23
+ type: string;
24
+ }
25
+ export declare function sanitizeDiagramSvg(svg: string, doc?: Document): string;
26
+ /** One lazy renderer for all Mermaid syntax surfaces. Never retries another engine. */
27
+ export declare function renderDiagram(source: string, options?: DiagramRenderOptions): Promise<DiagramRenderResult>;
@@ -0,0 +1,107 @@
1
+ import d from "../node_modules/.pnpm/dompurify@3.4.17/node_modules/dompurify/dist/purify.es.js";
2
+ import { secureRandomUUID as y } from "../utils/secureRandom.js";
3
+ class c extends Error {
4
+ constructor(t, l, n = 0, e = 0) {
5
+ super(l), this.code = t, this.line = n, this.column = e, this.name = "DiagramError";
6
+ }
7
+ code;
8
+ line;
9
+ column;
10
+ }
11
+ let p = Promise.resolve(), f = 0;
12
+ const u = (o) => {
13
+ if (o?.aborted) throw new DOMException("Aborted", "AbortError");
14
+ };
15
+ function S(o, t = document) {
16
+ const l = t.defaultView?.DOMParser ?? DOMParser, n = new l().parseFromString(o, "image/svg+xml"), e = [];
17
+ for (const r of Array.from(n.querySelectorAll("foreignObject"))) {
18
+ const i = r.querySelector("math");
19
+ if (!i) {
20
+ r.remove();
21
+ continue;
22
+ }
23
+ const h = t.createElement("template");
24
+ h.innerHTML = d.sanitize(i.outerHTML, { USE_PROFILES: { mathMl: !0 }, FORBID_TAGS: ["annotation-xml"], FORBID_ATTR: ["href", "style"] });
25
+ const g = h.content.querySelector("math");
26
+ if (!g) {
27
+ r.remove();
28
+ continue;
29
+ }
30
+ r.replaceChildren(), r.setAttribute("data-floe-formula", String(e.length)), e.push(g);
31
+ }
32
+ const m = d.sanitize(new XMLSerializer().serializeToString(n.documentElement), {
33
+ USE_PROFILES: { svg: !0, svgFilters: !0, mathMl: !0 },
34
+ ADD_TAGS: ["foreignObject"],
35
+ ADD_ATTR: ["role"],
36
+ FORBID_TAGS: ["script", "style", "image", "iframe", "object", "embed", "animate", "set"]
37
+ }), a = new l().parseFromString(m, "image/svg+xml"), s = a.documentElement;
38
+ if (s.localName !== "svg" || a.querySelector("parsererror")) throw new c("unavailable", "Invalid diagram SVG.");
39
+ for (const r of [s, ...Array.from(s.querySelectorAll("*"))])
40
+ for (const i of Array.from(r.attributes))
41
+ /^on/i.test(i.name) && r.removeAttribute(i.name), i.localName === "href" && !/^(?:#|https?:\/\/|mailto:)/i.test(i.value.trim()) && r.removeAttribute(i.name), /url\s*\(/i.test(i.value) && !/^url\(#[\w-]+\)$/.test(i.value.trim()) && r.removeAttribute(i.name);
42
+ for (const r of Array.from(s.querySelectorAll("foreignObject"))) {
43
+ const i = e[Number(r.getAttribute("data-floe-formula"))];
44
+ r.removeAttribute("data-floe-formula"), i ? r.append(a.importNode(i, !0)) : r.remove();
45
+ }
46
+ return new XMLSerializer().serializeToString(s);
47
+ }
48
+ async function w(o, t, l) {
49
+ if (!o.includes("$$")) return { dispose() {
50
+ } };
51
+ const { default: n } = await import("katex"), e = t.createElement("span");
52
+ return e.style.cssText = "position:fixed;left:-99999px;top:0;visibility:hidden;display:inline-block;white-space:nowrap;", e.style.fontSize = l + "px", t.body.append(e), {
53
+ dispose: () => e.remove(),
54
+ math(m, a) {
55
+ e.style.fontSize = a + "px", e.innerHTML = d.sanitize(n.renderToString(m, { output: "mathml", throwOnError: !0, trust: !1, strict: "error" }), { USE_PROFILES: { html: !0, mathMl: !0 } });
56
+ const s = e.querySelector("math");
57
+ if (!s) throw new c("semantic", "The diagram formula could not be typeset.");
58
+ const { width: r, height: i } = s.getBoundingClientRect();
59
+ return { html: s.outerHTML, width: r, height: i };
60
+ }
61
+ };
62
+ }
63
+ function A(o, t = {}) {
64
+ if (o.length > 5e4 || f >= 128) return Promise.reject(new c("limit", "Diagram rendering limit exceeded."));
65
+ f++;
66
+ const l = p.then(async () => {
67
+ await new Promise((a) => setTimeout(a, 0)), u(t.signal);
68
+ const n = t.document ?? document, { renderAsync: e } = await import("pele/lazy");
69
+ u(t.signal);
70
+ const m = await w(o, n, t.fontSize ?? 16);
71
+ try {
72
+ u(t.signal);
73
+ const a = await e(o, {
74
+ idPrefix: "floe-diagram-" + y(),
75
+ autoDirection: !1,
76
+ maxWidth: t.maxWidth,
77
+ fontFamily: t.fontFamily ?? "Inter, system-ui, sans-serif",
78
+ fontFamilyMono: t.fontFamilyMono ?? "monospace",
79
+ fontSize: t.fontSize ?? 16,
80
+ links: t.links === !0,
81
+ images: !1,
82
+ linkSchemes: ["https", "http", "mailto"],
83
+ linkRel: "noopener noreferrer",
84
+ limit: 5e4,
85
+ maxEdges: 500,
86
+ outputLimit: 4e6,
87
+ math: m.math
88
+ });
89
+ return u(t.signal), { svg: S(a.svg, n), width: a.width, height: a.height, type: a.type };
90
+ } finally {
91
+ m.dispose();
92
+ }
93
+ }).catch((n) => {
94
+ if (n instanceof c || n instanceof DOMException && n.name === "AbortError") throw n;
95
+ const e = n;
96
+ throw new c(e.code ?? "unavailable", e.message ?? "Diagram rendering failed.", e.line, e.column);
97
+ });
98
+ return p = l.catch(() => {
99
+ }).finally(() => {
100
+ f--;
101
+ }), l;
102
+ }
103
+ export {
104
+ c as DiagramError,
105
+ A as renderDiagram,
106
+ S as sanitizeDiagramSvg
107
+ };
@@ -0,0 +1,29 @@
1
+ .floe-diagram {
2
+ --pele-bg: var(--background); --pele-fg: var(--foreground);
3
+ --pele-muted: var(--muted-foreground); --pele-line: var(--muted-foreground);
4
+ --pele-surface: var(--card); --pele-surface-alt: var(--muted);
5
+ --pele-border: var(--border); --pele-accent: var(--primary);
6
+ --pele-font: var(--font-sans, Inter, system-ui, sans-serif);
7
+ --pele-font-mono: var(--font-mono, monospace);
8
+ --pele-fg-on-light: #171717; --pele-fg-on-dark: #fafafa;
9
+ min-width: 0; background:var(--background); color: var(--foreground); font: 14px/1.5 var(--pele-font);
10
+ border: 1px solid var(--border); border-radius: .5rem; overflow: hidden;
11
+ }
12
+ .floe-diagram-toolbar { display:flex; flex-wrap:wrap; align-items:center; gap:.25rem; padding:.375rem; border-bottom:1px solid var(--border); }
13
+ .floe-diagram-toolbar button { font:inherit; white-space:nowrap; border:0; border-radius:.25rem; padding:.25rem .5rem; background:transparent; color:inherit; cursor:pointer; }
14
+ .floe-diagram-toolbar button:hover,.floe-diagram-toolbar button[aria-pressed=true] { background:var(--accent); }
15
+ .floe-diagram-toolbar button:focus-visible { outline:2px solid var(--ring); outline-offset:-2px; }
16
+ .floe-diagram-feedback { flex:1; min-width:0; font-size:.85em; }
17
+ .floe-diagram-viewport { padding:.75rem; min-width:0; max-height:65vh; }
18
+ .floe-diagram-svg { min-height:2rem; width:100%; }
19
+ .floe-diagram-svg > svg { display:block; max-width:100%; height:auto; margin:auto; }
20
+ .floe-diagram-source,.floe-diagram-error pre { white-space:pre-wrap; overflow-wrap:anywhere; margin:0; padding:.75rem; font:12px/1.6 var(--pele-font-mono); }
21
+ .floe-diagram-status,.floe-diagram-error { padding:.75rem; }
22
+ .floe-diagram-error { color:var(--error,var(--foreground)); }
23
+ .floe-diagram-dialog { width:min(94vw,1100px); max-width:94vw; }
24
+ @media (forced-colors:active) { .floe-diagram { --pele-fg:CanvasText; --pele-line:CanvasText; --pele-bg:Canvas; --pele-surface:Canvas; --pele-surface-alt:Canvas; --pele-border:CanvasText; --pele-accent:Highlight; } }
25
+
26
+ .floe-diagram-zoomed > svg { width:calc(100% * var(--floe-diagram-scale,1)); max-width:none; }
27
+ .floe-diagram-toolbar button:disabled { opacity:.5; cursor:default; }
28
+
29
+ .floe-diagram-svg:not(.floe-diagram-zoomed) > svg { max-height:60vh; }
@@ -0,0 +1,4 @@
1
+ export { Diagram, diagramLabelsEnUS } from './diagrams/Diagram';
2
+ export type { DiagramProps, DiagramLabels } from './diagrams/Diagram';
3
+ export { renderDiagram, sanitizeDiagramSvg, DiagramError } from './diagrams/render';
4
+ export type { DiagramRenderOptions, DiagramRenderResult, DiagramErrorCode } from './diagrams/render';
@@ -0,0 +1,9 @@
1
+ import { Diagram as i, diagramLabelsEnUS as m } from "./diagrams/Diagram.js";
2
+ import { DiagramError as g, renderDiagram as o, sanitizeDiagramSvg as D } from "./diagrams/render.js";
3
+ export {
4
+ i as Diagram,
5
+ g as DiagramError,
6
+ m as diagramLabelsEnUS,
7
+ o as renderDiagram,
8
+ D as sanitizeDiagramSvg
9
+ };
@@ -0,0 +1 @@
1
+ .floe-diagram{--pele-bg: var(--background);--pele-fg: var(--foreground);--pele-muted: var(--muted-foreground);--pele-line: var(--muted-foreground);--pele-surface: var(--card);--pele-surface-alt: var(--muted);--pele-border: var(--border);--pele-accent: var(--primary);--pele-font: var(--font-sans, Inter, system-ui, sans-serif);--pele-font-mono: var(--font-mono, monospace);--pele-fg-on-light: #171717;--pele-fg-on-dark: #fafafa;min-width:0;background:var(--background);color:var(--foreground);font:14px/1.5 var(--pele-font);border:1px solid var(--border);border-radius:.5rem;overflow:hidden}.floe-diagram-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;padding:.375rem;border-bottom:1px solid var(--border)}.floe-diagram-toolbar button{font:inherit;white-space:nowrap;border:0;border-radius:.25rem;padding:.25rem .5rem;background:transparent;color:inherit;cursor:pointer}.floe-diagram-toolbar button:hover,.floe-diagram-toolbar button[aria-pressed=true]{background:var(--accent)}.floe-diagram-toolbar button:focus-visible{outline:2px solid var(--ring);outline-offset:-2px}.floe-diagram-feedback{flex:1;min-width:0;font-size:.85em}.floe-diagram-viewport{padding:.75rem;min-width:0;max-height:65vh}.floe-diagram-svg{min-height:2rem;width:100%}.floe-diagram-svg>svg{display:block;max-width:100%;height:auto;margin:auto}.floe-diagram-source,.floe-diagram-error pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:.75rem;font:12px/1.6 var(--pele-font-mono)}.floe-diagram-status,.floe-diagram-error{padding:.75rem}.floe-diagram-error{color:var(--error,var(--foreground))}.floe-diagram-dialog{width:min(94vw,1100px);max-width:94vw}@media(forced-colors:active){.floe-diagram{--pele-fg:CanvasText;--pele-line:CanvasText;--pele-bg:Canvas;--pele-surface:Canvas;--pele-surface-alt:Canvas;--pele-border:CanvasText;--pele-accent:Highlight}}.floe-diagram-zoomed>svg{width:calc(100% * var(--floe-diagram-scale,1));max-width:none}.floe-diagram-toolbar button:disabled{opacity:.5;cursor:default}.floe-diagram-svg:not(.floe-diagram-zoomed)>svg{max-height:60vh}
@@ -1,4 +1,5 @@
1
1
  export { createMarkdownParser } from './components/chat/markdown/parser';
2
+ export { isClosedMarkdownFence } from './components/chat/markdown/fence';
2
3
  export { createIncrementalMarkdownParser } from './components/chat/markdown/incremental';
3
4
  export { createMarkdownSessionWorker } from './components/chat/markdown/createSessionWorker';
4
5
  export { createMarkdownSessionHandler, createMarkdownWorkerClient } from './components/chat/markdown/workerSession';
package/dist/markdown.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import { createMarkdownParser as o } from "./components/chat/markdown/parser.js";
2
- import { createIncrementalMarkdownParser as n } from "./components/chat/markdown/incremental.js";
3
- import { createMarkdownSessionWorker as k } from "./components/chat/markdown/createSessionWorker.js";
4
- import { createMarkdownSessionHandler as d, createMarkdownWorkerClient as s } from "./components/chat/markdown/workerSession.js";
2
+ import { isClosedMarkdownFence as n } from "./components/chat/markdown/fence.js";
3
+ import { createIncrementalMarkdownParser as d } from "./components/chat/markdown/incremental.js";
4
+ import { createMarkdownSessionWorker as s } from "./components/chat/markdown/createSessionWorker.js";
5
+ import { createMarkdownSessionHandler as m, createMarkdownWorkerClient as w } from "./components/chat/markdown/workerSession.js";
5
6
  export {
6
- n as createIncrementalMarkdownParser,
7
+ d as createIncrementalMarkdownParser,
7
8
  o as createMarkdownParser,
8
- d as createMarkdownSessionHandler,
9
- k as createMarkdownSessionWorker,
10
- s as createMarkdownWorkerClient
9
+ m as createMarkdownSessionHandler,
10
+ s as createMarkdownSessionWorker,
11
+ w as createMarkdownWorkerClient,
12
+ n as isClosedMarkdownFence
11
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floegence/floe-webapp-core",
3
- "version": "0.86.74",
3
+ "version": "0.86.75",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -155,7 +155,12 @@
155
155
  "./pptx": {
156
156
  "types": "./dist/pptx.d.ts",
157
157
  "import": "./dist/pptx.js"
158
- }
158
+ },
159
+ "./diagrams": {
160
+ "types": "./dist/diagrams.d.ts",
161
+ "import": "./dist/diagrams.js"
162
+ },
163
+ "./diagrams.css": "./dist/diagrams.css"
159
164
  },
160
165
  "files": [
161
166
  "dist",
@@ -174,7 +179,9 @@
174
179
  "clean": "rm -rf dist *.tsbuildinfo"
175
180
  },
176
181
  "peerDependencies": {
177
- "solid-js": "^1.9.17"
182
+ "solid-js": "^1.9.17",
183
+ "pele": "1.13.0",
184
+ "katex": "0.18.10"
178
185
  },
179
186
  "dependencies": {
180
187
  "clsx": "^2.1.1",
@@ -184,7 +191,6 @@
184
191
  "libavoid-js": "0.5.0-beta.5",
185
192
  "marked": "^17.0.6",
186
193
  "marked-cjk-friendly": "0.1.2",
187
- "mermaid": "^11.17.2",
188
194
  "monaco-editor": "^0.57.0",
189
195
  "pdfjs-dist": "6.3.289",
190
196
  "shiki": "^3.23.0",
@@ -192,12 +198,23 @@
192
198
  "tailwind-merge": "^3.7.0"
193
199
  },
194
200
  "devDependencies": {
201
+ "@aiden0z/pptx-renderer": "1.3.0",
195
202
  "@tailwindcss/vite": "^4.3.3",
203
+ "@types/katex": "0.16.8",
204
+ "katex": "0.18.10",
205
+ "pele": "1.13.0",
196
206
  "solid-js": "^1.9.17",
197
207
  "tailwindcss": "^4.3.3",
198
208
  "typescript": "^5.9.3",
199
209
  "vite": "^7.3.6",
200
- "vite-plugin-solid": "^2.11.14",
201
- "@aiden0z/pptx-renderer": "1.3.0"
210
+ "vite-plugin-solid": "^2.11.14"
211
+ },
212
+ "peerDependenciesMeta": {
213
+ "pele": {
214
+ "optional": true
215
+ },
216
+ "katex": {
217
+ "optional": true
218
+ }
202
219
  }
203
220
  }