@hachej/boring-workspace 0.1.7 → 0.1.9

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,474 +0,0 @@
1
- import { jsxs as C, jsx as e } from "react/jsx-runtime";
2
- import { useState as x, useCallback as U, useRef as A, useEffect as N } from "react";
3
- import { ReactNodeViewRenderer as $, NodeViewWrapper as E, useEditor as P, EditorContent as F, useEditorState as D } from "@tiptap/react";
4
- import z from "@tiptap/starter-kit";
5
- import W from "@tiptap/extension-underline";
6
- import q from "@tiptap/extension-link";
7
- import S from "@tiptap/extension-placeholder";
8
- import j from "@tiptap/extension-task-list";
9
- import _ from "@tiptap/extension-task-item";
10
- import V from "@tiptap/extension-text-align";
11
- import X from "@tiptap/extension-highlight";
12
- import { Table as K } from "@tiptap/extension-table";
13
- import { TableRow as Q } from "@tiptap/extension-table-row";
14
- import { TableHeader as O } from "@tiptap/extension-table-header";
15
- import { TableCell as Z } from "@tiptap/extension-table-cell";
16
- import G from "@tiptap/extension-image";
17
- import { c as L } from "./utils-B6yFEsav.js";
18
- import { uploadFile as J } from "@hachej/boring-agent/front";
19
- import { an as Y, ao as tt } from "./CommandPalette-DzIDQUfk.js";
20
- import et from "@tiptap/extension-code-block-lowlight";
21
- import { createLowlight as it, common as rt } from "lowlight";
22
- import { Markdown as nt } from "@tiptap/markdown";
23
- import { BoldIcon as at, ItalicIcon as ot, UnderlineIcon as lt, StrikethroughIcon as st, Heading1Icon as ct, Heading2Icon as ut, Heading3Icon as gt, ListIcon as ft, ListOrderedIcon as dt, ListChecksIcon as mt, QuoteIcon as ht, CodeIcon as pt, LinkIcon as wt, ImageIcon as kt, HighlighterIcon as bt, AlignLeftIcon as vt, AlignCenterIcon as At, AlignRightIcon as It, MinusIcon as Lt } from "lucide-react";
24
- import { Toolbar as yt, Input as Nt, ToolbarButton as Ct, ToolbarSeparator as xt } from "@hachej/boring-ui-kit";
25
- function Tt(t) {
26
- const r = Y(), n = tt(), [a, s] = x(0);
27
- return { upload: U(
28
- async (o, h) => {
29
- s((b) => b + 1);
30
- try {
31
- return await J(o, {
32
- apiBaseUrl: r,
33
- workspaceRequestId: n,
34
- directory: (h == null ? void 0 : h.directory) ?? (t == null ? void 0 : t.directory),
35
- sourcePath: h == null ? void 0 : h.sourcePath
36
- });
37
- } finally {
38
- s((b) => b - 1);
39
- }
40
- },
41
- [r, n, t == null ? void 0 : t.directory]
42
- ), uploading: a > 0 };
43
- }
44
- const T = 64, R = 2e3;
45
- function Rt(t) {
46
- return t.replace(/\\/g, "\\\\").replace(/]/g, "\\]");
47
- }
48
- function y(t) {
49
- return t.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
50
- }
51
- function H(t) {
52
- if (typeof t == "number" && Number.isFinite(t) && t > 0) return t;
53
- if (typeof t == "string" && t.trim()) {
54
- const r = Number(t);
55
- if (Number.isFinite(r) && r > 0) return r;
56
- }
57
- return null;
58
- }
59
- const Ht = G.extend({
60
- name: "image",
61
- draggable: !0,
62
- parseMarkdown: (t, r) => r.createNode("image", {
63
- src: t.href,
64
- title: t.title,
65
- alt: t.text
66
- }),
67
- renderMarkdown: (t) => {
68
- var p, k, i, d, m, w, c;
69
- const r = typeof ((p = t.attrs) == null ? void 0 : p.src) == "string" ? t.attrs.src : "", n = typeof ((k = t.attrs) == null ? void 0 : k.alt) == "string" ? t.attrs.alt : "", a = typeof ((i = t.attrs) == null ? void 0 : i.title) == "string" ? t.attrs.title : "", s = H((d = t.attrs) == null ? void 0 : d.width), g = H((m = t.attrs) == null ? void 0 : m.height), o = ((w = t.attrs) == null ? void 0 : w.align) === "center" || ((c = t.attrs) == null ? void 0 : c.align) === "right" ? t.attrs.align : "left";
70
- if (!s && !g && o === "left") {
71
- const l = Rt(n);
72
- return a ? `![${l}](${r} "${a.replace(/"/g, '\\"')}")` : `![${l}](${r})`;
73
- }
74
- const b = `<img ${[
75
- `src="${y(r)}"`,
76
- n ? `alt="${y(n)}"` : null,
77
- a ? `title="${y(a)}"` : null,
78
- s ? `width="${s}"` : null,
79
- g ? `height="${g}"` : null
80
- ].filter(Boolean).join(" ")} />`;
81
- return o === "center" || o === "right" ? `<p align="${o}">${b}</p>` : b;
82
- },
83
- addAttributes() {
84
- var r;
85
- return {
86
- ...((r = this.parent) == null ? void 0 : r.call(this)) ?? {},
87
- width: {
88
- default: null,
89
- parseHTML: (n) => {
90
- const a = n.getAttribute("width");
91
- if (a) {
92
- const g = parseInt(a, 10);
93
- return Number.isFinite(g) ? g : null;
94
- }
95
- const s = n.style.width;
96
- if (s && s.endsWith("px")) {
97
- const g = parseInt(s, 10);
98
- return Number.isFinite(g) ? g : null;
99
- }
100
- return null;
101
- },
102
- renderHTML: (n) => n.width ? { width: String(n.width) } : {}
103
- },
104
- align: {
105
- default: "left",
106
- parseHTML: (n) => {
107
- const a = n.getAttribute("data-align");
108
- return a === "left" || a === "center" || a === "right" ? a : n.style.marginLeft === "auto" && n.style.marginRight === "auto" ? "center" : n.style.marginLeft === "auto" ? "right" : "left";
109
- },
110
- renderHTML: (n) => ({ "data-align": n.align ?? "left" })
111
- }
112
- };
113
- },
114
- addNodeView() {
115
- return $(Mt);
116
- }
117
- });
118
- function Mt({ node: t, updateAttributes: r, selected: n }) {
119
- const a = A(null), s = A(null), [g, o] = x(!1), h = t.attrs.src ?? "", b = t.attrs.alt ?? "", p = t.attrs.title ?? void 0, k = t.attrs.width, i = t.attrs.align ?? "left";
120
- N(() => {
121
- if (!g) return;
122
- const m = (c) => {
123
- const l = s.current;
124
- if (!l) return;
125
- const f = c.clientX - l.x, v = Math.max(T, Math.min(R, l.width + f));
126
- r({ width: Math.round(v) });
127
- }, w = () => {
128
- s.current = null, o(!1);
129
- };
130
- return window.addEventListener("pointermove", m), window.addEventListener("pointerup", w), window.addEventListener("pointercancel", w), () => {
131
- window.removeEventListener("pointermove", m), window.removeEventListener("pointerup", w), window.removeEventListener("pointercancel", w);
132
- };
133
- }, [g, r]);
134
- const d = (m) => {
135
- var l;
136
- m.preventDefault(), m.stopPropagation();
137
- const w = (l = a.current) == null ? void 0 : l.querySelector("img"), c = k ?? (w == null ? void 0 : w.getBoundingClientRect().width) ?? 320;
138
- s.current = { x: m.clientX, width: c }, o(!0);
139
- };
140
- return /* @__PURE__ */ C(
141
- E,
142
- {
143
- ref: a,
144
- "data-resizable-image": "",
145
- "data-selected": n ? "true" : void 0,
146
- className: L(
147
- "relative block max-w-full align-baseline",
148
- "[&>img]:block [&>img]:max-w-full [&>img]:h-auto [&>img]:rounded-md",
149
- i === "left" && "mr-auto",
150
- i === "center" && "mx-auto",
151
- i === "right" && "ml-auto",
152
- n && "ring-2 ring-[color:var(--accent)] ring-offset-1 ring-offset-background"
153
- ),
154
- style: { width: k ? `${k}px` : void 0 },
155
- children: [
156
- /* @__PURE__ */ e("img", { src: h, alt: b, title: p, draggable: !1 }),
157
- /* @__PURE__ */ e(
158
- "span",
159
- {
160
- role: "slider",
161
- "aria-label": "Resize image",
162
- "aria-valuenow": k ?? 0,
163
- "aria-valuemin": T,
164
- "aria-valuemax": R,
165
- "data-testid": "resize-handle",
166
- onPointerDown: d,
167
- className: L(
168
- "absolute right-0 bottom-0 h-3 w-3 translate-x-1/2 translate-y-1/2 cursor-nwse-resize",
169
- "rounded-full border border-background bg-[color:var(--accent)] shadow",
170
- "opacity-0 transition-opacity duration-150 ease-out",
171
- (n || g) && "opacity-100"
172
- )
173
- }
174
- )
175
- ]
176
- }
177
- );
178
- }
179
- const Bt = it(rt), St = [
180
- /<script[\s>][\s\S]*?<\/script>/gi,
181
- /<iframe[\s>][\s\S]*?<\/iframe>/gi,
182
- /\s+on\w+\s*=\s*["'][^"']*["']/gi,
183
- /\s+on\w+\s*=\s*\S+/gi,
184
- /href\s*=\s*["']?\s*javascript:[^"'\s>]*/gi,
185
- /src\s*=\s*["']?\s*javascript:[^"'\s>]*/gi
186
- ];
187
- function Ut(t) {
188
- let r = t;
189
- for (const n of St)
190
- r = r.replace(n, "");
191
- return r;
192
- }
193
- const M = [
194
- z.configure({
195
- codeBlock: !1,
196
- link: !1,
197
- underline: !1
198
- }),
199
- W,
200
- q.configure({
201
- openOnClick: !0,
202
- autolink: !0,
203
- linkOnPaste: !0,
204
- defaultProtocol: "https",
205
- HTMLAttributes: { rel: "noopener noreferrer nofollow", target: "_blank" }
206
- }),
207
- S.configure({
208
- placeholder: "Start writing..."
209
- }),
210
- j,
211
- _.configure({ nested: !0 }),
212
- V.configure({
213
- types: ["heading", "paragraph"]
214
- }),
215
- X,
216
- K.configure({
217
- resizable: !0
218
- }),
219
- Q,
220
- O,
221
- Z,
222
- Ht.configure({
223
- inline: !1,
224
- allowBase64: !0
225
- }),
226
- et.configure({ lowlight: Bt }),
227
- nt.configure({
228
- markedOptions: {
229
- gfm: !0,
230
- breaks: !1,
231
- pedantic: !1
232
- }
233
- })
234
- ];
235
- function u({ onClick: t, active: r, disabled: n, title: a, children: s }) {
236
- return /* @__PURE__ */ e(
237
- Ct,
238
- {
239
- type: "button",
240
- size: "icon-xs",
241
- onClick: t,
242
- disabled: n,
243
- title: a,
244
- "aria-pressed": r,
245
- className: L(
246
- "text-muted-foreground/70",
247
- r && "bg-[color:var(--accent-soft)] text-[color:var(--accent)]"
248
- ),
249
- children: s
250
- }
251
- );
252
- }
253
- function I() {
254
- return /* @__PURE__ */ e(xt, { className: "mx-2 h-3.5" });
255
- }
256
- function B(t) {
257
- const r = t.trim().toLowerCase();
258
- return !r.startsWith("javascript:") && !r.startsWith("data:text/html");
259
- }
260
- function $t(t) {
261
- return new Promise((r, n) => {
262
- const a = new FileReader();
263
- a.onload = () => r(a.result), a.onerror = () => n(a.error ?? new Error("Read failed")), a.readAsDataURL(t);
264
- });
265
- }
266
- function Et(t) {
267
- if (!t) return null;
268
- for (const r of Array.from(t.files ?? []))
269
- if (r.type.startsWith("image/")) return r;
270
- for (const r of Array.from(t.items ?? [])) {
271
- if (r.kind !== "file" || !r.type.startsWith("image/")) continue;
272
- const n = r.getAsFile();
273
- if (n) return n;
274
- }
275
- return null;
276
- }
277
- function Pt({
278
- editor: t,
279
- onInsertImage: r,
280
- rawMode: n,
281
- onToggleRawMode: a
282
- }) {
283
- const s = (i) => {
284
- if (t) {
285
- if (t.isActive("image")) {
286
- t.chain().focus().updateAttributes("image", { align: i }).run();
287
- return;
288
- }
289
- t.chain().focus().setTextAlign(i).run();
290
- }
291
- }, g = A(null), o = D({
292
- editor: t,
293
- selector: ({ editor: i }) => i ? {
294
- bold: i.isActive("bold"),
295
- italic: i.isActive("italic"),
296
- underline: i.isActive("underline"),
297
- strike: i.isActive("strike"),
298
- h1: i.isActive("heading", { level: 1 }),
299
- h2: i.isActive("heading", { level: 2 }),
300
- h3: i.isActive("heading", { level: 3 }),
301
- bulletList: i.isActive("bulletList"),
302
- orderedList: i.isActive("orderedList"),
303
- taskList: i.isActive("taskList"),
304
- blockquote: i.isActive("blockquote"),
305
- codeBlock: i.isActive("codeBlock"),
306
- link: i.isActive("link"),
307
- highlight: i.isActive("highlight"),
308
- alignLeft: i.isActive("image") ? (i.getAttributes("image").align ?? "left") === "left" : i.isActive({ textAlign: "left" }),
309
- alignCenter: i.isActive("image") ? i.getAttributes("image").align === "center" : i.isActive({ textAlign: "center" }),
310
- alignRight: i.isActive("image") ? i.getAttributes("image").align === "right" : i.isActive({ textAlign: "right" })
311
- } : null
312
- });
313
- if (!t || !o) return null;
314
- const h = () => {
315
- const i = window.prompt("URL:");
316
- i && B(i) && t.chain().focus().extendMarkRange("link").setLink({ href: i }).run();
317
- }, b = () => {
318
- const i = window.prompt("Image URL:");
319
- i && B(i) && t.chain().focus().setImage({ src: i }).run();
320
- }, p = (i) => {
321
- var d;
322
- if (i != null && i.shiftKey) {
323
- b();
324
- return;
325
- }
326
- (d = g.current) == null || d.click();
327
- }, k = async (i) => {
328
- var m;
329
- const d = (m = i.target.files) == null ? void 0 : m[0];
330
- i.target.value = "", !(!d || !d.type.startsWith("image/")) && await r(d);
331
- };
332
- return /* @__PURE__ */ C(yt, { className: "border-b border-border/60 bg-background px-3 py-1.5", "aria-label": "Formatting toolbar", children: [
333
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleBold().run(), active: o.bold, title: "Bold", children: /* @__PURE__ */ e(at, { className: "h-4 w-4" }) }),
334
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleItalic().run(), active: o.italic, title: "Italic", children: /* @__PURE__ */ e(ot, { className: "h-4 w-4" }) }),
335
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleUnderline().run(), active: o.underline, title: "Underline", children: /* @__PURE__ */ e(lt, { className: "h-4 w-4" }) }),
336
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleStrike().run(), active: o.strike, title: "Strikethrough", children: /* @__PURE__ */ e(st, { className: "h-4 w-4" }) }),
337
- /* @__PURE__ */ e(I, {}),
338
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleHeading({ level: 1 }).run(), active: o.h1, title: "Heading 1", children: /* @__PURE__ */ e(ct, { className: "h-4 w-4" }) }),
339
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleHeading({ level: 2 }).run(), active: o.h2, title: "Heading 2", children: /* @__PURE__ */ e(ut, { className: "h-4 w-4" }) }),
340
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleHeading({ level: 3 }).run(), active: o.h3, title: "Heading 3", children: /* @__PURE__ */ e(gt, { className: "h-4 w-4" }) }),
341
- /* @__PURE__ */ e(I, {}),
342
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleBulletList().run(), active: o.bulletList, title: "Bullet list", children: /* @__PURE__ */ e(ft, { className: "h-4 w-4" }) }),
343
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleOrderedList().run(), active: o.orderedList, title: "Ordered list", children: /* @__PURE__ */ e(dt, { className: "h-4 w-4" }) }),
344
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleTaskList().run(), active: o.taskList, title: "Task list", children: /* @__PURE__ */ e(mt, { className: "h-4 w-4" }) }),
345
- /* @__PURE__ */ e(I, {}),
346
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleBlockquote().run(), active: o.blockquote, title: "Quote", children: /* @__PURE__ */ e(ht, { className: "h-4 w-4" }) }),
347
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleCodeBlock().run(), active: o.codeBlock, title: "Code block", children: /* @__PURE__ */ e(pt, { className: "h-4 w-4" }) }),
348
- /* @__PURE__ */ e(u, { onClick: h, active: o.link, title: "Link", children: /* @__PURE__ */ e(wt, { className: "h-4 w-4" }) }),
349
- /* @__PURE__ */ e(
350
- u,
351
- {
352
- onClick: p,
353
- title: "Image (click to upload, Shift+click for URL)",
354
- children: /* @__PURE__ */ e(kt, { className: "h-4 w-4" })
355
- }
356
- ),
357
- /* @__PURE__ */ e(
358
- Nt,
359
- {
360
- ref: g,
361
- "data-testid": "image-file-input",
362
- type: "file",
363
- accept: "image/*",
364
- className: "hidden",
365
- onChange: k
366
- }
367
- ),
368
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().toggleHighlight().run(), active: o.highlight, title: "Highlight", children: /* @__PURE__ */ e(bt, { className: "h-4 w-4" }) }),
369
- /* @__PURE__ */ e(I, {}),
370
- /* @__PURE__ */ e(u, { onClick: () => s("left"), active: o.alignLeft, title: "Align left", children: /* @__PURE__ */ e(vt, { className: "h-4 w-4" }) }),
371
- /* @__PURE__ */ e(u, { onClick: () => s("center"), active: o.alignCenter, title: "Center align", children: /* @__PURE__ */ e(At, { className: "h-4 w-4" }) }),
372
- /* @__PURE__ */ e(u, { onClick: () => s("right"), active: o.alignRight, title: "Align right", children: /* @__PURE__ */ e(It, { className: "h-4 w-4" }) }),
373
- /* @__PURE__ */ e(I, {}),
374
- /* @__PURE__ */ e(u, { onClick: () => t.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: /* @__PURE__ */ e(Lt, { className: "h-4 w-4" }) }),
375
- /* @__PURE__ */ e(I, {}),
376
- /* @__PURE__ */ e(
377
- u,
378
- {
379
- onClick: a,
380
- active: n,
381
- title: n ? "Rich text" : "Raw markdown",
382
- children: /* @__PURE__ */ e("span", { className: "font-mono text-[10px] font-semibold leading-none tracking-[-0.02em]", children: "MD" })
383
- }
384
- )
385
- ] });
386
- }
387
- function se({
388
- content: t,
389
- onChange: r,
390
- readOnly: n = !1,
391
- placeholder: a,
392
- className: s,
393
- documentPath: g
394
- }) {
395
- const { upload: o } = Tt(), [h, b] = x(!1), p = A(r);
396
- p.current = r;
397
- const k = A(!1), i = A(null), d = A(async () => {
398
- });
399
- d.current = async (l) => {
400
- const f = i.current;
401
- if (f)
402
- try {
403
- const { url: v } = await o(l, { sourcePath: g });
404
- f.chain().focus().setImage({ src: v, alt: l.name }).run();
405
- } catch {
406
- try {
407
- const v = await $t(l);
408
- f.chain().focus().setImage({ src: v, alt: l.name }).run();
409
- } catch {
410
- }
411
- }
412
- };
413
- const m = t || { type: "doc", content: [{ type: "paragraph" }] }, w = t ? "markdown" : "json", c = P({
414
- extensions: a ? [
415
- ...M.filter((l) => l.name !== "placeholder"),
416
- S.configure({ placeholder: a })
417
- ] : M,
418
- content: m,
419
- contentType: w,
420
- editable: !n,
421
- editorProps: {
422
- attributes: {
423
- class: "tiptap-prose max-w-[68ch] px-8 py-6 focus:outline-none min-h-[200px]"
424
- },
425
- transformPastedHTML: Ut,
426
- handlePaste: (l, f) => {
427
- if (n) return !1;
428
- const v = Et(f.clipboardData);
429
- return v ? (f.preventDefault(), d.current(v), !0) : !1;
430
- }
431
- },
432
- onUpdate: ({ editor: l }) => {
433
- var f, v;
434
- k.current || (v = p.current) == null || v.call(p, ((f = l.getMarkdown) == null ? void 0 : f.call(l)) ?? l.getHTML());
435
- }
436
- });
437
- return i.current = c, N(() => {
438
- !c || c.isDestroyed || c.setEditable(!n);
439
- }, [c, n]), N(() => {
440
- var f;
441
- !c || c.isDestroyed || (((f = c.getMarkdown) == null ? void 0 : f.call(c)) ?? c.getHTML()) === t || (k.current = !0, c.commands.setContent(m, { contentType: w }), k.current = !1);
442
- }, [c, t]), /* @__PURE__ */ C("div", { className: L("flex h-full flex-col overflow-hidden", s), children: [
443
- !n && /* @__PURE__ */ e(
444
- Pt,
445
- {
446
- editor: c,
447
- onInsertImage: (l) => d.current(l),
448
- rawMode: h,
449
- onToggleRawMode: () => b((l) => !l)
450
- }
451
- ),
452
- /* @__PURE__ */ e("div", { className: "flex-1 overflow-auto", children: h && !n ? /* @__PURE__ */ e(
453
- "textarea",
454
- {
455
- "aria-label": "Raw markdown",
456
- "data-testid": "markdown-raw-editor",
457
- 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",
458
- value: t,
459
- placeholder: a,
460
- spellCheck: !1,
461
- onChange: (l) => {
462
- var f;
463
- return (f = p.current) == null ? void 0 : f.call(p, l.target.value);
464
- }
465
- }
466
- ) : /* @__PURE__ */ e(F, { editor: c }) })
467
- ] });
468
- }
469
- export {
470
- se as MarkdownEditor,
471
- B as isSafeUrl,
472
- $t as readFileAsDataUrl,
473
- Ut as sanitizeHtml
474
- };