@hachej/boring-workspace 0.1.63 → 0.1.65

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 (36) hide show
  1. package/dist/FileTree-B_fRS4Om.js +230 -0
  2. package/dist/MarkdownEditor-C55gVDyW.js +743 -0
  3. package/dist/WorkspaceLoadingState-D3i4X-eH.js +847 -0
  4. package/dist/WorkspaceProvider-Ddx7GByq.js +8770 -0
  5. package/dist/app-front.d.ts +106 -4
  6. package/dist/app-front.js +3110 -2427
  7. package/dist/app-server.d.ts +2 -2
  8. package/dist/app-server.js +6 -4
  9. package/dist/boring-workspace.css +2 -1
  10. package/dist/charts.d.ts +6 -1
  11. package/dist/charts.js +131 -138
  12. package/dist/plugin.d.ts +64 -1
  13. package/dist/plugin.js +32 -0
  14. package/dist/rolldown-runtime-Dqa2HsxW.js +20 -0
  15. package/dist/{runtimeEnv-HolIkcoB.d.ts → runtimeEnv-CU-c4kaV.d.ts} +7 -0
  16. package/dist/server.d.ts +2 -2
  17. package/dist/server.js +4 -3
  18. package/dist/testing-e2e.d.ts +5 -0
  19. package/dist/testing-e2e.js +33 -42
  20. package/dist/testing.d.ts +6 -1
  21. package/dist/testing.js +9474 -10814
  22. package/dist/utils-BRcxFdrz.js +8 -0
  23. package/dist/workspace.css +2790 -301
  24. package/dist/workspace.d.ts +164 -21
  25. package/dist/workspace.js +568 -734
  26. package/docs/plans/archive/CODE_OWNERSHIP_CLEANUP_PLAN.md +1 -1
  27. package/docs/plans/archive/DECLARATIVE_LAYOUT_MIGRATION.md +4 -4
  28. package/docs/plans/archive/GENERIC_EXPLORER_PLUGIN_PLAN.md +10 -10
  29. package/docs/plans/archive/PLUGIN_MODEL.md +37 -37
  30. package/docs/plans/archive/WORKSPACE_V2_PLAN.md +2 -2
  31. package/package.json +50 -50
  32. package/dist/FileTree-CUvn5K86.js +0 -315
  33. package/dist/MarkdownEditor-5f4lhBqc.js +0 -598
  34. package/dist/WorkspaceLoadingState-y087Q6ek.js +0 -866
  35. package/dist/WorkspaceProvider-U4izhS84.js +0 -8660
  36. package/dist/utils-B6yFEsav.js +0 -8
