@hachej/boring-workspace 0.1.16 → 0.1.17
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.
- package/dist/{CommandPalette-NOEOVkN2.js → CommandPalette-CJHuTJlD.js} +284 -282
- package/dist/{FileTree-Dl-qUAB0.js → FileTree-Dvaud3jU.js} +1 -1
- package/dist/MarkdownEditor-sLkqTXDj.js +534 -0
- package/dist/{WorkspaceLoadingState-CSZfENWe.js → WorkspaceLoadingState-zLzh1tGc.js} +1 -1
- package/dist/app-front.js +2 -2
- package/dist/testing.js +1 -1
- package/dist/workspace.js +5 -5
- package/package.json +3 -3
- package/dist/MarkdownEditor-yc6mFsnI.js +0 -533
|
@@ -2,7 +2,7 @@ import { jsx as i, jsxs as C } from "react/jsx-runtime";
|
|
|
2
2
|
import { useRef as w, useEffect as R, useMemo as P, useCallback as x, createContext as H, useContext as L } from "react";
|
|
3
3
|
import { Tree as q } from "react-arborist";
|
|
4
4
|
import { FolderOpenIcon as z, FolderIcon as B, ChevronRightIcon as E, Loader2Icon as J } from "lucide-react";
|
|
5
|
-
import { J as K } from "./CommandPalette-
|
|
5
|
+
import { J as K } from "./CommandPalette-CJHuTJlD.js";
|
|
6
6
|
import { Input as Y } from "@hachej/boring-ui-kit";
|
|
7
7
|
import { c as v } from "./utils-B6yFEsav.js";
|
|
8
8
|
const T = /* @__PURE__ */ new Set(), A = H({
|
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { jsxs as H, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { useState as E, useCallback as K, useRef as L, useEffect as D, useMemo as Q } from "react";
|
|
3
|
+
import { ReactNodeViewRenderer as Z, NodeViewWrapper as G, useEditor as J, EditorContent as Y, useEditorState as tt } from "@tiptap/react";
|
|
4
|
+
import et from "@tiptap/starter-kit";
|
|
5
|
+
import rt from "@tiptap/extension-underline";
|
|
6
|
+
import it from "@tiptap/extension-link";
|
|
7
|
+
import j from "@tiptap/extension-placeholder";
|
|
8
|
+
import nt from "@tiptap/extension-task-list";
|
|
9
|
+
import at from "@tiptap/extension-task-item";
|
|
10
|
+
import ot from "@tiptap/extension-text-align";
|
|
11
|
+
import lt from "@tiptap/extension-highlight";
|
|
12
|
+
import { Table as st } from "@tiptap/extension-table";
|
|
13
|
+
import { TableRow as ct } from "@tiptap/extension-table-row";
|
|
14
|
+
import { TableHeader as ut } from "@tiptap/extension-table-header";
|
|
15
|
+
import { TableCell as gt } from "@tiptap/extension-table-cell";
|
|
16
|
+
import dt from "@tiptap/extension-image";
|
|
17
|
+
import { c as U } from "./utils-B6yFEsav.js";
|
|
18
|
+
import { ao as q, ap as _ } from "./CommandPalette-CJHuTJlD.js";
|
|
19
|
+
import { uploadFile as ft } from "@hachej/boring-agent/front";
|
|
20
|
+
import mt from "@tiptap/extension-code-block-lowlight";
|
|
21
|
+
import { createLowlight as pt, common as ht } from "lowlight";
|
|
22
|
+
import { Markdown as wt } from "@tiptap/markdown";
|
|
23
|
+
import { BoldIcon as kt, ItalicIcon as vt, UnderlineIcon as bt, StrikethroughIcon as It, Heading1Icon as At, Heading2Icon as yt, Heading3Icon as Lt, ListIcon as xt, ListOrderedIcon as Nt, ListChecksIcon as Ct, QuoteIcon as Tt, CodeIcon as Mt, LinkIcon as Rt, ImageIcon as Ht, HighlighterIcon as Ut, AlignLeftIcon as St, AlignCenterIcon as $t, AlignRightIcon as Bt, MinusIcon as Dt, Loader2Icon as Et } from "lucide-react";
|
|
24
|
+
import { Toolbar as Ft, Input as zt, ToolbarButton as Wt, ToolbarSeparator as Pt } from "@hachej/boring-ui-kit";
|
|
25
|
+
function jt(t) {
|
|
26
|
+
const r = q(), i = _(), [a, s] = E(0);
|
|
27
|
+
return { upload: K(
|
|
28
|
+
async (g, o) => {
|
|
29
|
+
s((p) => p + 1);
|
|
30
|
+
try {
|
|
31
|
+
return await ft(g, {
|
|
32
|
+
apiBaseUrl: r,
|
|
33
|
+
workspaceRequestId: i,
|
|
34
|
+
directory: (o == null ? void 0 : o.directory) ?? (t == null ? void 0 : t.directory),
|
|
35
|
+
sourcePath: o == null ? void 0 : o.sourcePath
|
|
36
|
+
});
|
|
37
|
+
} finally {
|
|
38
|
+
s((p) => p - 1);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
[r, i, t == null ? void 0 : t.directory]
|
|
42
|
+
), uploading: a > 0 };
|
|
43
|
+
}
|
|
44
|
+
const F = 64, z = 2e3;
|
|
45
|
+
function qt(t) {
|
|
46
|
+
return t.replace(/\\/g, "\\\\").replace(/]/g, "\\]");
|
|
47
|
+
}
|
|
48
|
+
function B(t) {
|
|
49
|
+
return t.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
50
|
+
}
|
|
51
|
+
function W(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 O = dt.extend({
|
|
60
|
+
name: "image",
|
|
61
|
+
draggable: !0,
|
|
62
|
+
addOptions() {
|
|
63
|
+
var t;
|
|
64
|
+
return {
|
|
65
|
+
...(t = this.parent) == null ? void 0 : t.call(this),
|
|
66
|
+
resolveSrc: (r) => r
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
parseMarkdown: (t, r) => r.createNode("image", {
|
|
70
|
+
src: t.href,
|
|
71
|
+
title: t.title,
|
|
72
|
+
alt: t.text
|
|
73
|
+
}),
|
|
74
|
+
renderMarkdown: (t) => {
|
|
75
|
+
var y, b, A, n, c, k, I;
|
|
76
|
+
const r = typeof ((y = t.attrs) == null ? void 0 : y.src) == "string" ? t.attrs.src : "", i = typeof ((b = t.attrs) == null ? void 0 : b.alt) == "string" ? t.attrs.alt : "", a = typeof ((A = t.attrs) == null ? void 0 : A.title) == "string" ? t.attrs.title : "", s = W((n = t.attrs) == null ? void 0 : n.width), l = W((c = t.attrs) == null ? void 0 : c.height), g = ((k = t.attrs) == null ? void 0 : k.align) === "center" || ((I = t.attrs) == null ? void 0 : I.align) === "right" ? t.attrs.align : "left";
|
|
77
|
+
if (!s && !l && g === "left") {
|
|
78
|
+
const h = qt(i);
|
|
79
|
+
return a ? `}")` : ``;
|
|
80
|
+
}
|
|
81
|
+
const p = `<img ${[
|
|
82
|
+
`src="${B(r)}"`,
|
|
83
|
+
i ? `alt="${B(i)}"` : null,
|
|
84
|
+
a ? `title="${B(a)}"` : null,
|
|
85
|
+
s ? `width="${s}"` : null,
|
|
86
|
+
l ? `height="${l}"` : null
|
|
87
|
+
].filter(Boolean).join(" ")} />`;
|
|
88
|
+
return g === "center" || g === "right" ? `<p align="${g}">${p}</p>` : p;
|
|
89
|
+
},
|
|
90
|
+
addAttributes() {
|
|
91
|
+
var r;
|
|
92
|
+
return {
|
|
93
|
+
...((r = this.parent) == null ? void 0 : r.call(this)) ?? {},
|
|
94
|
+
width: {
|
|
95
|
+
default: null,
|
|
96
|
+
parseHTML: (i) => {
|
|
97
|
+
const a = i.getAttribute("width");
|
|
98
|
+
if (a) {
|
|
99
|
+
const l = parseInt(a, 10);
|
|
100
|
+
return Number.isFinite(l) ? l : null;
|
|
101
|
+
}
|
|
102
|
+
const s = i.style.width;
|
|
103
|
+
if (s && s.endsWith("px")) {
|
|
104
|
+
const l = parseInt(s, 10);
|
|
105
|
+
return Number.isFinite(l) ? l : null;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
},
|
|
109
|
+
renderHTML: (i) => i.width ? { width: String(i.width) } : {}
|
|
110
|
+
},
|
|
111
|
+
align: {
|
|
112
|
+
default: "left",
|
|
113
|
+
parseHTML: (i) => {
|
|
114
|
+
const a = i.getAttribute("data-align");
|
|
115
|
+
return a === "left" || a === "center" || a === "right" ? a : i.style.marginLeft === "auto" && i.style.marginRight === "auto" ? "center" : i.style.marginLeft === "auto" ? "right" : "left";
|
|
116
|
+
},
|
|
117
|
+
renderHTML: (i) => ({ "data-align": i.align ?? "left" })
|
|
118
|
+
},
|
|
119
|
+
// Transient marker used by MarkdownEditor.insertImageRef to find THIS
|
|
120
|
+
// specific inserted image when its background upload completes, even
|
|
121
|
+
// if the user pasted the same file twice (which produces two image
|
|
122
|
+
// nodes with identical `src` data URLs). Never serialized to HTML or
|
|
123
|
+
// markdown — purely in-memory state for the swap.
|
|
124
|
+
pendingUploadId: {
|
|
125
|
+
default: null,
|
|
126
|
+
parseHTML: () => null,
|
|
127
|
+
renderHTML: () => ({})
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
addNodeView() {
|
|
132
|
+
return Z(_t);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
function _t({ node: t, updateAttributes: r, selected: i, extension: a }) {
|
|
136
|
+
const s = L(null), l = L(null), [g, o] = E(!1), p = t.attrs.src ?? "", b = (a.options.resolveSrc ?? ((h) => h))(p), A = t.attrs.alt ?? "", n = t.attrs.title ?? void 0, c = t.attrs.width, k = t.attrs.align ?? "left";
|
|
137
|
+
D(() => {
|
|
138
|
+
if (!g) return;
|
|
139
|
+
const h = (x) => {
|
|
140
|
+
const u = l.current;
|
|
141
|
+
if (!u) return;
|
|
142
|
+
const d = x.clientX - u.x, m = Math.max(F, Math.min(z, u.width + d));
|
|
143
|
+
r({ width: Math.round(m) });
|
|
144
|
+
}, v = () => {
|
|
145
|
+
l.current = null, o(!1);
|
|
146
|
+
};
|
|
147
|
+
return window.addEventListener("pointermove", h), window.addEventListener("pointerup", v), window.addEventListener("pointercancel", v), () => {
|
|
148
|
+
window.removeEventListener("pointermove", h), window.removeEventListener("pointerup", v), window.removeEventListener("pointercancel", v);
|
|
149
|
+
};
|
|
150
|
+
}, [g, r]);
|
|
151
|
+
const I = (h) => {
|
|
152
|
+
var u;
|
|
153
|
+
h.preventDefault(), h.stopPropagation();
|
|
154
|
+
const v = (u = s.current) == null ? void 0 : u.querySelector("img"), x = c ?? (v == null ? void 0 : v.getBoundingClientRect().width) ?? 320;
|
|
155
|
+
l.current = { x: h.clientX, width: x }, o(!0);
|
|
156
|
+
};
|
|
157
|
+
return /* @__PURE__ */ H(
|
|
158
|
+
G,
|
|
159
|
+
{
|
|
160
|
+
ref: s,
|
|
161
|
+
"data-resizable-image": "",
|
|
162
|
+
"data-selected": i ? "true" : void 0,
|
|
163
|
+
className: U(
|
|
164
|
+
"relative block max-w-full align-baseline",
|
|
165
|
+
"[&>img]:block [&>img]:max-w-full [&>img]:h-auto [&>img]:rounded-md",
|
|
166
|
+
k === "left" && "mr-auto",
|
|
167
|
+
k === "center" && "mx-auto",
|
|
168
|
+
k === "right" && "ml-auto",
|
|
169
|
+
i && "ring-2 ring-[color:var(--accent)] ring-offset-1 ring-offset-background"
|
|
170
|
+
),
|
|
171
|
+
style: { width: c ? `${c}px` : void 0 },
|
|
172
|
+
children: [
|
|
173
|
+
/* @__PURE__ */ e("img", { src: b, alt: A, title: n, draggable: !1 }),
|
|
174
|
+
/* @__PURE__ */ e(
|
|
175
|
+
"span",
|
|
176
|
+
{
|
|
177
|
+
role: "slider",
|
|
178
|
+
"aria-label": "Resize image",
|
|
179
|
+
"aria-valuenow": c ?? 0,
|
|
180
|
+
"aria-valuemin": F,
|
|
181
|
+
"aria-valuemax": z,
|
|
182
|
+
"data-testid": "resize-handle",
|
|
183
|
+
onPointerDown: I,
|
|
184
|
+
className: U(
|
|
185
|
+
"absolute right-0 bottom-0 h-3 w-3 translate-x-1/2 translate-y-1/2 cursor-nwse-resize",
|
|
186
|
+
"rounded-full border border-background bg-[color:var(--accent)] shadow",
|
|
187
|
+
"opacity-0 transition-opacity duration-150 ease-out",
|
|
188
|
+
(i || g) && "opacity-100"
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
const Ot = pt(ht), Vt = [
|
|
197
|
+
/<script[\s>][\s\S]*?<\/script>/gi,
|
|
198
|
+
/<iframe[\s>][\s\S]*?<\/iframe>/gi,
|
|
199
|
+
/\s+on\w+\s*=\s*["'][^"']*["']/gi,
|
|
200
|
+
/\s+on\w+\s*=\s*\S+/gi,
|
|
201
|
+
/href\s*=\s*["']?\s*javascript:[^"'\s>]*/gi,
|
|
202
|
+
/src\s*=\s*["']?\s*javascript:[^"'\s>]*/gi
|
|
203
|
+
];
|
|
204
|
+
function Xt(t) {
|
|
205
|
+
let r = t;
|
|
206
|
+
for (const i of Vt)
|
|
207
|
+
r = r.replace(i, "");
|
|
208
|
+
return r;
|
|
209
|
+
}
|
|
210
|
+
function Kt(t) {
|
|
211
|
+
return /^(?:[a-z][a-z0-9+.-]*:|\/|#)/i.test(t);
|
|
212
|
+
}
|
|
213
|
+
function Qt(t, r) {
|
|
214
|
+
const i = t.match(/^([^?#]*)([?#].*)?$/), a = (i == null ? void 0 : i[1]) ?? t, s = (i == null ? void 0 : i[2]) ?? "", l = r != null && r.includes("/") ? r.slice(0, r.lastIndexOf("/")) : "", g = `${l ? `${l}/` : ""}${a}`.split("/"), o = [];
|
|
215
|
+
for (const p of g)
|
|
216
|
+
!p || p === "." || (p === ".." ? o.pop() : o.push(p));
|
|
217
|
+
return `${o.join("/")}${s}`;
|
|
218
|
+
}
|
|
219
|
+
function Zt(t, r, i, a) {
|
|
220
|
+
if (!t || Kt(t)) return t;
|
|
221
|
+
const s = Qt(t, r), l = i.replace(/\/$/, ""), g = new URLSearchParams({ path: s });
|
|
222
|
+
return a && g.set("workspaceId", a), `${l}/api/v1/files/raw?${g.toString()}`;
|
|
223
|
+
}
|
|
224
|
+
const Gt = [
|
|
225
|
+
et.configure({
|
|
226
|
+
codeBlock: !1,
|
|
227
|
+
link: !1,
|
|
228
|
+
underline: !1
|
|
229
|
+
}),
|
|
230
|
+
rt,
|
|
231
|
+
it.configure({
|
|
232
|
+
openOnClick: !0,
|
|
233
|
+
autolink: !0,
|
|
234
|
+
linkOnPaste: !0,
|
|
235
|
+
defaultProtocol: "https",
|
|
236
|
+
HTMLAttributes: { rel: "noopener noreferrer nofollow", target: "_blank" }
|
|
237
|
+
}),
|
|
238
|
+
j.configure({
|
|
239
|
+
placeholder: "Start writing..."
|
|
240
|
+
}),
|
|
241
|
+
nt,
|
|
242
|
+
at.configure({ nested: !0 }),
|
|
243
|
+
ot.configure({
|
|
244
|
+
types: ["heading", "paragraph"]
|
|
245
|
+
}),
|
|
246
|
+
lt,
|
|
247
|
+
st.configure({
|
|
248
|
+
resizable: !0
|
|
249
|
+
}),
|
|
250
|
+
ct,
|
|
251
|
+
ut,
|
|
252
|
+
gt,
|
|
253
|
+
O.configure({
|
|
254
|
+
inline: !1,
|
|
255
|
+
allowBase64: !0
|
|
256
|
+
}),
|
|
257
|
+
mt.configure({ lowlight: Ot }),
|
|
258
|
+
wt.configure({
|
|
259
|
+
markedOptions: {
|
|
260
|
+
gfm: !0,
|
|
261
|
+
breaks: !1,
|
|
262
|
+
pedantic: !1
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
];
|
|
266
|
+
function f({ onClick: t, active: r, disabled: i, title: a, children: s }) {
|
|
267
|
+
return /* @__PURE__ */ e(
|
|
268
|
+
Wt,
|
|
269
|
+
{
|
|
270
|
+
type: "button",
|
|
271
|
+
size: "icon-xs",
|
|
272
|
+
onClick: t,
|
|
273
|
+
disabled: i,
|
|
274
|
+
title: a,
|
|
275
|
+
"aria-pressed": r,
|
|
276
|
+
className: U(
|
|
277
|
+
"text-muted-foreground/70",
|
|
278
|
+
r && "bg-[color:var(--accent-soft)] text-[color:var(--accent)]"
|
|
279
|
+
),
|
|
280
|
+
children: s
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
function N() {
|
|
285
|
+
return /* @__PURE__ */ e(Pt, { className: "mx-2 h-3.5" });
|
|
286
|
+
}
|
|
287
|
+
function P(t) {
|
|
288
|
+
const r = t.trim().toLowerCase();
|
|
289
|
+
return !r.startsWith("javascript:") && !r.startsWith("data:text/html");
|
|
290
|
+
}
|
|
291
|
+
function Jt(t) {
|
|
292
|
+
return new Promise((r, i) => {
|
|
293
|
+
const a = new FileReader();
|
|
294
|
+
a.onload = () => r(a.result), a.onerror = () => i(a.error ?? new Error("Read failed")), a.readAsDataURL(t);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
function Yt(t) {
|
|
298
|
+
if (!t) return null;
|
|
299
|
+
for (const r of Array.from(t.files ?? []))
|
|
300
|
+
if (r.type.startsWith("image/")) return r;
|
|
301
|
+
for (const r of Array.from(t.items ?? [])) {
|
|
302
|
+
if (r.kind !== "file" || !r.type.startsWith("image/")) continue;
|
|
303
|
+
const i = r.getAsFile();
|
|
304
|
+
if (i) return i;
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
function te({
|
|
309
|
+
editor: t,
|
|
310
|
+
onInsertImage: r,
|
|
311
|
+
rawMode: i,
|
|
312
|
+
onToggleRawMode: a,
|
|
313
|
+
uploading: s
|
|
314
|
+
}) {
|
|
315
|
+
const l = (n) => {
|
|
316
|
+
if (t) {
|
|
317
|
+
if (t.isActive("image")) {
|
|
318
|
+
t.chain().focus().updateAttributes("image", { align: n }).run();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
t.chain().focus().setTextAlign(n).run();
|
|
322
|
+
}
|
|
323
|
+
}, g = L(null), o = tt({
|
|
324
|
+
editor: t,
|
|
325
|
+
selector: ({ editor: n }) => n ? {
|
|
326
|
+
bold: n.isActive("bold"),
|
|
327
|
+
italic: n.isActive("italic"),
|
|
328
|
+
underline: n.isActive("underline"),
|
|
329
|
+
strike: n.isActive("strike"),
|
|
330
|
+
h1: n.isActive("heading", { level: 1 }),
|
|
331
|
+
h2: n.isActive("heading", { level: 2 }),
|
|
332
|
+
h3: n.isActive("heading", { level: 3 }),
|
|
333
|
+
bulletList: n.isActive("bulletList"),
|
|
334
|
+
orderedList: n.isActive("orderedList"),
|
|
335
|
+
taskList: n.isActive("taskList"),
|
|
336
|
+
blockquote: n.isActive("blockquote"),
|
|
337
|
+
codeBlock: n.isActive("codeBlock"),
|
|
338
|
+
link: n.isActive("link"),
|
|
339
|
+
highlight: n.isActive("highlight"),
|
|
340
|
+
alignLeft: n.isActive("image") ? (n.getAttributes("image").align ?? "left") === "left" : n.isActive({ textAlign: "left" }),
|
|
341
|
+
alignCenter: n.isActive("image") ? n.getAttributes("image").align === "center" : n.isActive({ textAlign: "center" }),
|
|
342
|
+
alignRight: n.isActive("image") ? n.getAttributes("image").align === "right" : n.isActive({ textAlign: "right" })
|
|
343
|
+
} : null
|
|
344
|
+
});
|
|
345
|
+
if (!t || !o) return null;
|
|
346
|
+
const p = () => {
|
|
347
|
+
const n = window.prompt("URL:");
|
|
348
|
+
n && P(n) && t.chain().focus().extendMarkRange("link").setLink({ href: n }).run();
|
|
349
|
+
}, y = () => {
|
|
350
|
+
const n = window.prompt("Image URL:");
|
|
351
|
+
n && P(n) && t.chain().focus().setImage({ src: n }).run();
|
|
352
|
+
}, b = (n) => {
|
|
353
|
+
var c;
|
|
354
|
+
if (n != null && n.shiftKey) {
|
|
355
|
+
y();
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
(c = g.current) == null || c.click();
|
|
359
|
+
}, A = async (n) => {
|
|
360
|
+
var k;
|
|
361
|
+
const c = (k = n.target.files) == null ? void 0 : k[0];
|
|
362
|
+
n.target.value = "", !(!c || !c.type.startsWith("image/")) && await r(c);
|
|
363
|
+
};
|
|
364
|
+
return /* @__PURE__ */ H(Ft, { className: "border-b border-border/60 bg-background px-3 py-1.5", "aria-label": "Formatting toolbar", children: [
|
|
365
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleBold().run(), active: o.bold, title: "Bold", children: /* @__PURE__ */ e(kt, { className: "h-4 w-4" }) }),
|
|
366
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleItalic().run(), active: o.italic, title: "Italic", children: /* @__PURE__ */ e(vt, { className: "h-4 w-4" }) }),
|
|
367
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleUnderline().run(), active: o.underline, title: "Underline", children: /* @__PURE__ */ e(bt, { className: "h-4 w-4" }) }),
|
|
368
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleStrike().run(), active: o.strike, title: "Strikethrough", children: /* @__PURE__ */ e(It, { className: "h-4 w-4" }) }),
|
|
369
|
+
/* @__PURE__ */ e(N, {}),
|
|
370
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleHeading({ level: 1 }).run(), active: o.h1, title: "Heading 1", children: /* @__PURE__ */ e(At, { className: "h-4 w-4" }) }),
|
|
371
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleHeading({ level: 2 }).run(), active: o.h2, title: "Heading 2", children: /* @__PURE__ */ e(yt, { className: "h-4 w-4" }) }),
|
|
372
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleHeading({ level: 3 }).run(), active: o.h3, title: "Heading 3", children: /* @__PURE__ */ e(Lt, { className: "h-4 w-4" }) }),
|
|
373
|
+
/* @__PURE__ */ e(N, {}),
|
|
374
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleBulletList().run(), active: o.bulletList, title: "Bullet list", children: /* @__PURE__ */ e(xt, { className: "h-4 w-4" }) }),
|
|
375
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleOrderedList().run(), active: o.orderedList, title: "Ordered list", children: /* @__PURE__ */ e(Nt, { className: "h-4 w-4" }) }),
|
|
376
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleTaskList().run(), active: o.taskList, title: "Task list", children: /* @__PURE__ */ e(Ct, { className: "h-4 w-4" }) }),
|
|
377
|
+
/* @__PURE__ */ e(N, {}),
|
|
378
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleBlockquote().run(), active: o.blockquote, title: "Quote", children: /* @__PURE__ */ e(Tt, { className: "h-4 w-4" }) }),
|
|
379
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleCodeBlock().run(), active: o.codeBlock, title: "Code block", children: /* @__PURE__ */ e(Mt, { className: "h-4 w-4" }) }),
|
|
380
|
+
/* @__PURE__ */ e(f, { onClick: p, active: o.link, title: "Link", children: /* @__PURE__ */ e(Rt, { className: "h-4 w-4" }) }),
|
|
381
|
+
/* @__PURE__ */ e(
|
|
382
|
+
f,
|
|
383
|
+
{
|
|
384
|
+
onClick: b,
|
|
385
|
+
title: "Image (click to upload, Shift+click for URL)",
|
|
386
|
+
children: /* @__PURE__ */ e(Ht, { className: "h-4 w-4" })
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
/* @__PURE__ */ e(
|
|
390
|
+
zt,
|
|
391
|
+
{
|
|
392
|
+
ref: g,
|
|
393
|
+
"data-testid": "image-file-input",
|
|
394
|
+
type: "file",
|
|
395
|
+
accept: "image/*",
|
|
396
|
+
className: "hidden",
|
|
397
|
+
onChange: A
|
|
398
|
+
}
|
|
399
|
+
),
|
|
400
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().toggleHighlight().run(), active: o.highlight, title: "Highlight", children: /* @__PURE__ */ e(Ut, { className: "h-4 w-4" }) }),
|
|
401
|
+
/* @__PURE__ */ e(N, {}),
|
|
402
|
+
/* @__PURE__ */ e(f, { onClick: () => l("left"), active: o.alignLeft, title: "Align left", children: /* @__PURE__ */ e(St, { className: "h-4 w-4" }) }),
|
|
403
|
+
/* @__PURE__ */ e(f, { onClick: () => l("center"), active: o.alignCenter, title: "Center align", children: /* @__PURE__ */ e($t, { className: "h-4 w-4" }) }),
|
|
404
|
+
/* @__PURE__ */ e(f, { onClick: () => l("right"), active: o.alignRight, title: "Align right", children: /* @__PURE__ */ e(Bt, { className: "h-4 w-4" }) }),
|
|
405
|
+
/* @__PURE__ */ e(N, {}),
|
|
406
|
+
/* @__PURE__ */ e(f, { onClick: () => t.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: /* @__PURE__ */ e(Dt, { className: "h-4 w-4" }) }),
|
|
407
|
+
/* @__PURE__ */ e(N, {}),
|
|
408
|
+
s && /* @__PURE__ */ H(
|
|
409
|
+
"span",
|
|
410
|
+
{
|
|
411
|
+
role: "status",
|
|
412
|
+
"aria-live": "polite",
|
|
413
|
+
className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground/80",
|
|
414
|
+
children: [
|
|
415
|
+
/* @__PURE__ */ e(Et, { className: "h-3 w-3 animate-spin", "aria-hidden": !0 }),
|
|
416
|
+
"Uploading…"
|
|
417
|
+
]
|
|
418
|
+
}
|
|
419
|
+
),
|
|
420
|
+
/* @__PURE__ */ e(
|
|
421
|
+
f,
|
|
422
|
+
{
|
|
423
|
+
onClick: a,
|
|
424
|
+
active: i,
|
|
425
|
+
title: i ? "Rich text" : "Raw markdown",
|
|
426
|
+
children: /* @__PURE__ */ e("span", { className: "font-mono text-[10px] font-semibold leading-none tracking-[-0.02em]", children: "MD" })
|
|
427
|
+
}
|
|
428
|
+
)
|
|
429
|
+
] });
|
|
430
|
+
}
|
|
431
|
+
function xe({
|
|
432
|
+
content: t,
|
|
433
|
+
onChange: r,
|
|
434
|
+
readOnly: i = !1,
|
|
435
|
+
placeholder: a,
|
|
436
|
+
className: s,
|
|
437
|
+
documentPath: l
|
|
438
|
+
}) {
|
|
439
|
+
const g = q(), o = _(), { upload: p, uploading: y } = jt(), [b, A] = E(!1), n = Q(() => {
|
|
440
|
+
const d = O.configure({
|
|
441
|
+
inline: !1,
|
|
442
|
+
allowBase64: !0,
|
|
443
|
+
resolveSrc: (w) => Zt(w, l, g, o)
|
|
444
|
+
}), m = Gt.map((w) => w.name === "image" ? d : w);
|
|
445
|
+
return a ? [
|
|
446
|
+
...m.filter((w) => w.name !== "placeholder"),
|
|
447
|
+
j.configure({ placeholder: a })
|
|
448
|
+
] : m;
|
|
449
|
+
}, [g, l, a, o]), c = L(r);
|
|
450
|
+
c.current = r;
|
|
451
|
+
const k = L(!1), I = L(null), h = L(async () => {
|
|
452
|
+
});
|
|
453
|
+
h.current = async (d) => {
|
|
454
|
+
const m = I.current;
|
|
455
|
+
if (!m) return;
|
|
456
|
+
let w;
|
|
457
|
+
try {
|
|
458
|
+
w = await Jt(d);
|
|
459
|
+
} catch {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const S = typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `pending-${Date.now()}-${Math.random().toString(36).slice(2)}`, V = { src: w, alt: d.name, pendingUploadId: S };
|
|
463
|
+
m.chain().focus().setImage(V).run();
|
|
464
|
+
try {
|
|
465
|
+
const { url: C } = await p(d, { sourcePath: l }), T = I.current;
|
|
466
|
+
if (!T || T.isDestroyed) return;
|
|
467
|
+
T.commands.command(({ tr: $, state: M }) => (M.doc.descendants((R, X) => (R.type.name === "image" && R.attrs.pendingUploadId === S && $.setNodeMarkup(X, void 0, { ...R.attrs, src: C, pendingUploadId: null }), !0)), !0));
|
|
468
|
+
} catch {
|
|
469
|
+
const C = I.current;
|
|
470
|
+
if (!C || C.isDestroyed) return;
|
|
471
|
+
C.commands.command(({ tr: T, state: $ }) => ($.doc.descendants((M, R) => (M.type.name === "image" && M.attrs.pendingUploadId === S && T.setNodeMarkup(R, void 0, { ...M.attrs, pendingUploadId: null }), !0)), !0));
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
const v = t || { type: "doc", content: [{ type: "paragraph" }] }, x = t ? "markdown" : "json", u = J({
|
|
475
|
+
extensions: n,
|
|
476
|
+
content: v,
|
|
477
|
+
contentType: x,
|
|
478
|
+
editable: !i,
|
|
479
|
+
editorProps: {
|
|
480
|
+
attributes: {
|
|
481
|
+
class: "tiptap-prose max-w-[68ch] px-8 py-6 focus:outline-none min-h-[200px]"
|
|
482
|
+
},
|
|
483
|
+
transformPastedHTML: Xt,
|
|
484
|
+
handlePaste: (d, m) => {
|
|
485
|
+
if (i) return !1;
|
|
486
|
+
const w = Yt(m.clipboardData);
|
|
487
|
+
return w ? (m.preventDefault(), h.current(w), !0) : !1;
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
onUpdate: ({ editor: d }) => {
|
|
491
|
+
var m, w;
|
|
492
|
+
k.current || (w = c.current) == null || w.call(c, ((m = d.getMarkdown) == null ? void 0 : m.call(d)) ?? d.getHTML());
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
return I.current = u, D(() => {
|
|
496
|
+
!u || u.isDestroyed || u.setEditable(!i);
|
|
497
|
+
}, [u, i]), D(() => {
|
|
498
|
+
var m;
|
|
499
|
+
!u || u.isDestroyed || (((m = u.getMarkdown) == null ? void 0 : m.call(u)) ?? u.getHTML()) === t || (k.current = !0, u.commands.setContent(v, { contentType: x }), k.current = !1);
|
|
500
|
+
}, [u, t]), /* @__PURE__ */ H("div", { className: U("flex h-full flex-col overflow-hidden", s), children: [
|
|
501
|
+
!i && /* @__PURE__ */ e(
|
|
502
|
+
te,
|
|
503
|
+
{
|
|
504
|
+
editor: u,
|
|
505
|
+
onInsertImage: (d) => h.current(d),
|
|
506
|
+
rawMode: b,
|
|
507
|
+
onToggleRawMode: () => A((d) => !d),
|
|
508
|
+
uploading: y
|
|
509
|
+
}
|
|
510
|
+
),
|
|
511
|
+
/* @__PURE__ */ e("div", { className: "flex-1 overflow-auto", children: b && !i ? /* @__PURE__ */ e(
|
|
512
|
+
"textarea",
|
|
513
|
+
{
|
|
514
|
+
"aria-label": "Raw markdown",
|
|
515
|
+
"data-testid": "markdown-raw-editor",
|
|
516
|
+
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",
|
|
517
|
+
value: t,
|
|
518
|
+
placeholder: a,
|
|
519
|
+
spellCheck: !1,
|
|
520
|
+
onChange: (d) => {
|
|
521
|
+
var m;
|
|
522
|
+
return (m = c.current) == null ? void 0 : m.call(c, d.target.value);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
) : /* @__PURE__ */ e(Y, { editor: u }) })
|
|
526
|
+
] });
|
|
527
|
+
}
|
|
528
|
+
export {
|
|
529
|
+
xe as MarkdownEditor,
|
|
530
|
+
P as isSafeUrl,
|
|
531
|
+
Zt as rawFileUrlForMarkdownImage,
|
|
532
|
+
Jt as readFileAsDataUrl,
|
|
533
|
+
Xt as sanitizeHtml
|
|
534
|
+
};
|
|
@@ -2,7 +2,7 @@ import { jsxs as d, jsx as a, Fragment as V } from "react/jsx-runtime";
|
|
|
2
2
|
import { useCallback as b, useMemo as F, useEffect as I, useState as q, Suspense as Q, useRef as Y } from "react";
|
|
3
3
|
import { LoadingState as ee, ResizeHandle as te, IconButton as Z, Button as ne, Kbd as re } from "@hachej/boring-ui-kit";
|
|
4
4
|
import { c as g } from "./utils-B6yFEsav.js";
|
|
5
|
-
import { a0 as ae, a7 as oe, B as ie, an as se, al as ce, u as de } from "./CommandPalette-
|
|
5
|
+
import { a0 as ae, a7 as oe, B as ie, an as se, al as ce, u as de } from "./CommandPalette-CJHuTJlD.js";
|
|
6
6
|
import { Search as le, Plus as ue } from "lucide-react";
|
|
7
7
|
function ke(e, t, r = !0) {
|
|
8
8
|
if (!r || typeof window > "u") return t;
|
package/dist/app-front.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as d, jsxs as $e, Fragment as W } from "react/jsx-runtime";
|
|
2
2
|
import { useSyncExternalStore as Qe, useMemo as b, useCallback as y, useRef as $, useState as H, useEffect as v } from "react";
|
|
3
3
|
import { ChatPanel as Xe, useSessions as Ze } from "@hachej/boring-agent/front";
|
|
4
|
-
import { U as Ce, p as He, al as qe, u as et, am as tt } from "./CommandPalette-
|
|
5
|
-
import { T as st, C as nt, r as Ke, w as rt, W as Le } from "./WorkspaceLoadingState-
|
|
4
|
+
import { U as Ce, p as He, al as qe, u as et, am as tt } from "./CommandPalette-CJHuTJlD.js";
|
|
5
|
+
import { T as st, C as nt, r as Ke, w as rt, W as Le } from "./WorkspaceLoadingState-zLzh1tGc.js";
|
|
6
6
|
function ot() {
|
|
7
7
|
const e = `s${Date.now()}`;
|
|
8
8
|
return {
|
package/dist/testing.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as Ba } from "react/jsx-runtime";
|
|
2
2
|
import * as Pa from "react";
|
|
3
3
|
import { createElement as is, useMemo as wn, useLayoutEffect as us, isValidElement as ss, cloneElement as ds, useSyncExternalStore as Gi } from "react";
|
|
4
|
-
import { i as cs, p as fs, ak as ps } from "./CommandPalette-
|
|
4
|
+
import { i as cs, p as fs, ak as ps } from "./CommandPalette-CJHuTJlD.js";
|
|
5
5
|
import { d as ms } from "./panel-DnvDNQac.js";
|
|
6
6
|
import * as bs from "react-dom/test-utils";
|
|
7
7
|
import ka from "react-dom";
|
package/dist/workspace.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
var X = Object.defineProperty;
|
|
2
2
|
var q = (e, a, t) => a in e ? X(e, a, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[a] = t;
|
|
3
3
|
var R = (e, a, t) => q(e, typeof a != "symbol" ? a + "" : a, t);
|
|
4
|
-
import { d as G, u as K, a as Q, b as Y, D as Z } from "./CommandPalette-
|
|
5
|
-
import { A as $e, C as He, c as Ue, e as Ae, f as Je, F as Ve, g as Xe, M as qe, h as Ge, P as Qe, i as Ye, j as Ze, k as et, l as tt, R as at, S as nt, m as rt, n as st, T as ot, U as it, W as lt, o as ct, p as dt, q as ut, r as pt, s as mt, t as ft, v as ht, w as gt, x as bt, y as yt, z as vt, B as xt, E as Pt, G as St, H as Ct, I as kt, J as wt, K as Nt, L as Ot, N as Et, O as Tt, Q as Rt, V as It, X as Mt, Y as Lt, Z as Bt, _ as Ft, $ as Wt, a0 as Dt, a1 as zt, a2 as jt, a3 as Kt, a4 as _t, a5 as $t, a6 as Ht, a7 as Ut, a8 as At, a9 as Jt, aa as Vt, ab as Xt, ac as qt, ad as Gt, ae as Qt, af as Yt, ag as Zt, ah as ea, ai as ta, aj as aa } from "./CommandPalette-
|
|
4
|
+
import { d as G, u as K, a as Q, b as Y, D as Z } from "./CommandPalette-CJHuTJlD.js";
|
|
5
|
+
import { A as $e, C as He, c as Ue, e as Ae, f as Je, F as Ve, g as Xe, M as qe, h as Ge, P as Qe, i as Ye, j as Ze, k as et, l as tt, R as at, S as nt, m as rt, n as st, T as ot, U as it, W as lt, o as ct, p as dt, q as ut, r as pt, s as mt, t as ft, v as ht, w as gt, x as bt, y as yt, z as vt, B as xt, E as Pt, G as St, H as Ct, I as kt, J as wt, K as Nt, L as Ot, N as Et, O as Tt, Q as Rt, V as It, X as Mt, Y as Lt, Z as Bt, _ as Ft, $ as Wt, a0 as Dt, a1 as zt, a2 as jt, a3 as Kt, a4 as _t, a5 as $t, a6 as Ht, a7 as Ut, a8 as At, a9 as Jt, aa as Vt, ab as Xt, ac as qt, ad as Gt, ae as Qt, af as Yt, ag as Zt, ah as ea, ai as ta, aj as aa } from "./CommandPalette-CJHuTJlD.js";
|
|
6
6
|
import { c as N } from "./utils-B6yFEsav.js";
|
|
7
|
-
import { C as ra, T as sa, W as oa, b as ia } from "./WorkspaceLoadingState-
|
|
7
|
+
import { C as ra, T as sa, W as oa, b as ia } from "./WorkspaceLoadingState-zLzh1tGc.js";
|
|
8
8
|
import { jsxs as b, jsx as r, Fragment as ee } from "react/jsx-runtime";
|
|
9
9
|
import { Button as k, Sheet as te, SheetContent as ae, SheetHeader as ne, SheetTitle as re, SheetDescription as se, EmptyState as oe, Kbd as I, ErrorState as ie, IconButton as M } from "@hachej/boring-ui-kit";
|
|
10
10
|
import { Toaster as ca, dismissToast as da, toast as ua } from "@hachej/boring-ui-kit";
|
|
11
11
|
import { useSyncExternalStore as le, useState as O, useEffect as P, useRef as w, useCallback as y, useMemo as C, Suspense as ce, Component as de } from "react";
|
|
12
12
|
import { C as ma, c as fa } from "./CodeEditor-DQqOn4xz.js";
|
|
13
|
-
import { FileTree as ga } from "./FileTree-
|
|
14
|
-
import { MarkdownEditor as ya } from "./MarkdownEditor-
|
|
13
|
+
import { FileTree as ga } from "./FileTree-Dvaud3jU.js";
|
|
14
|
+
import { MarkdownEditor as ya } from "./MarkdownEditor-sLkqTXDj.js";
|
|
15
15
|
import { MenuIcon as ue, PanelLeftOpenIcon as pe, PanelLeftCloseIcon as me, PinIcon as fe, CheckIcon as he, CopyIcon as ge } from "lucide-react";
|
|
16
16
|
import { d as xa } from "./panel-DnvDNQac.js";
|
|
17
17
|
function S(e, a) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Workspace UI, plugin, and bridge package for composing chat, files, catalogs, editors, and app-specific panes.",
|
|
@@ -123,8 +123,8 @@
|
|
|
123
123
|
"tailwind-merge": "^2.0.0",
|
|
124
124
|
"zod": "^3.23.0",
|
|
125
125
|
"zustand": "^5.0.0",
|
|
126
|
-
"@hachej/boring-agent": "0.1.
|
|
127
|
-
"@hachej/boring-ui-kit": "0.1.
|
|
126
|
+
"@hachej/boring-agent": "0.1.17",
|
|
127
|
+
"@hachej/boring-ui-kit": "0.1.17"
|
|
128
128
|
},
|
|
129
129
|
"devDependencies": {
|
|
130
130
|
"@tailwindcss/postcss": "^4.0.0",
|