@hachej/boring-workspace 0.1.59 → 0.1.60

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,34 +1,34 @@
1
- import { jsxs as S, jsx as n } from "react/jsx-runtime";
2
- import { useState as W, useCallback as Y, useRef as A, useEffect as F, useMemo as j } from "react";
3
- import { ReactNodeViewRenderer as tt, NodeViewWrapper as et, useEditor as rt, EditorContent as nt, useEditorState as it } from "@tiptap/react";
4
- import at from "@tiptap/starter-kit";
5
- import ot from "@tiptap/extension-underline";
6
- import st from "@tiptap/extension-link";
7
- import P from "@tiptap/extension-placeholder";
8
- import lt from "@tiptap/extension-task-list";
9
- import ct from "@tiptap/extension-task-item";
10
- import ut from "@tiptap/extension-text-align";
11
- import gt from "@tiptap/extension-highlight";
12
- import { Table as dt } from "@tiptap/extension-table";
13
- import { TableRow as ft } from "@tiptap/extension-table-row";
14
- import { TableHeader as pt } from "@tiptap/extension-table-header";
15
- import { TableCell as mt } from "@tiptap/extension-table-cell";
16
- import ht from "@tiptap/extension-image";
17
- import { c as E } from "./utils-B6yFEsav.js";
18
- import { a8 as O, aA as V, p as wt } from "./WorkspaceProvider-Bp1Sm40K.js";
19
- import { uploadFile as kt } from "@hachej/boring-agent/front";
20
- import bt from "@tiptap/extension-code-block-lowlight";
21
- import { createLowlight as vt, common as It } from "lowlight";
22
- import { Markdown as xt } from "@tiptap/markdown";
23
- import { BoldIcon as yt, ItalicIcon as Lt, UnderlineIcon as At, StrikethroughIcon as Ct, Heading1Icon as Nt, Heading2Icon as Tt, Heading3Icon as $t, ListIcon as Mt, ListOrderedIcon as Rt, ListChecksIcon as Ut, QuoteIcon as Ht, CodeIcon as St, LinkIcon as Et, ImageIcon as Bt, HighlighterIcon as Dt, AlignLeftIcon as Ft, AlignCenterIcon as zt, AlignRightIcon as Wt, MinusIcon as jt, Loader2Icon as qt } from "lucide-react";
24
- import { Toolbar as _t, Input as Kt, ToolbarButton as Pt, ToolbarSeparator as Ot } from "@hachej/boring-ui-kit";
25
- function Vt(t) {
26
- const e = O(), r = V(), [o, l] = W(0);
27
- return { upload: Y(
1
+ import { jsxs as E, jsx as n } from "react/jsx-runtime";
2
+ import { useState as j, useCallback as tt, useRef as L, useEffect as z, useMemo as q } from "react";
3
+ import { ReactNodeViewRenderer as et, NodeViewWrapper as rt, useEditor as nt, EditorContent as it, useEditorState as at } from "@tiptap/react";
4
+ import ot from "@tiptap/starter-kit";
5
+ import st from "@tiptap/extension-underline";
6
+ import lt from "@tiptap/extension-link";
7
+ import O from "@tiptap/extension-placeholder";
8
+ import ct from "@tiptap/extension-task-list";
9
+ import ut from "@tiptap/extension-task-item";
10
+ import gt from "@tiptap/extension-text-align";
11
+ import dt from "@tiptap/extension-highlight";
12
+ import { Table as ft } from "@tiptap/extension-table";
13
+ import { TableRow as pt } from "@tiptap/extension-table-row";
14
+ import { TableHeader as mt } from "@tiptap/extension-table-header";
15
+ import { TableCell as ht } from "@tiptap/extension-table-cell";
16
+ import wt from "@tiptap/extension-image";
17
+ import { c as B } from "./utils-B6yFEsav.js";
18
+ import { ac as V, aF as X, p as kt } from "./WorkspaceProvider-Dxvh_Faj.js";
19
+ import { uploadFile as bt } from "@hachej/boring-agent/front";
20
+ import vt from "@tiptap/extension-code-block-lowlight";
21
+ import { createLowlight as It, common as xt } from "lowlight";
22
+ import { Markdown as yt } from "@tiptap/markdown";
23
+ import { BoldIcon as Lt, ItalicIcon as At, UnderlineIcon as Ct, StrikethroughIcon as Nt, Heading1Icon as Tt, Heading2Icon as $t, Heading3Icon as Mt, ListIcon as Rt, ListOrderedIcon as Ut, ListChecksIcon as Ht, QuoteIcon as St, CodeIcon as Et, LinkIcon as Bt, ImageIcon as Dt, HighlighterIcon as Ft, AlignLeftIcon as zt, AlignCenterIcon as Wt, AlignRightIcon as jt, MinusIcon as qt, Loader2Icon as _t } from "lucide-react";
24
+ import { Toolbar as Kt, Input as Pt, ToolbarButton as Ot, ToolbarSeparator as Vt } from "@hachej/boring-ui-kit";
25
+ function Xt(t) {
26
+ const e = V(), r = X(), [o, l] = j(0);
27
+ return { upload: tt(
28
28
  async (c, a) => {
29
29
  l((m) => m + 1);
30
30
  try {
31
- return await kt(c, {
31
+ return await bt(c, {
32
32
  apiBaseUrl: e,
33
33
  workspaceRequestId: r,
34
34
  directory: (a == null ? void 0 : a.directory) ?? (t == null ? void 0 : t.directory),
@@ -41,14 +41,14 @@ function Vt(t) {
41
41
  [e, r, t == null ? void 0 : t.directory]
42
42
  ), uploading: o > 0 };
43
43
  }
44
- const q = 64, _ = 2e3;
45
- function Xt(t) {
44
+ const _ = 64, K = 2e3;
45
+ function Qt(t) {
46
46
  return t.replace(/\\/g, "\\\\").replace(/]/g, "\\]");
47
47
  }
48
- function D(t) {
48
+ function F(t) {
49
49
  return t.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
50
50
  }
51
- function K(t) {
51
+ function P(t) {
52
52
  if (typeof t == "number" && Number.isFinite(t) && t > 0) return t;
53
53
  if (typeof t == "string" && t.trim()) {
54
54
  const e = Number(t);
@@ -56,7 +56,7 @@ function K(t) {
56
56
  }
57
57
  return null;
58
58
  }
59
- const X = ht.extend({
59
+ const Q = wt.extend({
60
60
  name: "image",
61
61
  draggable: !0,
62
62
  addOptions() {
@@ -72,16 +72,16 @@ const X = ht.extend({
72
72
  alt: t.text
73
73
  }),
74
74
  renderMarkdown: (t) => {
75
- var C, v, y, i, g, k, L;
76
- const e = typeof ((C = t.attrs) == null ? void 0 : C.src) == "string" ? t.attrs.src : "", r = typeof ((v = t.attrs) == null ? void 0 : v.alt) == "string" ? t.attrs.alt : "", o = typeof ((y = t.attrs) == null ? void 0 : y.title) == "string" ? t.attrs.title : "", l = K((i = t.attrs) == null ? void 0 : i.width), s = K((g = t.attrs) == null ? void 0 : g.height), c = ((k = t.attrs) == null ? void 0 : k.align) === "center" || ((L = t.attrs) == null ? void 0 : L.align) === "right" ? t.attrs.align : "left";
75
+ var C, x, A, i, g, k, v;
76
+ const e = typeof ((C = t.attrs) == null ? void 0 : C.src) == "string" ? t.attrs.src : "", r = typeof ((x = t.attrs) == null ? void 0 : x.alt) == "string" ? t.attrs.alt : "", o = typeof ((A = t.attrs) == null ? void 0 : A.title) == "string" ? t.attrs.title : "", l = P((i = t.attrs) == null ? void 0 : i.width), s = P((g = t.attrs) == null ? void 0 : g.height), c = ((k = t.attrs) == null ? void 0 : k.align) === "center" || ((v = t.attrs) == null ? void 0 : v.align) === "right" ? t.attrs.align : "left";
77
77
  if (!l && !s && c === "left") {
78
- const w = Xt(r);
79
- return o ? `![${w}](${e} "${o.replace(/"/g, '\\"')}")` : `![${w}](${e})`;
78
+ const h = Qt(r);
79
+ return o ? `![${h}](${e} "${o.replace(/"/g, '\\"')}")` : `![${h}](${e})`;
80
80
  }
81
81
  const m = `<img ${[
82
- `src="${D(e)}"`,
83
- r ? `alt="${D(r)}"` : null,
84
- o ? `title="${D(o)}"` : null,
82
+ `src="${F(e)}"`,
83
+ r ? `alt="${F(r)}"` : null,
84
+ o ? `title="${F(o)}"` : null,
85
85
  l ? `width="${l}"` : null,
86
86
  s ? `height="${s}"` : null
87
87
  ].filter(Boolean).join(" ")} />`;
@@ -129,38 +129,38 @@ const X = ht.extend({
129
129
  };
130
130
  },
131
131
  addNodeView() {
132
- return tt(Qt);
132
+ return et(Zt);
133
133
  }
134
134
  });
135
- function Qt({ node: t, updateAttributes: e, selected: r, extension: o }) {
136
- const l = A(null), s = A(null), [c, a] = W(!1), m = t.attrs.src ?? "", v = (o.options.resolveSrc ?? ((w) => w))(m), y = t.attrs.alt ?? "", i = t.attrs.title ?? void 0, g = t.attrs.width, k = t.attrs.align ?? "left";
137
- F(() => {
135
+ function Zt({ node: t, updateAttributes: e, selected: r, extension: o }) {
136
+ const l = L(null), s = L(null), [c, a] = j(!1), m = t.attrs.src ?? "", x = (o.options.resolveSrc ?? ((h) => h))(m), A = t.attrs.alt ?? "", i = t.attrs.title ?? void 0, g = t.attrs.width, k = t.attrs.align ?? "left";
137
+ z(() => {
138
138
  if (!c) return;
139
- const w = (N) => {
139
+ const h = (T) => {
140
140
  const I = s.current;
141
141
  if (!I) return;
142
- const H = N.clientX - I.x, h = Math.max(q, Math.min(_, I.width + H));
143
- e({ width: Math.round(h) });
142
+ const H = T.clientX - I.x, S = Math.max(_, Math.min(K, I.width + H));
143
+ e({ width: Math.round(S) });
144
144
  }, b = () => {
145
145
  s.current = null, a(!1);
146
146
  };
147
- return window.addEventListener("pointermove", w), window.addEventListener("pointerup", b), window.addEventListener("pointercancel", b), () => {
148
- window.removeEventListener("pointermove", w), window.removeEventListener("pointerup", b), window.removeEventListener("pointercancel", b);
147
+ return window.addEventListener("pointermove", h), window.addEventListener("pointerup", b), window.addEventListener("pointercancel", b), () => {
148
+ window.removeEventListener("pointermove", h), window.removeEventListener("pointerup", b), window.removeEventListener("pointercancel", b);
149
149
  };
150
150
  }, [c, e]);
151
- const L = (w) => {
151
+ const v = (h) => {
152
152
  var I;
153
- w.preventDefault(), w.stopPropagation();
154
- const b = (I = l.current) == null ? void 0 : I.querySelector("img"), N = g ?? (b == null ? void 0 : b.getBoundingClientRect().width) ?? 320;
155
- s.current = { x: w.clientX, width: N }, a(!0);
153
+ h.preventDefault(), h.stopPropagation();
154
+ const b = (I = l.current) == null ? void 0 : I.querySelector("img"), T = g ?? (b == null ? void 0 : b.getBoundingClientRect().width) ?? 320;
155
+ s.current = { x: h.clientX, width: T }, a(!0);
156
156
  };
157
- return /* @__PURE__ */ S(
158
- et,
157
+ return /* @__PURE__ */ E(
158
+ rt,
159
159
  {
160
160
  ref: l,
161
161
  "data-resizable-image": "",
162
162
  "data-selected": r ? "true" : void 0,
163
- className: E(
163
+ className: B(
164
164
  "relative block max-w-full align-baseline",
165
165
  "[&>img]:block [&>img]:max-w-full [&>img]:h-auto [&>img]:rounded-md",
166
166
  k === "left" && "mr-auto",
@@ -170,18 +170,18 @@ function Qt({ node: t, updateAttributes: e, selected: r, extension: o }) {
170
170
  ),
171
171
  style: { width: g ? `${g}px` : void 0 },
172
172
  children: [
173
- /* @__PURE__ */ n("img", { src: v, alt: y, title: i, draggable: !1 }),
173
+ /* @__PURE__ */ n("img", { src: x, alt: A, title: i, draggable: !1 }),
174
174
  /* @__PURE__ */ n(
175
175
  "span",
176
176
  {
177
177
  role: "slider",
178
178
  "aria-label": "Resize image",
179
179
  "aria-valuenow": g ?? 0,
180
- "aria-valuemin": q,
181
- "aria-valuemax": _,
180
+ "aria-valuemin": _,
181
+ "aria-valuemax": K,
182
182
  "data-testid": "resize-handle",
183
- onPointerDown: L,
184
- className: E(
183
+ onPointerDown: v,
184
+ className: B(
185
185
  "absolute right-0 bottom-0 h-3 w-3 translate-x-1/2 translate-y-1/2 cursor-nwse-resize",
186
186
  "rounded-full border border-background bg-[color:var(--accent)] shadow",
187
187
  "opacity-0 transition-opacity duration-150 ease-out",
@@ -193,7 +193,7 @@ function Qt({ node: t, updateAttributes: e, selected: r, extension: o }) {
193
193
  }
194
194
  );
195
195
  }
196
- const Zt = vt(It), Gt = [
196
+ const Gt = It(xt), Jt = [
197
197
  /<script[\s>][\s\S]*?<\/script>/gi,
198
198
  /<iframe[\s>][\s\S]*?<\/iframe>/gi,
199
199
  /\s+on\w+\s*=\s*["'][^"']*["']/gi,
@@ -201,42 +201,42 @@ const Zt = vt(It), Gt = [
201
201
  /href\s*=\s*["']?\s*javascript:[^"'\s>]*/gi,
202
202
  /src\s*=\s*["']?\s*javascript:[^"'\s>]*/gi
203
203
  ];
204
- function Jt(t) {
204
+ function Yt(t) {
205
205
  let e = t;
206
- for (const r of Gt)
206
+ for (const r of Jt)
207
207
  e = e.replace(r, "");
208
208
  return e;
209
209
  }
210
- function Yt(t) {
210
+ function te(t) {
211
211
  const r = t.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);
212
212
  return (r == null ? void 0 : r.length) ?? 0;
213
213
  }
214
- function te(t) {
214
+ function ee(t) {
215
215
  return `${t} word${t === 1 ? "" : "s"}`;
216
216
  }
217
- function ee(t) {
217
+ function re(t) {
218
218
  return /^(?:[a-z][a-z0-9+.-]*:|\/|#)/i.test(t);
219
219
  }
220
- function re(t, e) {
221
- return !(t === "" && !e);
220
+ function ne(t, e, r = !1) {
221
+ return e || r;
222
222
  }
223
- function ne(t, e) {
223
+ function ie(t, e) {
224
224
  const r = t.match(/^([^?#]*)([?#].*)?$/), o = (r == null ? void 0 : r[1]) ?? t, l = (r == null ? void 0 : r[2]) ?? "", s = e != null && e.includes("/") ? e.slice(0, e.lastIndexOf("/")) : "", c = `${s ? `${s}/` : ""}${o}`.split("/"), a = [];
225
225
  for (const m of c)
226
226
  !m || m === "." || (m === ".." ? a.pop() : a.push(m));
227
227
  return `${a.join("/")}${l}`;
228
228
  }
229
- function ie(t, e, r, o) {
230
- if (!t || ee(t)) return t;
231
- const l = ne(t, e), s = r.replace(/\/$/, ""), c = new URLSearchParams({ path: l });
229
+ function ae(t, e, r, o) {
230
+ if (!t || re(t)) return t;
231
+ const l = ie(t, e), s = r.replace(/\/$/, ""), c = new URLSearchParams({ path: l });
232
232
  return o && c.set("workspaceId", o), `${s}/api/v1/files/raw?${c.toString()}`;
233
233
  }
234
- function ae(t) {
234
+ function oe(t) {
235
235
  return /^(?:[a-z][a-z0-9+.-]*:|\/\/|\/|#|\?)/i.test(t);
236
236
  }
237
- function Q(t, e) {
237
+ function Z(t, e) {
238
238
  const r = t.trim();
239
- if (!r || ae(r)) return null;
239
+ if (!r || oe(r)) return null;
240
240
  const o = r.split(/[?#]/, 1)[0];
241
241
  if (!o) return null;
242
242
  const l = e != null && e.includes("/") ? e.slice(0, e.lastIndexOf("/")) : "", s = `${l ? `${l}/` : ""}${o}`.split("/"), c = [];
@@ -251,45 +251,45 @@ function Q(t, e) {
251
251
  }
252
252
  return c.join("/") || null;
253
253
  }
254
- function oe(t) {
254
+ function se(t) {
255
255
  return t.button === 0 && !t.metaKey && !t.ctrlKey && !t.altKey && !t.shiftKey;
256
256
  }
257
- const se = [
258
- at.configure({
257
+ const le = [
258
+ ot.configure({
259
259
  codeBlock: !1,
260
260
  link: !1,
261
261
  underline: !1
262
262
  }),
263
- ot,
264
- st.configure({
263
+ st,
264
+ lt.configure({
265
265
  openOnClick: !0,
266
266
  autolink: !0,
267
267
  linkOnPaste: !0,
268
268
  defaultProtocol: "https",
269
- isAllowedUri: (t, e) => z(t) && (Q(t) !== null || e.defaultValidate(t)),
269
+ isAllowedUri: (t, e) => W(t) && (Z(t) !== null || e.defaultValidate(t)),
270
270
  HTMLAttributes: { rel: "noopener noreferrer nofollow", target: "_blank" }
271
271
  }),
272
- P.configure({
272
+ O.configure({
273
273
  placeholder: "Start writing..."
274
274
  }),
275
- lt,
276
- ct.configure({ nested: !0 }),
277
- ut.configure({
275
+ ct,
276
+ ut.configure({ nested: !0 }),
277
+ gt.configure({
278
278
  types: ["heading", "paragraph"]
279
279
  }),
280
- gt,
281
- dt.configure({
280
+ dt,
281
+ ft.configure({
282
282
  resizable: !0
283
283
  }),
284
- ft,
285
284
  pt,
286
285
  mt,
287
- X.configure({
286
+ ht,
287
+ Q.configure({
288
288
  inline: !1,
289
289
  allowBase64: !0
290
290
  }),
291
- bt.configure({ lowlight: Zt }),
292
- xt.configure({
291
+ vt.configure({ lowlight: Gt }),
292
+ yt.configure({
293
293
  markedOptions: {
294
294
  gfm: !0,
295
295
  breaks: !1,
@@ -299,7 +299,7 @@ const se = [
299
299
  ];
300
300
  function f({ onClick: t, active: e, disabled: r, title: o, children: l }) {
301
301
  return /* @__PURE__ */ n(
302
- Pt,
302
+ Ot,
303
303
  {
304
304
  type: "button",
305
305
  size: "icon-xs",
@@ -307,7 +307,7 @@ function f({ onClick: t, active: e, disabled: r, title: o, children: l }) {
307
307
  disabled: r,
308
308
  title: o,
309
309
  "aria-pressed": e,
310
- className: E(
310
+ className: B(
311
311
  "text-muted-foreground/70",
312
312
  e && "bg-[color:var(--accent-soft)] text-[color:var(--accent)]"
313
313
  ),
@@ -315,20 +315,20 @@ function f({ onClick: t, active: e, disabled: r, title: o, children: l }) {
315
315
  }
316
316
  );
317
317
  }
318
- function T() {
319
- return /* @__PURE__ */ n(Ot, { className: "mx-2 h-3.5" });
318
+ function N() {
319
+ return /* @__PURE__ */ n(Vt, { className: "mx-2 h-3.5" });
320
320
  }
321
- function z(t) {
321
+ function W(t) {
322
322
  const e = t.trim().toLowerCase();
323
323
  return !e.startsWith("javascript:") && !e.startsWith("data:text/html");
324
324
  }
325
- function le(t) {
325
+ function ce(t) {
326
326
  return new Promise((e, r) => {
327
327
  const o = new FileReader();
328
328
  o.onload = () => e(o.result), o.onerror = () => r(o.error ?? new Error("Read failed")), o.readAsDataURL(t);
329
329
  });
330
330
  }
331
- function ce(t) {
331
+ function ue(t) {
332
332
  if (!t) return null;
333
333
  for (const e of Array.from(t.files ?? []))
334
334
  if (e.type.startsWith("image/")) return e;
@@ -339,7 +339,7 @@ function ce(t) {
339
339
  }
340
340
  return null;
341
341
  }
342
- function ue({
342
+ function ge({
343
343
  editor: t,
344
344
  onInsertImage: e,
345
345
  rawMode: r,
@@ -354,7 +354,7 @@ function ue({
354
354
  }
355
355
  t.chain().focus().setTextAlign(i).run();
356
356
  }
357
- }, c = A(null), a = it({
357
+ }, c = L(null), a = at({
358
358
  editor: t,
359
359
  selector: ({ editor: i }) => i ? {
360
360
  bold: i.isActive("bold"),
@@ -379,74 +379,74 @@ function ue({
379
379
  if (!t || !a) return null;
380
380
  const m = () => {
381
381
  const i = window.prompt("URL:");
382
- i && z(i) && t.chain().focus().extendMarkRange("link").setLink({ href: i }).run();
382
+ i && W(i) && t.chain().focus().extendMarkRange("link").setLink({ href: i }).run();
383
383
  }, C = () => {
384
384
  const i = window.prompt("Image URL:");
385
- i && z(i) && t.chain().focus().setImage({ src: i }).run();
386
- }, v = (i) => {
385
+ i && W(i) && t.chain().focus().setImage({ src: i }).run();
386
+ }, x = (i) => {
387
387
  var g;
388
388
  if (i != null && i.shiftKey) {
389
389
  C();
390
390
  return;
391
391
  }
392
392
  (g = c.current) == null || g.click();
393
- }, y = async (i) => {
393
+ }, A = async (i) => {
394
394
  var k;
395
395
  const g = (k = i.target.files) == null ? void 0 : k[0];
396
396
  i.target.value = "", !(!g || !g.type.startsWith("image/")) && await e(g);
397
397
  };
398
- return /* @__PURE__ */ S(_t, { className: "border-b border-border/60 bg-background px-3 py-1.5", "aria-label": "Formatting toolbar", children: [
399
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleBold().run(), active: a.bold, title: "Bold", children: /* @__PURE__ */ n(yt, { className: "h-4 w-4" }) }),
400
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleItalic().run(), active: a.italic, title: "Italic", children: /* @__PURE__ */ n(Lt, { className: "h-4 w-4" }) }),
401
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleUnderline().run(), active: a.underline, title: "Underline", children: /* @__PURE__ */ n(At, { className: "h-4 w-4" }) }),
402
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleStrike().run(), active: a.strike, title: "Strikethrough", children: /* @__PURE__ */ n(Ct, { className: "h-4 w-4" }) }),
403
- /* @__PURE__ */ n(T, {}),
404
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHeading({ level: 1 }).run(), active: a.h1, title: "Heading 1", children: /* @__PURE__ */ n(Nt, { className: "h-4 w-4" }) }),
405
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHeading({ level: 2 }).run(), active: a.h2, title: "Heading 2", children: /* @__PURE__ */ n(Tt, { className: "h-4 w-4" }) }),
406
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHeading({ level: 3 }).run(), active: a.h3, title: "Heading 3", children: /* @__PURE__ */ n($t, { className: "h-4 w-4" }) }),
407
- /* @__PURE__ */ n(T, {}),
408
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleBulletList().run(), active: a.bulletList, title: "Bullet list", children: /* @__PURE__ */ n(Mt, { className: "h-4 w-4" }) }),
409
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleOrderedList().run(), active: a.orderedList, title: "Ordered list", children: /* @__PURE__ */ n(Rt, { className: "h-4 w-4" }) }),
410
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleTaskList().run(), active: a.taskList, title: "Task list", children: /* @__PURE__ */ n(Ut, { className: "h-4 w-4" }) }),
411
- /* @__PURE__ */ n(T, {}),
412
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleBlockquote().run(), active: a.blockquote, title: "Quote", children: /* @__PURE__ */ n(Ht, { className: "h-4 w-4" }) }),
413
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleCodeBlock().run(), active: a.codeBlock, title: "Code block", children: /* @__PURE__ */ n(St, { className: "h-4 w-4" }) }),
414
- /* @__PURE__ */ n(f, { onClick: m, active: a.link, title: "Link", children: /* @__PURE__ */ n(Et, { className: "h-4 w-4" }) }),
398
+ return /* @__PURE__ */ E(Kt, { className: "border-b border-border/60 bg-background px-3 py-1.5", "aria-label": "Formatting toolbar", children: [
399
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleBold().run(), active: a.bold, title: "Bold", children: /* @__PURE__ */ n(Lt, { className: "h-4 w-4" }) }),
400
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleItalic().run(), active: a.italic, title: "Italic", children: /* @__PURE__ */ n(At, { className: "h-4 w-4" }) }),
401
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleUnderline().run(), active: a.underline, title: "Underline", children: /* @__PURE__ */ n(Ct, { className: "h-4 w-4" }) }),
402
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleStrike().run(), active: a.strike, title: "Strikethrough", children: /* @__PURE__ */ n(Nt, { className: "h-4 w-4" }) }),
403
+ /* @__PURE__ */ n(N, {}),
404
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHeading({ level: 1 }).run(), active: a.h1, title: "Heading 1", children: /* @__PURE__ */ n(Tt, { className: "h-4 w-4" }) }),
405
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHeading({ level: 2 }).run(), active: a.h2, title: "Heading 2", children: /* @__PURE__ */ n($t, { className: "h-4 w-4" }) }),
406
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHeading({ level: 3 }).run(), active: a.h3, title: "Heading 3", children: /* @__PURE__ */ n(Mt, { className: "h-4 w-4" }) }),
407
+ /* @__PURE__ */ n(N, {}),
408
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleBulletList().run(), active: a.bulletList, title: "Bullet list", children: /* @__PURE__ */ n(Rt, { className: "h-4 w-4" }) }),
409
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleOrderedList().run(), active: a.orderedList, title: "Ordered list", children: /* @__PURE__ */ n(Ut, { className: "h-4 w-4" }) }),
410
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleTaskList().run(), active: a.taskList, title: "Task list", children: /* @__PURE__ */ n(Ht, { className: "h-4 w-4" }) }),
411
+ /* @__PURE__ */ n(N, {}),
412
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleBlockquote().run(), active: a.blockquote, title: "Quote", children: /* @__PURE__ */ n(St, { className: "h-4 w-4" }) }),
413
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleCodeBlock().run(), active: a.codeBlock, title: "Code block", children: /* @__PURE__ */ n(Et, { className: "h-4 w-4" }) }),
414
+ /* @__PURE__ */ n(f, { onClick: m, active: a.link, title: "Link", children: /* @__PURE__ */ n(Bt, { className: "h-4 w-4" }) }),
415
415
  /* @__PURE__ */ n(
416
416
  f,
417
417
  {
418
- onClick: v,
418
+ onClick: x,
419
419
  title: "Image (click to upload, Shift+click for URL)",
420
- children: /* @__PURE__ */ n(Bt, { className: "h-4 w-4" })
420
+ children: /* @__PURE__ */ n(Dt, { className: "h-4 w-4" })
421
421
  }
422
422
  ),
423
423
  /* @__PURE__ */ n(
424
- Kt,
424
+ Pt,
425
425
  {
426
426
  ref: c,
427
427
  "data-testid": "image-file-input",
428
428
  type: "file",
429
429
  accept: "image/*",
430
430
  className: "hidden",
431
- onChange: y
431
+ onChange: A
432
432
  }
433
433
  ),
434
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHighlight().run(), active: a.highlight, title: "Highlight", children: /* @__PURE__ */ n(Dt, { className: "h-4 w-4" }) }),
435
- /* @__PURE__ */ n(T, {}),
436
- /* @__PURE__ */ n(f, { onClick: () => s("left"), active: a.alignLeft, title: "Align left", children: /* @__PURE__ */ n(Ft, { className: "h-4 w-4" }) }),
437
- /* @__PURE__ */ n(f, { onClick: () => s("center"), active: a.alignCenter, title: "Center align", children: /* @__PURE__ */ n(zt, { className: "h-4 w-4" }) }),
438
- /* @__PURE__ */ n(f, { onClick: () => s("right"), active: a.alignRight, title: "Align right", children: /* @__PURE__ */ n(Wt, { className: "h-4 w-4" }) }),
439
- /* @__PURE__ */ n(T, {}),
440
- /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: /* @__PURE__ */ n(jt, { className: "h-4 w-4" }) }),
441
- /* @__PURE__ */ n(T, {}),
442
- l && /* @__PURE__ */ S(
434
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().toggleHighlight().run(), active: a.highlight, title: "Highlight", children: /* @__PURE__ */ n(Ft, { className: "h-4 w-4" }) }),
435
+ /* @__PURE__ */ n(N, {}),
436
+ /* @__PURE__ */ n(f, { onClick: () => s("left"), active: a.alignLeft, title: "Align left", children: /* @__PURE__ */ n(zt, { className: "h-4 w-4" }) }),
437
+ /* @__PURE__ */ n(f, { onClick: () => s("center"), active: a.alignCenter, title: "Center align", children: /* @__PURE__ */ n(Wt, { className: "h-4 w-4" }) }),
438
+ /* @__PURE__ */ n(f, { onClick: () => s("right"), active: a.alignRight, title: "Align right", children: /* @__PURE__ */ n(jt, { className: "h-4 w-4" }) }),
439
+ /* @__PURE__ */ n(N, {}),
440
+ /* @__PURE__ */ n(f, { onClick: () => t.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: /* @__PURE__ */ n(qt, { className: "h-4 w-4" }) }),
441
+ /* @__PURE__ */ n(N, {}),
442
+ l && /* @__PURE__ */ E(
443
443
  "span",
444
444
  {
445
445
  role: "status",
446
446
  "aria-live": "polite",
447
447
  className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground/80",
448
448
  children: [
449
- /* @__PURE__ */ n(qt, { className: "h-3 w-3 animate-spin", "aria-hidden": !0 }),
449
+ /* @__PURE__ */ n(_t, { className: "h-3 w-3 animate-spin", "aria-hidden": !0 }),
450
450
  "Uploading…"
451
451
  ]
452
452
  }
@@ -462,7 +462,7 @@ function ue({
462
462
  )
463
463
  ] });
464
464
  }
465
- function Ee({
465
+ function Be({
466
466
  content: t,
467
467
  onChange: e,
468
468
  readOnly: r = !1,
@@ -470,113 +470,129 @@ function Ee({
470
470
  className: l,
471
471
  documentPath: s
472
472
  }) {
473
- const c = O(), a = V(), { upload: m, uploading: C } = Vt(), [v, y] = W(!1), i = j(() => {
474
- const u = X.configure({
473
+ const c = V(), a = X(), { upload: m, uploading: C } = Xt(), [x, A] = j(!1), i = q(() => {
474
+ const u = Q.configure({
475
475
  inline: !1,
476
476
  allowBase64: !0,
477
- resolveSrc: (p) => ie(p, s, c, a)
478
- }), d = se.map((p) => p.name === "image" ? u : p);
477
+ resolveSrc: (p) => ae(p, s, c, a)
478
+ }), d = le.map((p) => p.name === "image" ? u : p);
479
479
  return o ? [
480
480
  ...d.filter((p) => p.name !== "placeholder"),
481
- P.configure({ placeholder: o })
481
+ O.configure({ placeholder: o })
482
482
  ] : d;
483
- }, [c, s, o, a]), g = A(e);
483
+ }, [c, s, o, a]), g = L(e);
484
484
  g.current = e;
485
- const k = A(!1), L = A(t), w = A(null), b = j(() => Yt(t), [t]), N = A(async () => {
485
+ const k = L(!1), v = L(!1), h = L(t), b = L(null), T = q(() => te(t), [t]), I = L(async () => {
486
486
  });
487
- N.current = async (u) => {
488
- const d = w.current;
487
+ I.current = async (u) => {
488
+ v.current = !0;
489
+ const d = b.current;
489
490
  if (!d) return;
490
491
  let p;
491
492
  try {
492
- p = await le(u);
493
+ p = await ce(u);
493
494
  } catch {
494
495
  return;
495
496
  }
496
- const x = typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `pending-${Date.now()}-${Math.random().toString(36).slice(2)}`, G = { src: p, alt: u.name, pendingUploadId: x };
497
- d.chain().focus().setImage(G).run();
497
+ const y = typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `pending-${Date.now()}-${Math.random().toString(36).slice(2)}`, J = { src: p, alt: u.name, pendingUploadId: y };
498
+ d.chain().focus().setImage(J).run();
498
499
  try {
499
- const { url: $ } = await m(u, { sourcePath: s }), M = w.current;
500
+ const { url: $ } = await m(u, { sourcePath: s }), M = b.current;
500
501
  if (!M || M.isDestroyed) return;
501
- M.commands.command(({ tr: B, state: R }) => (R.doc.descendants((U, J) => (U.type.name === "image" && U.attrs.pendingUploadId === x && B.setNodeMarkup(J, void 0, { ...U.attrs, src: $, pendingUploadId: null }), !0)), !0));
502
+ M.commands.command(({ tr: D, state: R }) => (R.doc.descendants((U, Y) => (U.type.name === "image" && U.attrs.pendingUploadId === y && D.setNodeMarkup(Y, void 0, { ...U.attrs, src: $, pendingUploadId: null }), !0)), !0));
502
503
  } catch {
503
- const $ = w.current;
504
+ const $ = b.current;
504
505
  if (!$ || $.isDestroyed) return;
505
- $.commands.command(({ tr: M, state: B }) => (B.doc.descendants((R, U) => (R.type.name === "image" && R.attrs.pendingUploadId === x && M.setNodeMarkup(U, void 0, { ...R.attrs, pendingUploadId: null }), !0)), !0));
506
+ $.commands.command(({ tr: M, state: D }) => (D.doc.descendants((R, U) => (R.type.name === "image" && R.attrs.pendingUploadId === y && M.setNodeMarkup(U, void 0, { ...R.attrs, pendingUploadId: null }), !0)), !0));
506
507
  }
507
508
  };
508
- const I = t || { type: "doc", content: [{ type: "paragraph" }] }, H = t ? "markdown" : "json", h = rt({
509
+ const H = t || { type: "doc", content: [{ type: "paragraph" }] }, S = t ? "markdown" : "json", w = nt({
509
510
  extensions: i,
510
- content: I,
511
- contentType: H,
511
+ content: H,
512
+ contentType: S,
512
513
  editable: !r,
513
514
  editorProps: {
514
515
  attributes: {
515
516
  class: "tiptap-prose max-w-[68ch] px-8 py-6 focus:outline-none min-h-[200px]"
516
517
  },
517
- transformPastedHTML: Jt,
518
+ transformPastedHTML: Yt,
518
519
  handlePaste: (u, d) => {
519
520
  if (r) return !1;
520
- const p = ce(d.clipboardData);
521
- return p ? (d.preventDefault(), N.current(p), !0) : !1;
521
+ const p = ue(d.clipboardData);
522
+ return p ? (d.preventDefault(), I.current(p), !0) : !1;
522
523
  }
523
524
  },
524
525
  onUpdate: ({ editor: u }) => {
525
- var p, x;
526
+ var p, y;
526
527
  if (k.current) return;
527
528
  const d = ((p = u.getMarkdown) == null ? void 0 : p.call(u)) ?? u.getHTML();
528
- L.current = d, re(d, u.isFocused) && ((x = g.current) == null || x.call(g, d));
529
+ h.current = d, ne(d, u.isFocused, v.current) && ((y = g.current) == null || y.call(g, d));
529
530
  }
530
531
  });
531
- w.current = h, F(() => {
532
- !h || h.isDestroyed || h.setEditable(!r);
533
- }, [h, r]), F(() => {
532
+ b.current = w, z(() => {
533
+ !w || w.isDestroyed || w.setEditable(!r);
534
+ }, [w, r]), z(() => {
534
535
  var d;
535
- !h || h.isDestroyed || t === L.current || (((d = h.getMarkdown) == null ? void 0 : d.call(h)) ?? h.getHTML()) === t || (k.current = !0, h.commands.setContent(I, { contentType: H }), k.current = !1, L.current = t);
536
- }, [h, t]);
537
- const Z = (u) => {
538
- if (!oe(u.nativeEvent)) return;
536
+ !w || w.isDestroyed || t === h.current || (((d = w.getMarkdown) == null ? void 0 : d.call(w)) ?? w.getHTML()) === t || (k.current = !0, w.commands.setContent(H, { contentType: S }), k.current = !1, h.current = t);
537
+ }, [w, t]);
538
+ const G = (u) => {
539
+ if (!se(u.nativeEvent)) return;
539
540
  const d = u.target instanceof Element ? u.target.closest("a[href]") : null, p = d == null ? void 0 : d.getAttribute("href");
540
541
  if (!p) return;
541
- const x = Q(p, s);
542
- x && (u.preventDefault(), u.stopPropagation(), wt({ kind: "openFile", params: { path: x } }));
542
+ const y = Z(p, s);
543
+ y && (u.preventDefault(), u.stopPropagation(), kt({ kind: "openFile", params: { path: y } }));
543
544
  };
544
- return /* @__PURE__ */ S("div", { className: E("flex h-full min-h-0 flex-col overflow-hidden", l), children: [
545
- !r && /* @__PURE__ */ n(
546
- ue,
547
- {
548
- editor: h,
549
- onInsertImage: (u) => N.current(u),
550
- rawMode: v,
551
- onToggleRawMode: () => y((u) => !u),
552
- uploading: C
553
- }
554
- ),
555
- /* @__PURE__ */ n("div", { className: "min-h-0 flex-1 overflow-auto", onClickCapture: Z, children: v && !r ? /* @__PURE__ */ n(
556
- "textarea",
557
- {
558
- "aria-label": "Raw markdown",
559
- "data-testid": "markdown-raw-editor",
560
- 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",
561
- value: t,
562
- placeholder: o,
563
- spellCheck: !1,
564
- onChange: (u) => {
565
- var d;
566
- return (d = g.current) == null ? void 0 : d.call(g, u.target.value);
567
- }
568
- }
569
- ) : /* @__PURE__ */ n(nt, { editor: h }) }),
570
- /* @__PURE__ */ n("div", { className: "border-t border-border/60 px-4 py-2 text-right text-xs text-muted-foreground", "data-testid": "markdown-word-count", children: te(b) })
571
- ] });
545
+ return /* @__PURE__ */ E(
546
+ "div",
547
+ {
548
+ className: B("flex h-full min-h-0 flex-col overflow-hidden", l),
549
+ onPointerDownCapture: () => {
550
+ v.current = !0;
551
+ },
552
+ onClickCapture: () => {
553
+ v.current = !0;
554
+ },
555
+ onKeyDownCapture: () => {
556
+ v.current = !0;
557
+ },
558
+ children: [
559
+ !r && /* @__PURE__ */ n(
560
+ ge,
561
+ {
562
+ editor: w,
563
+ onInsertImage: (u) => I.current(u),
564
+ rawMode: x,
565
+ onToggleRawMode: () => A((u) => !u),
566
+ uploading: C
567
+ }
568
+ ),
569
+ /* @__PURE__ */ n("div", { className: "min-h-0 flex-1 overflow-auto", onClickCapture: G, children: x && !r ? /* @__PURE__ */ n(
570
+ "textarea",
571
+ {
572
+ "aria-label": "Raw markdown",
573
+ "data-testid": "markdown-raw-editor",
574
+ 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",
575
+ value: t,
576
+ placeholder: o,
577
+ spellCheck: !1,
578
+ onChange: (u) => {
579
+ var d;
580
+ return (d = g.current) == null ? void 0 : d.call(g, u.target.value);
581
+ }
582
+ }
583
+ ) : /* @__PURE__ */ n(it, { editor: w }) }),
584
+ /* @__PURE__ */ n("div", { className: "border-t border-border/60 px-4 py-2 text-right text-xs text-muted-foreground", "data-testid": "markdown-word-count", children: ee(T) })
585
+ ]
586
+ }
587
+ );
572
588
  }
573
589
  export {
574
- Ee as MarkdownEditor,
575
- Yt as countMarkdownWords,
576
- z as isSafeUrl,
577
- re as isUserEditedChange,
578
- ie as rawFileUrlForMarkdownImage,
579
- le as readFileAsDataUrl,
580
- Jt as sanitizeHtml,
581
- Q as workspaceFilePathForMarkdownLink
590
+ Be as MarkdownEditor,
591
+ te as countMarkdownWords,
592
+ W as isSafeUrl,
593
+ ne as isUserEditedChange,
594
+ ae as rawFileUrlForMarkdownImage,
595
+ ce as readFileAsDataUrl,
596
+ Yt as sanitizeHtml,
597
+ Z as workspaceFilePathForMarkdownLink
582
598
  };