@@ -0,0 +1,743 @@
1
+ import { n as e } from "./rolldown-runtime-Dqa2HsxW.js";
2
+ import { Lt as t, Mt as n, Pt as r, tn as i } from "./WorkspaceProvider-Ddx7GByq.js";
3
+ import { t as a } from "./utils-BRcxFdrz.js";
4
+ import { useCallback as o, useEffect as s, useMemo as c, useRef as l, useState as u } from "react";
5
+ import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
6
+ import { AlignCenterIcon as m, AlignLeftIcon as h, AlignRightIcon as g, BoldIcon as _, CodeIcon as v, Heading1Icon as y, Heading2Icon as b, Heading3Icon as x, HighlighterIcon as S, ImageIcon as ee, ItalicIcon as C, LinkIcon as w, ListChecksIcon as te, ListIcon as T, ListOrderedIcon as E, Loader2Icon as D, MinusIcon as O, QuoteIcon as k, StrikethroughIcon as A, UnderlineIcon as ne } from "lucide-react";
7
+ import { Input as j, Toolbar as M, ToolbarButton as N, ToolbarSeparator as P } from "@hachej/boring-ui-kit";
8
+ import { uploadFile as F } from "@hachej/boring-agent/front";
9
+ import { EditorContent as re, NodeViewWrapper as I, ReactNodeViewRenderer as L, useEditor as ie, useEditorState as ae } from "@tiptap/react";
10
+ import oe from "@tiptap/starter-kit";
11
+ import se from "@tiptap/extension-underline";
12
+ import ce from "@tiptap/extension-link";
13
+ import R from "@tiptap/extension-placeholder";
14
+ import le from "@tiptap/extension-task-list";
15
+ import ue from "@tiptap/extension-task-item";
16
+ import de from "@tiptap/extension-text-align";
17
+ import fe from "@tiptap/extension-highlight";
18
+ import { Table as pe } from "@tiptap/extension-table";
19
+ import { TableRow as me } from "@tiptap/extension-table-row";
20
+ import { TableHeader as he } from "@tiptap/extension-table-header";
21
+ import { TableCell as ge } from "@tiptap/extension-table-cell";
22
+ import _e from "@tiptap/extension-image";
23
+ import ve from "@tiptap/extension-code-block-lowlight";
24
+ import { common as ye, createLowlight as be } from "lowlight";
25
+ import { Markdown as xe } from "@tiptap/markdown";
26
+ //#region src/plugins/filesystemPlugin/front/data/useFileUpload.ts
27
+ function Se(e) {
28
+ let t = n(), i = r(), [a, s] = u(0);
29
+ return {
30
+ upload: o(async (n, r) => {
31
+ s((e) => e + 1);
32
+ try {
33
+ return await F(n, {
34
+ apiBaseUrl: t,
35
+ workspaceRequestId: i,
36
+ directory: r?.directory ?? e?.directory,
37
+ sourcePath: r?.sourcePath
38
+ });
39
+ } finally {
40
+ s((e) => e - 1);
41
+ }
42
+ }, [
43
+ t,
44
+ i,
45
+ e?.directory
46
+ ]),
47
+ uploading: a > 0
48
+ };
49
+ }
50
+ //#endregion
51
+ //#region src/plugins/filesystemPlugin/front/markdown-editor/ResizableImage.tsx
52
+ var z = 64, B = 2e3;
53
+ function Ce(e) {
54
+ return e.replace(/\\/g, "\\\\").replace(/]/g, "\\]");
55
+ }
56
+ function V(e) {
57
+ return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
58
+ }
59
+ function H(e) {
60
+ if (typeof e == "number" && Number.isFinite(e) && e > 0) return e;
61
+ if (typeof e == "string" && e.trim()) {
62
+ let t = Number(e);
63
+ if (Number.isFinite(t) && t > 0) return t;
64
+ }
65
+ return null;
66
+ }
67
+ var we = _e.extend({
68
+ name: "image",
69
+ draggable: !0,
70
+ addOptions() {
71
+ return {
72
+ ...this.parent?.(),
73
+ resolveSrc: (e) => e,
74
+ resizable: !0
75
+ };
76
+ },
77
+ parseMarkdown: (e, t) => t.createNode("image", {
78
+ src: e.href,
79
+ title: e.title,
80
+ alt: e.text
81
+ }),
82
+ renderMarkdown: (e) => {
83
+ let t = typeof e.attrs?.src == "string" ? e.attrs.src : "", n = typeof e.attrs?.alt == "string" ? e.attrs.alt : "", r = typeof e.attrs?.title == "string" ? e.attrs.title : "", i = H(e.attrs?.width), a = H(e.attrs?.height), o = e.attrs?.align === "center" || e.attrs?.align === "right" ? e.attrs.align : "left";
84
+ if (!i && !a && o === "left") {
85
+ let e = Ce(n);
86
+ return r ? `![${e}](${t} "${r.replace(/"/g, "\\\"")}")` : `![${e}](${t})`;
87
+ }
88
+ let s = `<img ${[
89
+ `src="${V(t)}"`,
90
+ n ? `alt="${V(n)}"` : null,
91
+ r ? `title="${V(r)}"` : null,
92
+ i ? `width="${i}"` : null,
93
+ a ? `height="${a}"` : null
94
+ ].filter(Boolean).join(" ")} />`;
95
+ return o === "center" || o === "right" ? `<p align="${o}">${s}</p>` : s;
96
+ },
97
+ addAttributes() {
98
+ return {
99
+ ...this.parent?.() ?? {},
100
+ width: {
101
+ default: null,
102
+ parseHTML: (e) => {
103
+ let t = e.getAttribute("width");
104
+ if (t) {
105
+ let e = parseInt(t, 10);
106
+ return Number.isFinite(e) ? e : null;
107
+ }
108
+ let n = e.style.width;
109
+ if (n && n.endsWith("px")) {
110
+ let e = parseInt(n, 10);
111
+ return Number.isFinite(e) ? e : null;
112
+ }
113
+ return null;
114
+ },
115
+ renderHTML: (e) => e.width ? { width: String(e.width) } : {}
116
+ },
117
+ align: {
118
+ default: "left",
119
+ parseHTML: (e) => {
120
+ let t = e.getAttribute("data-align");
121
+ return t === "left" || t === "center" || t === "right" ? t : e.style.marginLeft === "auto" && e.style.marginRight === "auto" ? "center" : e.style.marginLeft === "auto" ? "right" : "left";
122
+ },
123
+ renderHTML: (e) => ({ "data-align": e.align ?? "left" })
124
+ },
125
+ pendingUploadId: {
126
+ default: null,
127
+ parseHTML: () => null,
128
+ renderHTML: () => ({})
129
+ }
130
+ };
131
+ },
132
+ addNodeView() {
133
+ return L(Te);
134
+ }
135
+ });
136
+ function Te({ node: e, updateAttributes: t, selected: n, extension: r }) {
137
+ let i = l(null), o = l(null), [c, d] = u(!1), m = e.attrs.src ?? "", h = (r.options.resolveSrc ?? ((e) => e))(m), g = r.options.resizable !== !1, _ = e.attrs.alt ?? "", v = e.attrs.title ?? void 0, y = e.attrs.width, b = e.attrs.align ?? "left";
138
+ return s(() => {
139
+ if (!c || !g) return;
140
+ let e = (e) => {
141
+ let n = o.current;
142
+ if (!n) return;
143
+ let r = e.clientX - n.x, i = Math.max(z, Math.min(B, n.width + r));
144
+ t({ width: Math.round(i) });
145
+ }, n = () => {
146
+ o.current = null, d(!1);
147
+ };
148
+ return window.addEventListener("pointermove", e), window.addEventListener("pointerup", n), window.addEventListener("pointercancel", n), () => {
149
+ window.removeEventListener("pointermove", e), window.removeEventListener("pointerup", n), window.removeEventListener("pointercancel", n);
150
+ };
151
+ }, [
152
+ c,
153
+ g,
154
+ t
155
+ ]), /* @__PURE__ */ p(I, {
156
+ ref: i,
157
+ "data-resizable-image": "",
158
+ "data-selected": n ? "true" : void 0,
159
+ className: a("relative block max-w-full align-baseline", "[&>img]:block [&>img]:max-w-full [&>img]:h-auto [&>img]:rounded-md", b === "left" && "mr-auto", b === "center" && "mx-auto", b === "right" && "ml-auto", g && n && "ring-2 ring-[color:var(--accent)] ring-offset-1 ring-offset-background"),
160
+ style: { width: y ? `${y}px` : void 0 },
161
+ children: [/* @__PURE__ */ f("img", {
162
+ src: h,
163
+ alt: _,
164
+ title: v,
165
+ draggable: !1
166
+ }), g && /* @__PURE__ */ f("span", {
167
+ role: "slider",
168
+ "aria-label": "Resize image",
169
+ "aria-valuenow": y ?? 0,
170
+ "aria-valuemin": z,
171
+ "aria-valuemax": B,
172
+ "data-testid": "resize-handle",
173
+ onPointerDown: (e) => {
174
+ if (!g) return;
175
+ e.preventDefault(), e.stopPropagation();
176
+ let t = i.current?.querySelector("img"), n = y ?? t?.getBoundingClientRect().width ?? 320;
177
+ o.current = {
178
+ x: e.clientX,
179
+ width: n
180
+ }, d(!0);
181
+ },
182
+ className: a("absolute right-0 bottom-0 h-3 w-3 translate-x-1/2 translate-y-1/2 cursor-nwse-resize", "rounded-full border border-background bg-[color:var(--accent)] shadow", "opacity-0 transition-opacity duration-150 ease-out", (n || c) && "opacity-100")
183
+ })]
184
+ });
185
+ }
186
+ //#endregion
187
+ //#region src/plugins/filesystemPlugin/front/markdown-editor/MarkdownEditor.tsx
188
+ var Ee = /* @__PURE__ */ e({
189
+ MarkdownEditor: () => $,
190
+ countMarkdownWords: () => K,
191
+ isSafeUrl: () => Z,
192
+ isUserEditedChange: () => q,
193
+ parseMarkdownFrontmatter: () => W,
194
+ rawFileUrlForMarkdownImage: () => Fe,
195
+ readFileAsDataUrl: () => Q,
196
+ sanitizeHtml: () => U,
197
+ serializeMarkdownEditorChange: () => G,
198
+ workspaceFilePathForMarkdownLink: () => J
199
+ }), De = be(ye), Oe = [
200
+ /<script[\s>][\s\S]*?<\/script>/gi,
201
+ /<iframe[\s>][\s\S]*?<\/iframe>/gi,
202
+ /\s+on\w+\s*=\s*["'][^"']*["']/gi,
203
+ /\s+on\w+\s*=\s*\S+/gi,
204
+ /href\s*=\s*["']?\s*javascript:[^"'\s>]*/gi,
205
+ /src\s*=\s*["']?\s*javascript:[^"'\s>]*/gi
206
+ ];
207
+ function U(e) {
208
+ let t = e;
209
+ for (let e of Oe) t = t.replace(e, "");
210
+ return t;
211
+ }
212
+ function ke(e) {
213
+ let t = e.trim();
214
+ if (t.length < 2) return t;
215
+ let n = t[0], r = t[t.length - 1];
216
+ return n === "\"" && r === "\"" || n === "'" && r === "'" ? t.slice(1, -1) : t;
217
+ }
218
+ function Ae(e) {
219
+ return ke(e.split("\n").map((e) => e.trim()).filter(Boolean).map((e) => e.replace(/^-\s+/, "")).join(", "));
220
+ }
221
+ function W(e) {
222
+ let t = e.replace(/^\uFEFF/, ""), n = t.match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n(?:---|\.\.\.)[ \t]*(?:\r?\n|$)/);
223
+ if (!n || n.index !== 0) return null;
224
+ let r = n[1] ?? "", i = t.slice(n[0].length), a = [], o = null, s = () => {
225
+ if (!o) return;
226
+ let e = Ae(o.lines.join("\n"));
227
+ e && a.push({
228
+ key: o.key,
229
+ value: e
230
+ }), o = null;
231
+ };
232
+ for (let e of r.split(/\r?\n/)) {
233
+ if (!e.trim() || e.trimStart().startsWith("#")) continue;
234
+ let t = e.match(/^([A-Za-z0-9_-]+):(?:\s*(.*))?$/);
235
+ if (t) {
236
+ s(), o = {
237
+ key: t[1],
238
+ lines: [t[2] ?? ""]
239
+ };
240
+ continue;
241
+ }
242
+ o && /^\s+/.test(e) && o.lines.push(e);
243
+ }
244
+ return s(), a.length > 0 ? {
245
+ entries: a,
246
+ block: n[0],
247
+ raw: r,
248
+ body: i
249
+ } : null;
250
+ }
251
+ function je(e, t) {
252
+ if (!e) return t;
253
+ let n = e.block.endsWith("\n") || t.length === 0 ? "" : "\n";
254
+ return `${e.block}${n}${t}`;
255
+ }
256
+ function G(e, t, n, r = !1) {
257
+ return q(e, t, r) ? je(n, e) : null;
258
+ }
259
+ function K(e) {
260
+ return (W(e)?.body ?? e).replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/^\s{0,3}#{1,6}\s+/gm, "").replace(/!\[[^\]]*\]\([^)]*\)/g, " ").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/<[^>]+>/g, " ").replace(/^\s{0,3}[-*_]{3,}\s*$/gm, " ").replace(/^\s{0,3}(?:[-*+]\s+|\d+[.)]\s+|>\s?)/gm, "").replace(/^\s{0,3}\|?(?:\s*:?-+:?\s*\|)+\s*$/gm, " ").replace(/\|/g, " ").replace(/[*_~>#]/g, " ").match(/\b[\p{L}\p{N}']+\b/gu)?.length ?? 0;
261
+ }
262
+ function Me(e) {
263
+ return `${e} word${e === 1 ? "" : "s"}`;
264
+ }
265
+ function Ne(e) {
266
+ return /^(?:[a-z][a-z0-9+.-]*:|\/|#)/i.test(e);
267
+ }
268
+ function q(e, t, n = !1) {
269
+ return t || n;
270
+ }
271
+ function Pe(e, t) {
272
+ let n = e.match(/^([^?#]*)([?#].*)?$/), r = n?.[1] ?? e, i = n?.[2] ?? "", a = t?.includes("/") ? t.slice(0, t.lastIndexOf("/")) : "", o = `${a ? `${a}/` : ""}${r}`.split("/"), s = [];
273
+ for (let e of o) !e || e === "." || (e === ".." ? s.pop() : s.push(e));
274
+ return `${s.join("/")}${i}`;
275
+ }
276
+ function Fe(e, t, n, r, a) {
277
+ if (!e) return e;
278
+ let o = i(a), s = o !== "user";
279
+ if (Ne(e) && !(s && e.startsWith("/") && !e.startsWith("//"))) return e;
280
+ let c = s && e.startsWith("/") ? e : s && t?.startsWith("/") ? `/${Pe(e, t)}` : Pe(e, t), l = n.replace(/\/$/, ""), u = new URLSearchParams({ path: c });
281
+ return r && u.set("workspaceId", r), o !== "user" && u.set("filesystem", o), `${l}/api/v1/files/raw?${u.toString()}`;
282
+ }
283
+ function Ie(e) {
284
+ return /^(?:[a-z][a-z0-9+.-]*:|\/\/|\/|#|\?)/i.test(e);
285
+ }
286
+ function J(e, t) {
287
+ let n = e.trim();
288
+ if (!n || Ie(n)) return null;
289
+ let r = n.split(/[?#]/, 1)[0];
290
+ if (!r) return null;
291
+ let i = t?.includes("/") ? t.slice(0, t.lastIndexOf("/")) : "", a = `${i ? `${i}/` : ""}${r}`.split("/"), o = [];
292
+ for (let e of a) if (!(!e || e === ".")) {
293
+ if (e === "..") {
294
+ if (o.length === 0) return null;
295
+ o.pop();
296
+ continue;
297
+ }
298
+ o.push(e);
299
+ }
300
+ return o.join("/") || null;
301
+ }
302
+ function Le(e) {
303
+ return e.button === 0 && !e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey;
304
+ }
305
+ var Re = [
306
+ oe.configure({
307
+ codeBlock: !1,
308
+ link: !1,
309
+ underline: !1
310
+ }),
311
+ se,
312
+ ce.configure({
313
+ openOnClick: !0,
314
+ autolink: !0,
315
+ linkOnPaste: !0,
316
+ defaultProtocol: "https",
317
+ isAllowedUri: (e, t) => Z(e) && (J(e) !== null || t.defaultValidate(e)),
318
+ HTMLAttributes: {
319
+ rel: "noopener noreferrer nofollow",
320
+ target: "_blank"
321
+ }
322
+ }),
323
+ R.configure({ placeholder: "Start writing..." }),
324
+ le,
325
+ ue.configure({ nested: !0 }),
326
+ de.configure({ types: ["heading", "paragraph"] }),
327
+ fe,
328
+ pe.configure({ resizable: !0 }),
329
+ me,
330
+ he,
331
+ ge,
332
+ we.configure({
333
+ inline: !1,
334
+ allowBase64: !0
335
+ }),
336
+ ve.configure({ lowlight: De }),
337
+ xe.configure({ markedOptions: {
338
+ gfm: !0,
339
+ breaks: !1,
340
+ pedantic: !1
341
+ } })
342
+ ];
343
+ function Y({ onClick: e, active: t, disabled: n, title: r, children: i }) {
344
+ return /* @__PURE__ */ f(N, {
345
+ type: "button",
346
+ size: "icon-xs",
347
+ onClick: e,
348
+ disabled: n,
349
+ title: r,
350
+ "aria-pressed": t,
351
+ className: a("text-muted-foreground/70", t && "bg-[color:var(--accent-soft)] text-[color:var(--accent)]"),
352
+ children: i
353
+ });
354
+ }
355
+ function X() {
356
+ return /* @__PURE__ */ f(P, { className: "mx-2 h-3.5" });
357
+ }
358
+ function Z(e) {
359
+ let t = e.trim().toLowerCase();
360
+ return !t.startsWith("javascript:") && !t.startsWith("data:text/html");
361
+ }
362
+ function Q(e) {
363
+ return new Promise((t, n) => {
364
+ let r = new FileReader();
365
+ r.onload = () => t(r.result), r.onerror = () => n(r.error ?? /* @__PURE__ */ Error("Read failed")), r.readAsDataURL(e);
366
+ });
367
+ }
368
+ function ze(e) {
369
+ if (!e) return null;
370
+ for (let t of Array.from(e.files ?? [])) if (t.type.startsWith("image/")) return t;
371
+ for (let t of Array.from(e.items ?? [])) {
372
+ if (t.kind !== "file" || !t.type.startsWith("image/")) continue;
373
+ let e = t.getAsFile();
374
+ if (e) return e;
375
+ }
376
+ return null;
377
+ }
378
+ function Be({ editor: e, onInsertImage: t, rawMode: n, onToggleRawMode: r, uploading: i, allowImageUpload: a }) {
379
+ let o = (t) => {
380
+ if (e) {
381
+ if (e.isActive("image")) {
382
+ e.chain().focus().updateAttributes("image", { align: t }).run();
383
+ return;
384
+ }
385
+ e.chain().focus().setTextAlign(t).run();
386
+ }
387
+ }, s = l(null), c = ae({
388
+ editor: e,
389
+ selector: ({ editor: e }) => e ? {
390
+ bold: e.isActive("bold"),
391
+ italic: e.isActive("italic"),
392
+ underline: e.isActive("underline"),
393
+ strike: e.isActive("strike"),
394
+ h1: e.isActive("heading", { level: 1 }),
395
+ h2: e.isActive("heading", { level: 2 }),
396
+ h3: e.isActive("heading", { level: 3 }),
397
+ bulletList: e.isActive("bulletList"),
398
+ orderedList: e.isActive("orderedList"),
399
+ taskList: e.isActive("taskList"),
400
+ blockquote: e.isActive("blockquote"),
401
+ codeBlock: e.isActive("codeBlock"),
402
+ link: e.isActive("link"),
403
+ highlight: e.isActive("highlight"),
404
+ alignLeft: e.isActive("image") ? (e.getAttributes("image").align ?? "left") === "left" : e.isActive({ textAlign: "left" }),
405
+ alignCenter: e.isActive("image") ? e.getAttributes("image").align === "center" : e.isActive({ textAlign: "center" }),
406
+ alignRight: e.isActive("image") ? e.getAttributes("image").align === "right" : e.isActive({ textAlign: "right" })
407
+ } : null
408
+ });
409
+ if (!e || !c) return null;
410
+ let u = () => {
411
+ let t = window.prompt("URL:");
412
+ t && Z(t) && e.chain().focus().extendMarkRange("link").setLink({ href: t }).run();
413
+ }, d = () => {
414
+ let t = window.prompt("Image URL:");
415
+ t && Z(t) && e.chain().focus().setImage({ src: t }).run();
416
+ };
417
+ return /* @__PURE__ */ p(M, {
418
+ className: "border-b border-border/60 bg-background px-3 py-1.5",
419
+ "aria-label": "Formatting toolbar",
420
+ children: [
421
+ /* @__PURE__ */ f(Y, {
422
+ onClick: () => e.chain().focus().toggleBold().run(),
423
+ active: c.bold,
424
+ title: "Bold",
425
+ children: /* @__PURE__ */ f(_, { className: "h-4 w-4" })
426
+ }),
427
+ /* @__PURE__ */ f(Y, {
428
+ onClick: () => e.chain().focus().toggleItalic().run(),
429
+ active: c.italic,
430
+ title: "Italic",
431
+ children: /* @__PURE__ */ f(C, { className: "h-4 w-4" })
432
+ }),
433
+ /* @__PURE__ */ f(Y, {
434
+ onClick: () => e.chain().focus().toggleUnderline().run(),
435
+ active: c.underline,
436
+ title: "Underline",
437
+ children: /* @__PURE__ */ f(ne, { className: "h-4 w-4" })
438
+ }),
439
+ /* @__PURE__ */ f(Y, {
440
+ onClick: () => e.chain().focus().toggleStrike().run(),
441
+ active: c.strike,
442
+ title: "Strikethrough",
443
+ children: /* @__PURE__ */ f(A, { className: "h-4 w-4" })
444
+ }),
445
+ /* @__PURE__ */ f(X, {}),
446
+ /* @__PURE__ */ f(Y, {
447
+ onClick: () => e.chain().focus().toggleHeading({ level: 1 }).run(),
448
+ active: c.h1,
449
+ title: "Heading 1",
450
+ children: /* @__PURE__ */ f(y, { className: "h-4 w-4" })
451
+ }),
452
+ /* @__PURE__ */ f(Y, {
453
+ onClick: () => e.chain().focus().toggleHeading({ level: 2 }).run(),
454
+ active: c.h2,
455
+ title: "Heading 2",
456
+ children: /* @__PURE__ */ f(b, { className: "h-4 w-4" })
457
+ }),
458
+ /* @__PURE__ */ f(Y, {
459
+ onClick: () => e.chain().focus().toggleHeading({ level: 3 }).run(),
460
+ active: c.h3,
461
+ title: "Heading 3",
462
+ children: /* @__PURE__ */ f(x, { className: "h-4 w-4" })
463
+ }),
464
+ /* @__PURE__ */ f(X, {}),
465
+ /* @__PURE__ */ f(Y, {
466
+ onClick: () => e.chain().focus().toggleBulletList().run(),
467
+ active: c.bulletList,
468
+ title: "Bullet list",
469
+ children: /* @__PURE__ */ f(T, { className: "h-4 w-4" })
470
+ }),
471
+ /* @__PURE__ */ f(Y, {
472
+ onClick: () => e.chain().focus().toggleOrderedList().run(),
473
+ active: c.orderedList,
474
+ title: "Ordered list",
475
+ children: /* @__PURE__ */ f(E, { className: "h-4 w-4" })
476
+ }),
477
+ /* @__PURE__ */ f(Y, {
478
+ onClick: () => e.chain().focus().toggleTaskList().run(),
479
+ active: c.taskList,
480
+ title: "Task list",
481
+ children: /* @__PURE__ */ f(te, { className: "h-4 w-4" })
482
+ }),
483
+ /* @__PURE__ */ f(X, {}),
484
+ /* @__PURE__ */ f(Y, {
485
+ onClick: () => e.chain().focus().toggleBlockquote().run(),
486
+ active: c.blockquote,
487
+ title: "Quote",
488
+ children: /* @__PURE__ */ f(k, { className: "h-4 w-4" })
489
+ }),
490
+ /* @__PURE__ */ f(Y, {
491
+ onClick: () => e.chain().focus().toggleCodeBlock().run(),
492
+ active: c.codeBlock,
493
+ title: "Code block",
494
+ children: /* @__PURE__ */ f(v, { className: "h-4 w-4" })
495
+ }),
496
+ /* @__PURE__ */ f(Y, {
497
+ onClick: u,
498
+ active: c.link,
499
+ title: "Link",
500
+ children: /* @__PURE__ */ f(w, { className: "h-4 w-4" })
501
+ }),
502
+ /* @__PURE__ */ f(Y, {
503
+ onClick: (e) => {
504
+ if (e?.shiftKey) {
505
+ d();
506
+ return;
507
+ }
508
+ a && s.current?.click();
509
+ },
510
+ disabled: !a,
511
+ title: a ? "Image (click to upload, Shift+click for URL)" : "Image upload unavailable for this filesystem",
512
+ children: /* @__PURE__ */ f(ee, { className: "h-4 w-4" })
513
+ }),
514
+ /* @__PURE__ */ f(j, {
515
+ ref: s,
516
+ "data-testid": "image-file-input",
517
+ type: "file",
518
+ accept: "image/*",
519
+ className: "hidden",
520
+ onChange: async (e) => {
521
+ let n = e.target.files?.[0];
522
+ e.target.value = "", !(!n || !n.type.startsWith("image/")) && await t(n);
523
+ }
524
+ }),
525
+ /* @__PURE__ */ f(Y, {
526
+ onClick: () => e.chain().focus().toggleHighlight().run(),
527
+ active: c.highlight,
528
+ title: "Highlight",
529
+ children: /* @__PURE__ */ f(S, { className: "h-4 w-4" })
530
+ }),
531
+ /* @__PURE__ */ f(X, {}),
532
+ /* @__PURE__ */ f(Y, {
533
+ onClick: () => o("left"),
534
+ active: c.alignLeft,
535
+ title: "Align left",
536
+ children: /* @__PURE__ */ f(h, { className: "h-4 w-4" })
537
+ }),
538
+ /* @__PURE__ */ f(Y, {
539
+ onClick: () => o("center"),
540
+ active: c.alignCenter,
541
+ title: "Center align",
542
+ children: /* @__PURE__ */ f(m, { className: "h-4 w-4" })
543
+ }),
544
+ /* @__PURE__ */ f(Y, {
545
+ onClick: () => o("right"),
546
+ active: c.alignRight,
547
+ title: "Align right",
548
+ children: /* @__PURE__ */ f(g, { className: "h-4 w-4" })
549
+ }),
550
+ /* @__PURE__ */ f(X, {}),
551
+ /* @__PURE__ */ f(Y, {
552
+ onClick: () => e.chain().focus().setHorizontalRule().run(),
553
+ title: "Horizontal rule",
554
+ children: /* @__PURE__ */ f(O, { className: "h-4 w-4" })
555
+ }),
556
+ /* @__PURE__ */ f(X, {}),
557
+ i && /* @__PURE__ */ p("span", {
558
+ role: "status",
559
+ "aria-live": "polite",
560
+ className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground/80",
561
+ children: [/* @__PURE__ */ f(D, {
562
+ className: "h-3 w-3 animate-spin",
563
+ "aria-hidden": !0
564
+ }), "Uploading…"]
565
+ }),
566
+ /* @__PURE__ */ f(Y, {
567
+ onClick: r,
568
+ active: n,
569
+ title: n ? "Rich text" : "Raw markdown",
570
+ children: /* @__PURE__ */ f("span", {
571
+ className: "font-mono text-[10px] font-semibold leading-none tracking-[-0.02em]",
572
+ children: "MD"
573
+ })
574
+ })
575
+ ]
576
+ });
577
+ }
578
+ function Ve({ summary: e }) {
579
+ return /* @__PURE__ */ f("section", {
580
+ "aria-label": "Frontmatter",
581
+ className: "border-b border-border/60 bg-transparent px-6 py-5",
582
+ "data-testid": "markdown-frontmatter-summary",
583
+ children: /* @__PURE__ */ p("div", {
584
+ className: "rounded-xl border border-[#3a3a3a] bg-[#262626] px-6 py-5 shadow-sm",
585
+ children: [/* @__PURE__ */ f("h2", {
586
+ className: "mb-5 text-base font-medium text-[#c9c9c9]",
587
+ children: "Metadata"
588
+ }), /* @__PURE__ */ f("dl", {
589
+ className: "grid gap-x-10 gap-y-4 text-sm sm:grid-cols-[minmax(9rem,17rem)_minmax(0,1fr)]",
590
+ children: e.entries.map((e, t) => /* @__PURE__ */ p("div", {
591
+ className: "contents",
592
+ children: [/* @__PURE__ */ f("dt", {
593
+ className: "font-mono text-[#b8b8b8]",
594
+ children: e.key
595
+ }), /* @__PURE__ */ f("dd", {
596
+ className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[#f5f5f5]",
597
+ children: e.value
598
+ })]
599
+ }, `${e.key}-${t}`))
600
+ })]
601
+ })
602
+ });
603
+ }
604
+ function $({ content: e, onChange: o, readOnly: m = !1, placeholder: h, className: g, documentPath: _, filesystem: v }) {
605
+ let y = i(v), b = n(), x = r(), S = y === "user", { upload: ee, uploading: C } = Se(), [w, te] = u(!1), T = c(() => {
606
+ let e = we.configure({
607
+ inline: !1,
608
+ allowBase64: !0,
609
+ resizable: !m,
610
+ resolveSrc: (e) => Fe(e, _, b, x, y)
611
+ }), t = Re.map((t) => t.name === "image" ? e : t);
612
+ return h ? [...t.filter((e) => e.name !== "placeholder"), R.configure({ placeholder: h })] : t;
613
+ }, [
614
+ b,
615
+ _,
616
+ y,
617
+ h,
618
+ m,
619
+ x
620
+ ]), E = l(o);
621
+ E.current = o;
622
+ let D = l(!1), O = l(!1), k = l(e), A = l(null), ne = c(() => K(e), [e]), j = c(() => W(e), [e]), M = j?.body ?? e, N = l(async () => {}), P = l(j);
623
+ P.current = j, N.current = async (e) => {
624
+ O.current = !0;
625
+ let t = A.current;
626
+ if (!t || !S) return;
627
+ let n;
628
+ try {
629
+ n = await Q(e);
630
+ } catch {
631
+ return;
632
+ }
633
+ let r = typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `pending-${Date.now()}-${Math.random().toString(36).slice(2)}`, i = {
634
+ src: n,
635
+ alt: e.name,
636
+ pendingUploadId: r
637
+ };
638
+ t.chain().focus().setImage(i).run();
639
+ try {
640
+ let { url: t } = await ee(e, { sourcePath: _ }), n = A.current;
641
+ if (!n || n.isDestroyed) return;
642
+ n.commands.command(({ tr: e, state: n }) => (n.doc.descendants((n, i) => (n.type.name === "image" && n.attrs.pendingUploadId === r && e.setNodeMarkup(i, void 0, {
643
+ ...n.attrs,
644
+ src: t,
645
+ pendingUploadId: null
646
+ }), !0)), !0));
647
+ } catch {
648
+ let e = A.current;
649
+ if (!e || e.isDestroyed) return;
650
+ e.commands.command(({ tr: e, state: t }) => (t.doc.descendants((t, n) => (t.type.name === "image" && t.attrs.pendingUploadId === r && e.setNodeMarkup(n, void 0, {
651
+ ...t.attrs,
652
+ pendingUploadId: null
653
+ }), !0)), !0));
654
+ }
655
+ };
656
+ let F = c(() => M || {
657
+ type: "doc",
658
+ content: [{ type: "paragraph" }]
659
+ }, [M]), I = M ? "markdown" : "json", L = ie({
660
+ extensions: T,
661
+ content: F,
662
+ contentType: I,
663
+ editable: !m,
664
+ editorProps: {
665
+ attributes: { class: "tiptap-prose max-w-[68ch] px-8 py-6 focus:outline-none min-h-[200px]" },
666
+ transformPastedHTML: U,
667
+ handlePaste: (e, t) => {
668
+ if (m) return !1;
669
+ let n = ze(t.clipboardData);
670
+ return n ? (t.preventDefault(), N.current(n), !0) : !1;
671
+ }
672
+ },
673
+ onUpdate: ({ editor: e }) => {
674
+ if (D.current) return;
675
+ let t = G(e.getMarkdown?.() ?? e.getHTML(), e.isFocused, P.current, O.current);
676
+ t !== null && (k.current = t, E.current?.(t));
677
+ }
678
+ });
679
+ return A.current = L, s(() => {
680
+ !L || L.isDestroyed || L.setEditable(!m);
681
+ }, [L, m]), s(() => {
682
+ !L || L.isDestroyed || e !== k.current && (L.getMarkdown?.() ?? L.getHTML()) !== M && (D.current = !0, L.commands.setContent(F, { contentType: I }), D.current = !1, k.current = e);
683
+ }, [
684
+ L,
685
+ e,
686
+ F,
687
+ I,
688
+ M
689
+ ]), /* @__PURE__ */ p("div", {
690
+ className: a("flex h-full min-h-0 flex-col overflow-hidden", g),
691
+ onPointerDownCapture: () => {
692
+ O.current = !0;
693
+ },
694
+ onClickCapture: () => {
695
+ O.current = !0;
696
+ },
697
+ onKeyDownCapture: () => {
698
+ O.current = !0;
699
+ },
700
+ children: [
701
+ !m && /* @__PURE__ */ f(Be, {
702
+ editor: L,
703
+ onInsertImage: (e) => N.current(e),
704
+ rawMode: w,
705
+ onToggleRawMode: () => te((e) => !e),
706
+ uploading: C,
707
+ allowImageUpload: S
708
+ }),
709
+ /* @__PURE__ */ f("div", {
710
+ className: "min-h-0 flex-1 overflow-auto",
711
+ onClickCapture: (e) => {
712
+ if (!Le(e.nativeEvent)) return;
713
+ let n = (e.target instanceof Element ? e.target.closest("a[href]") : null)?.getAttribute("href");
714
+ if (!n) return;
715
+ let r = i(y), a = r !== "user", o = J(n, _) ?? (a && n.startsWith("/") && !n.startsWith("//") ? n.split(/[?#]/, 1)[0] : null);
716
+ o && (e.preventDefault(), e.stopPropagation(), t({
717
+ kind: "openFile",
718
+ params: {
719
+ path: a && _?.startsWith("/") && !o.startsWith("/") ? `/${o}` : o,
720
+ ...r === "user" ? {} : { filesystem: r }
721
+ }
722
+ }));
723
+ },
724
+ children: w && !m ? /* @__PURE__ */ f("textarea", {
725
+ "aria-label": "Raw markdown",
726
+ "data-testid": "markdown-raw-editor",
727
+ className: "h-full min-h-[200px] w-full resize-none bg-background px-8 py-6 font-mono text-[13px] leading-6 text-foreground outline-none placeholder:text-muted-foreground/70",
728
+ value: e,
729
+ placeholder: h,
730
+ spellCheck: !1,
731
+ onChange: (e) => E.current?.(e.target.value)
732
+ }) : /* @__PURE__ */ p(d, { children: [j && /* @__PURE__ */ f(Ve, { summary: j }), /* @__PURE__ */ f(re, { editor: L })] })
733
+ }),
734
+ /* @__PURE__ */ f("div", {
735
+ className: "border-t border-border/60 px-4 py-2 text-right text-xs text-muted-foreground",
736
+ "data-testid": "markdown-word-count",
737
+ children: Me(ne)
738
+ })
739
+ ]
740
+ });
741
+ }
742
+ //#endregion
743
+ export { Ee as n, $ as t };