@hachej/boring-workspace 0.1.5 → 0.1.6
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-aM61U-b0.js → CommandPalette-CdiVSPYz.js} +5 -3
- package/dist/{FileTree-DRq_bfue.js → FileTree-Bgg50HQf.js} +1 -1
- package/dist/MarkdownEditor-BA37oZKg.js +458 -0
- package/dist/{WorkspaceLoadingState-By0dZoPD.js → WorkspaceLoadingState-CLhYOvtL.js} +1 -1
- package/dist/app-front.js +2 -2
- package/dist/testing.js +1 -1
- package/dist/workspace.css +12 -0
- package/dist/workspace.d.ts +3 -1
- package/dist/workspace.js +5 -5
- package/package.json +4 -4
- package/dist/MarkdownEditor-DjiHxnRv.js +0 -349
|
@@ -2095,7 +2095,7 @@ function Qs(e) {
|
|
|
2095
2095
|
}
|
|
2096
2096
|
return t;
|
|
2097
2097
|
}
|
|
2098
|
-
const Qn = () => import("./FileTree-
|
|
2098
|
+
const Qn = () => import("./FileTree-Bgg50HQf.js").then((e) => ({ default: e.FileTree }));
|
|
2099
2099
|
function Xs() {
|
|
2100
2100
|
Qn();
|
|
2101
2101
|
}
|
|
@@ -2945,7 +2945,7 @@ function Xt({ params: e, api: t, className: n }) {
|
|
|
2945
2945
|
);
|
|
2946
2946
|
}
|
|
2947
2947
|
const yi = Ge(
|
|
2948
|
-
() => import("./MarkdownEditor-
|
|
2948
|
+
() => import("./MarkdownEditor-BA37oZKg.js").then((e) => ({ default: e.MarkdownEditor }))
|
|
2949
2949
|
);
|
|
2950
2950
|
function vi({ params: e, api: t, className: n }) {
|
|
2951
2951
|
const r = typeof (e == null ? void 0 : e.path) == "string" ? e.path : "", {
|
|
@@ -2970,7 +2970,7 @@ function vi({ params: e, api: t, className: n }) {
|
|
|
2970
2970
|
onReload: d,
|
|
2971
2971
|
onOverwrite: i,
|
|
2972
2972
|
editorComponent: yi,
|
|
2973
|
-
editorProps: { className: n }
|
|
2973
|
+
editorProps: { className: n, documentPath: r }
|
|
2974
2974
|
}
|
|
2975
2975
|
);
|
|
2976
2976
|
}
|
|
@@ -5201,6 +5201,8 @@ export {
|
|
|
5201
5201
|
$n as ak,
|
|
5202
5202
|
Ka as al,
|
|
5203
5203
|
pe as am,
|
|
5204
|
+
Ye as an,
|
|
5205
|
+
Je as ao,
|
|
5204
5206
|
Ja as b,
|
|
5205
5207
|
Xt as c,
|
|
5206
5208
|
go as d,
|
|
@@ -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 K, Loader2Icon as E } from "lucide-react";
|
|
5
|
-
import { K as Y } from "./CommandPalette-
|
|
5
|
+
import { K as Y } from "./CommandPalette-CdiVSPYz.js";
|
|
6
6
|
import { Input as G } 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,458 @@
|
|
|
1
|
+
import { jsxs as T, jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as v, useState as B, useEffect as L } from "react";
|
|
3
|
+
import { ReactNodeViewRenderer as $, NodeViewWrapper as E, useEditor as z, EditorContent as P, useEditorState as D } from "@tiptap/react";
|
|
4
|
+
import q from "@tiptap/starter-kit";
|
|
5
|
+
import j from "@tiptap/extension-underline";
|
|
6
|
+
import F from "@tiptap/extension-link";
|
|
7
|
+
import S from "@tiptap/extension-placeholder";
|
|
8
|
+
import W from "@tiptap/extension-task-list";
|
|
9
|
+
import O from "@tiptap/extension-task-item";
|
|
10
|
+
import V from "@tiptap/extension-text-align";
|
|
11
|
+
import _ from "@tiptap/extension-highlight";
|
|
12
|
+
import { Table as X } from "@tiptap/extension-table";
|
|
13
|
+
import { TableRow as K } from "@tiptap/extension-table-row";
|
|
14
|
+
import { TableHeader as Q } from "@tiptap/extension-table-header";
|
|
15
|
+
import { TableCell as J } from "@tiptap/extension-table-cell";
|
|
16
|
+
import Z from "@tiptap/extension-image";
|
|
17
|
+
import { c as x } from "./utils-B6yFEsav.js";
|
|
18
|
+
import { an as G, ao as Y } from "./CommandPalette-CdiVSPYz.js";
|
|
19
|
+
import tt from "@tiptap/extension-code-block-lowlight";
|
|
20
|
+
import { createLowlight as et, common as it } from "lowlight";
|
|
21
|
+
import { Markdown as rt } from "@tiptap/markdown";
|
|
22
|
+
import { BoldIcon as nt, ItalicIcon as at, UnderlineIcon as ot, StrikethroughIcon as lt, Heading1Icon as st, Heading2Icon as ct, Heading3Icon as ut, ListIcon as gt, ListOrderedIcon as dt, ListChecksIcon as ft, QuoteIcon as mt, CodeIcon as ht, LinkIcon as pt, ImageIcon as wt, HighlighterIcon as kt, AlignLeftIcon as bt, AlignCenterIcon as vt, AlignRightIcon as It, MinusIcon as xt } from "lucide-react";
|
|
23
|
+
import { Toolbar as At, Input as Lt, ToolbarButton as Nt, ToolbarSeparator as Tt } from "@hachej/boring-ui-kit";
|
|
24
|
+
const C = 64, y = 2e3;
|
|
25
|
+
function Ct(t) {
|
|
26
|
+
return t.replace(/\\/g, "\\\\").replace(/]/g, "\\]");
|
|
27
|
+
}
|
|
28
|
+
function A(t) {
|
|
29
|
+
return t.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
30
|
+
}
|
|
31
|
+
function R(t) {
|
|
32
|
+
if (typeof t == "number" && Number.isFinite(t) && t > 0) return t;
|
|
33
|
+
if (typeof t == "string" && t.trim()) {
|
|
34
|
+
const n = Number(t);
|
|
35
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const yt = Z.extend({
|
|
40
|
+
name: "image",
|
|
41
|
+
draggable: !0,
|
|
42
|
+
parseMarkdown: (t, n) => n.createNode("image", {
|
|
43
|
+
src: t.href,
|
|
44
|
+
title: t.title,
|
|
45
|
+
alt: t.text
|
|
46
|
+
}),
|
|
47
|
+
renderMarkdown: (t) => {
|
|
48
|
+
var k, f, h, w, e, a, u;
|
|
49
|
+
const n = typeof ((k = t.attrs) == null ? void 0 : k.src) == "string" ? t.attrs.src : "", r = typeof ((f = t.attrs) == null ? void 0 : f.alt) == "string" ? t.attrs.alt : "", o = typeof ((h = t.attrs) == null ? void 0 : h.title) == "string" ? t.attrs.title : "", c = R((w = t.attrs) == null ? void 0 : w.width), d = R((e = t.attrs) == null ? void 0 : e.height), m = ((a = t.attrs) == null ? void 0 : a.align) === "center" || ((u = t.attrs) == null ? void 0 : u.align) === "right" ? t.attrs.align : "left";
|
|
50
|
+
if (!c && !d && m === "left") {
|
|
51
|
+
const s = Ct(r);
|
|
52
|
+
return o ? `}")` : ``;
|
|
53
|
+
}
|
|
54
|
+
const l = `<img ${[
|
|
55
|
+
`src="${A(n)}"`,
|
|
56
|
+
r ? `alt="${A(r)}"` : null,
|
|
57
|
+
o ? `title="${A(o)}"` : null,
|
|
58
|
+
c ? `width="${c}"` : null,
|
|
59
|
+
d ? `height="${d}"` : null
|
|
60
|
+
].filter(Boolean).join(" ")} />`;
|
|
61
|
+
return m === "center" || m === "right" ? `<p align="${m}">${l}</p>` : l;
|
|
62
|
+
},
|
|
63
|
+
addAttributes() {
|
|
64
|
+
var n;
|
|
65
|
+
return {
|
|
66
|
+
...((n = this.parent) == null ? void 0 : n.call(this)) ?? {},
|
|
67
|
+
width: {
|
|
68
|
+
default: null,
|
|
69
|
+
parseHTML: (r) => {
|
|
70
|
+
const o = r.getAttribute("width");
|
|
71
|
+
if (o) {
|
|
72
|
+
const d = parseInt(o, 10);
|
|
73
|
+
return Number.isFinite(d) ? d : null;
|
|
74
|
+
}
|
|
75
|
+
const c = r.style.width;
|
|
76
|
+
if (c && c.endsWith("px")) {
|
|
77
|
+
const d = parseInt(c, 10);
|
|
78
|
+
return Number.isFinite(d) ? d : null;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
},
|
|
82
|
+
renderHTML: (r) => r.width ? { width: String(r.width) } : {}
|
|
83
|
+
},
|
|
84
|
+
align: {
|
|
85
|
+
default: "left",
|
|
86
|
+
parseHTML: (r) => {
|
|
87
|
+
const o = r.getAttribute("data-align");
|
|
88
|
+
return o === "left" || o === "center" || o === "right" ? o : r.style.marginLeft === "auto" && r.style.marginRight === "auto" ? "center" : r.style.marginLeft === "auto" ? "right" : "left";
|
|
89
|
+
},
|
|
90
|
+
renderHTML: (r) => ({ "data-align": r.align ?? "left" })
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
addNodeView() {
|
|
95
|
+
return $(Rt);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
function Rt({ node: t, updateAttributes: n, selected: r }) {
|
|
99
|
+
const o = v(null), c = v(null), [d, m] = B(!1), p = t.attrs.src ?? "", l = t.attrs.alt ?? "", k = t.attrs.title ?? void 0, f = t.attrs.width, h = t.attrs.align ?? "left";
|
|
100
|
+
L(() => {
|
|
101
|
+
if (!d) return;
|
|
102
|
+
const e = (u) => {
|
|
103
|
+
const s = c.current;
|
|
104
|
+
if (!s) return;
|
|
105
|
+
const I = u.clientX - s.x, U = Math.max(C, Math.min(y, s.width + I));
|
|
106
|
+
n({ width: Math.round(U) });
|
|
107
|
+
}, a = () => {
|
|
108
|
+
c.current = null, m(!1);
|
|
109
|
+
};
|
|
110
|
+
return window.addEventListener("pointermove", e), window.addEventListener("pointerup", a), window.addEventListener("pointercancel", a), () => {
|
|
111
|
+
window.removeEventListener("pointermove", e), window.removeEventListener("pointerup", a), window.removeEventListener("pointercancel", a);
|
|
112
|
+
};
|
|
113
|
+
}, [d, n]);
|
|
114
|
+
const w = (e) => {
|
|
115
|
+
var s;
|
|
116
|
+
e.preventDefault(), e.stopPropagation();
|
|
117
|
+
const a = (s = o.current) == null ? void 0 : s.querySelector("img"), u = f ?? (a == null ? void 0 : a.getBoundingClientRect().width) ?? 320;
|
|
118
|
+
c.current = { x: e.clientX, width: u }, m(!0);
|
|
119
|
+
};
|
|
120
|
+
return /* @__PURE__ */ T(
|
|
121
|
+
E,
|
|
122
|
+
{
|
|
123
|
+
ref: o,
|
|
124
|
+
"data-resizable-image": "",
|
|
125
|
+
"data-selected": r ? "true" : void 0,
|
|
126
|
+
className: x(
|
|
127
|
+
"relative block max-w-full align-baseline",
|
|
128
|
+
"[&>img]:block [&>img]:max-w-full [&>img]:h-auto [&>img]:rounded-md",
|
|
129
|
+
h === "left" && "mr-auto",
|
|
130
|
+
h === "center" && "mx-auto",
|
|
131
|
+
h === "right" && "ml-auto",
|
|
132
|
+
r && "ring-2 ring-[color:var(--accent)] ring-offset-1 ring-offset-background"
|
|
133
|
+
),
|
|
134
|
+
style: { width: f ? `${f}px` : void 0 },
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ i("img", { src: p, alt: l, title: k, draggable: !1 }),
|
|
137
|
+
/* @__PURE__ */ i(
|
|
138
|
+
"span",
|
|
139
|
+
{
|
|
140
|
+
role: "slider",
|
|
141
|
+
"aria-label": "Resize image",
|
|
142
|
+
"aria-valuenow": f ?? 0,
|
|
143
|
+
"aria-valuemin": C,
|
|
144
|
+
"aria-valuemax": y,
|
|
145
|
+
"data-testid": "resize-handle",
|
|
146
|
+
onPointerDown: w,
|
|
147
|
+
className: x(
|
|
148
|
+
"absolute right-0 bottom-0 h-3 w-3 translate-x-1/2 translate-y-1/2 cursor-nwse-resize",
|
|
149
|
+
"rounded-full border border-background bg-[color:var(--accent)] shadow",
|
|
150
|
+
"opacity-0 transition-opacity duration-150 ease-out",
|
|
151
|
+
(r || d) && "opacity-100"
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
const Ht = et(it), Mt = [
|
|
160
|
+
/<script[\s>][\s\S]*?<\/script>/gi,
|
|
161
|
+
/<iframe[\s>][\s\S]*?<\/iframe>/gi,
|
|
162
|
+
/\s+on\w+\s*=\s*["'][^"']*["']/gi,
|
|
163
|
+
/\s+on\w+\s*=\s*\S+/gi,
|
|
164
|
+
/href\s*=\s*["']?\s*javascript:[^"'\s>]*/gi,
|
|
165
|
+
/src\s*=\s*["']?\s*javascript:[^"'\s>]*/gi
|
|
166
|
+
];
|
|
167
|
+
function Bt(t) {
|
|
168
|
+
let n = t;
|
|
169
|
+
for (const r of Mt)
|
|
170
|
+
n = n.replace(r, "");
|
|
171
|
+
return n;
|
|
172
|
+
}
|
|
173
|
+
const H = [
|
|
174
|
+
q.configure({
|
|
175
|
+
codeBlock: !1,
|
|
176
|
+
link: !1,
|
|
177
|
+
underline: !1
|
|
178
|
+
}),
|
|
179
|
+
j,
|
|
180
|
+
F.configure({
|
|
181
|
+
openOnClick: !0,
|
|
182
|
+
autolink: !0,
|
|
183
|
+
linkOnPaste: !0,
|
|
184
|
+
defaultProtocol: "https",
|
|
185
|
+
HTMLAttributes: { rel: "noopener noreferrer nofollow", target: "_blank" }
|
|
186
|
+
}),
|
|
187
|
+
S.configure({
|
|
188
|
+
placeholder: "Start writing..."
|
|
189
|
+
}),
|
|
190
|
+
W,
|
|
191
|
+
O.configure({ nested: !0 }),
|
|
192
|
+
V.configure({
|
|
193
|
+
types: ["heading", "paragraph"]
|
|
194
|
+
}),
|
|
195
|
+
_,
|
|
196
|
+
X.configure({
|
|
197
|
+
resizable: !0
|
|
198
|
+
}),
|
|
199
|
+
K,
|
|
200
|
+
Q,
|
|
201
|
+
J,
|
|
202
|
+
yt.configure({
|
|
203
|
+
inline: !1,
|
|
204
|
+
allowBase64: !0
|
|
205
|
+
}),
|
|
206
|
+
tt.configure({ lowlight: Ht }),
|
|
207
|
+
rt.configure({
|
|
208
|
+
markedOptions: {
|
|
209
|
+
gfm: !0,
|
|
210
|
+
breaks: !1,
|
|
211
|
+
pedantic: !1
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
];
|
|
215
|
+
function g({ onClick: t, active: n, disabled: r, title: o, children: c }) {
|
|
216
|
+
return /* @__PURE__ */ i(
|
|
217
|
+
Nt,
|
|
218
|
+
{
|
|
219
|
+
type: "button",
|
|
220
|
+
size: "icon-xs",
|
|
221
|
+
onClick: t,
|
|
222
|
+
disabled: r,
|
|
223
|
+
title: o,
|
|
224
|
+
"aria-pressed": n,
|
|
225
|
+
className: x(
|
|
226
|
+
"text-muted-foreground/70",
|
|
227
|
+
n && "bg-[color:var(--accent-soft)] text-[color:var(--accent)]"
|
|
228
|
+
),
|
|
229
|
+
children: c
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
function b() {
|
|
234
|
+
return /* @__PURE__ */ i(Tt, { className: "mx-2 h-3.5" });
|
|
235
|
+
}
|
|
236
|
+
function M(t) {
|
|
237
|
+
const n = t.trim().toLowerCase();
|
|
238
|
+
return !n.startsWith("javascript:") && !n.startsWith("data:text/html");
|
|
239
|
+
}
|
|
240
|
+
function N(t) {
|
|
241
|
+
return new Promise((n, r) => {
|
|
242
|
+
const o = new FileReader();
|
|
243
|
+
o.onload = () => n(o.result), o.onerror = () => r(o.error ?? new Error("Read failed")), o.readAsDataURL(t);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
function St(t, n) {
|
|
247
|
+
return `${t.replace(/\/$/, "")}${n}`;
|
|
248
|
+
}
|
|
249
|
+
async function Ut(t, n, r = {}) {
|
|
250
|
+
if (!n) return await N(t);
|
|
251
|
+
const o = await N(t), c = o.indexOf(","), d = c >= 0 ? o.slice(c + 1) : "", m = { "Content-Type": "application/json" };
|
|
252
|
+
r.workspaceRequestId && (m["x-boring-workspace-id"] = r.workspaceRequestId);
|
|
253
|
+
const p = await fetch(St(r.apiBaseUrl ?? "", "/api/v1/files/upload"), {
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: m,
|
|
256
|
+
credentials: "include",
|
|
257
|
+
body: JSON.stringify({
|
|
258
|
+
filename: t.name,
|
|
259
|
+
contentType: t.type,
|
|
260
|
+
contentBase64: d,
|
|
261
|
+
sourcePath: n
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
if (!p.ok) throw new Error(`Upload failed: ${p.status}`);
|
|
265
|
+
const l = await p.json();
|
|
266
|
+
return l.markdownUrl ?? l.path ?? o;
|
|
267
|
+
}
|
|
268
|
+
function $t({
|
|
269
|
+
editor: t,
|
|
270
|
+
documentPath: n,
|
|
271
|
+
apiBaseUrl: r,
|
|
272
|
+
workspaceRequestId: o,
|
|
273
|
+
rawMode: c,
|
|
274
|
+
onToggleRawMode: d
|
|
275
|
+
}) {
|
|
276
|
+
const m = (e) => {
|
|
277
|
+
if (t) {
|
|
278
|
+
if (t.isActive("image")) {
|
|
279
|
+
t.chain().focus().updateAttributes("image", { align: e }).run();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
t.chain().focus().setTextAlign(e).run();
|
|
283
|
+
}
|
|
284
|
+
}, p = v(null), l = D({
|
|
285
|
+
editor: t,
|
|
286
|
+
selector: ({ editor: e }) => e ? {
|
|
287
|
+
bold: e.isActive("bold"),
|
|
288
|
+
italic: e.isActive("italic"),
|
|
289
|
+
underline: e.isActive("underline"),
|
|
290
|
+
strike: e.isActive("strike"),
|
|
291
|
+
h1: e.isActive("heading", { level: 1 }),
|
|
292
|
+
h2: e.isActive("heading", { level: 2 }),
|
|
293
|
+
h3: e.isActive("heading", { level: 3 }),
|
|
294
|
+
bulletList: e.isActive("bulletList"),
|
|
295
|
+
orderedList: e.isActive("orderedList"),
|
|
296
|
+
taskList: e.isActive("taskList"),
|
|
297
|
+
blockquote: e.isActive("blockquote"),
|
|
298
|
+
codeBlock: e.isActive("codeBlock"),
|
|
299
|
+
link: e.isActive("link"),
|
|
300
|
+
highlight: e.isActive("highlight"),
|
|
301
|
+
alignLeft: e.isActive("image") ? (e.getAttributes("image").align ?? "left") === "left" : e.isActive({ textAlign: "left" }),
|
|
302
|
+
alignCenter: e.isActive("image") ? e.getAttributes("image").align === "center" : e.isActive({ textAlign: "center" }),
|
|
303
|
+
alignRight: e.isActive("image") ? e.getAttributes("image").align === "right" : e.isActive({ textAlign: "right" })
|
|
304
|
+
} : null
|
|
305
|
+
});
|
|
306
|
+
if (!t || !l) return null;
|
|
307
|
+
const k = () => {
|
|
308
|
+
const e = window.prompt("URL:");
|
|
309
|
+
e && M(e) && t.chain().focus().extendMarkRange("link").setLink({ href: e }).run();
|
|
310
|
+
}, f = () => {
|
|
311
|
+
const e = window.prompt("Image URL:");
|
|
312
|
+
e && M(e) && t.chain().focus().setImage({ src: e }).run();
|
|
313
|
+
}, h = (e) => {
|
|
314
|
+
var a;
|
|
315
|
+
if (e != null && e.shiftKey) {
|
|
316
|
+
f();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
(a = p.current) == null || a.click();
|
|
320
|
+
}, w = async (e) => {
|
|
321
|
+
var u;
|
|
322
|
+
const a = (u = e.target.files) == null ? void 0 : u[0];
|
|
323
|
+
if (e.target.value = "", !(!a || !a.type.startsWith("image/")))
|
|
324
|
+
try {
|
|
325
|
+
const s = await Ut(a, n, { apiBaseUrl: r, workspaceRequestId: o });
|
|
326
|
+
t.chain().focus().setImage({ src: s, alt: a.name }).run();
|
|
327
|
+
} catch {
|
|
328
|
+
try {
|
|
329
|
+
const s = await N(a);
|
|
330
|
+
t.chain().focus().setImage({ src: s, alt: a.name }).run();
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
return /* @__PURE__ */ T(At, { className: "border-b border-border/60 bg-background px-3 py-1.5", "aria-label": "Formatting toolbar", children: [
|
|
336
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleBold().run(), active: l.bold, title: "Bold", children: /* @__PURE__ */ i(nt, { className: "h-4 w-4" }) }),
|
|
337
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleItalic().run(), active: l.italic, title: "Italic", children: /* @__PURE__ */ i(at, { className: "h-4 w-4" }) }),
|
|
338
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleUnderline().run(), active: l.underline, title: "Underline", children: /* @__PURE__ */ i(ot, { className: "h-4 w-4" }) }),
|
|
339
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleStrike().run(), active: l.strike, title: "Strikethrough", children: /* @__PURE__ */ i(lt, { className: "h-4 w-4" }) }),
|
|
340
|
+
/* @__PURE__ */ i(b, {}),
|
|
341
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleHeading({ level: 1 }).run(), active: l.h1, title: "Heading 1", children: /* @__PURE__ */ i(st, { className: "h-4 w-4" }) }),
|
|
342
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleHeading({ level: 2 }).run(), active: l.h2, title: "Heading 2", children: /* @__PURE__ */ i(ct, { className: "h-4 w-4" }) }),
|
|
343
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleHeading({ level: 3 }).run(), active: l.h3, title: "Heading 3", children: /* @__PURE__ */ i(ut, { className: "h-4 w-4" }) }),
|
|
344
|
+
/* @__PURE__ */ i(b, {}),
|
|
345
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleBulletList().run(), active: l.bulletList, title: "Bullet list", children: /* @__PURE__ */ i(gt, { className: "h-4 w-4" }) }),
|
|
346
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleOrderedList().run(), active: l.orderedList, title: "Ordered list", children: /* @__PURE__ */ i(dt, { className: "h-4 w-4" }) }),
|
|
347
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleTaskList().run(), active: l.taskList, title: "Task list", children: /* @__PURE__ */ i(ft, { className: "h-4 w-4" }) }),
|
|
348
|
+
/* @__PURE__ */ i(b, {}),
|
|
349
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleBlockquote().run(), active: l.blockquote, title: "Quote", children: /* @__PURE__ */ i(mt, { className: "h-4 w-4" }) }),
|
|
350
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleCodeBlock().run(), active: l.codeBlock, title: "Code block", children: /* @__PURE__ */ i(ht, { className: "h-4 w-4" }) }),
|
|
351
|
+
/* @__PURE__ */ i(g, { onClick: k, active: l.link, title: "Link", children: /* @__PURE__ */ i(pt, { className: "h-4 w-4" }) }),
|
|
352
|
+
/* @__PURE__ */ i(
|
|
353
|
+
g,
|
|
354
|
+
{
|
|
355
|
+
onClick: h,
|
|
356
|
+
title: "Image (click to upload, Shift+click for URL)",
|
|
357
|
+
children: /* @__PURE__ */ i(wt, { className: "h-4 w-4" })
|
|
358
|
+
}
|
|
359
|
+
),
|
|
360
|
+
/* @__PURE__ */ i(
|
|
361
|
+
Lt,
|
|
362
|
+
{
|
|
363
|
+
ref: p,
|
|
364
|
+
"data-testid": "image-file-input",
|
|
365
|
+
type: "file",
|
|
366
|
+
accept: "image/*",
|
|
367
|
+
className: "hidden",
|
|
368
|
+
onChange: w
|
|
369
|
+
}
|
|
370
|
+
),
|
|
371
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().toggleHighlight().run(), active: l.highlight, title: "Highlight", children: /* @__PURE__ */ i(kt, { className: "h-4 w-4" }) }),
|
|
372
|
+
/* @__PURE__ */ i(b, {}),
|
|
373
|
+
/* @__PURE__ */ i(g, { onClick: () => m("left"), active: l.alignLeft, title: "Align left", children: /* @__PURE__ */ i(bt, { className: "h-4 w-4" }) }),
|
|
374
|
+
/* @__PURE__ */ i(g, { onClick: () => m("center"), active: l.alignCenter, title: "Center align", children: /* @__PURE__ */ i(vt, { className: "h-4 w-4" }) }),
|
|
375
|
+
/* @__PURE__ */ i(g, { onClick: () => m("right"), active: l.alignRight, title: "Align right", children: /* @__PURE__ */ i(It, { className: "h-4 w-4" }) }),
|
|
376
|
+
/* @__PURE__ */ i(b, {}),
|
|
377
|
+
/* @__PURE__ */ i(g, { onClick: () => t.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: /* @__PURE__ */ i(xt, { className: "h-4 w-4" }) }),
|
|
378
|
+
/* @__PURE__ */ i(b, {}),
|
|
379
|
+
/* @__PURE__ */ i(
|
|
380
|
+
g,
|
|
381
|
+
{
|
|
382
|
+
onClick: d,
|
|
383
|
+
active: c,
|
|
384
|
+
title: c ? "Rich text" : "Raw markdown",
|
|
385
|
+
children: /* @__PURE__ */ i("span", { className: "font-mono text-[10px] font-semibold leading-none tracking-[-0.02em]", children: "MD" })
|
|
386
|
+
}
|
|
387
|
+
)
|
|
388
|
+
] });
|
|
389
|
+
}
|
|
390
|
+
function ae({
|
|
391
|
+
content: t,
|
|
392
|
+
onChange: n,
|
|
393
|
+
readOnly: r = !1,
|
|
394
|
+
placeholder: o,
|
|
395
|
+
className: c,
|
|
396
|
+
documentPath: d
|
|
397
|
+
}) {
|
|
398
|
+
const m = G(), p = Y(), [l, k] = B(!1), f = v(n);
|
|
399
|
+
f.current = n;
|
|
400
|
+
const h = v(!1), w = t || { type: "doc", content: [{ type: "paragraph" }] }, e = t ? "markdown" : "json", a = z({
|
|
401
|
+
extensions: o ? [
|
|
402
|
+
...H.filter((u) => u.name !== "placeholder"),
|
|
403
|
+
S.configure({ placeholder: o })
|
|
404
|
+
] : H,
|
|
405
|
+
content: w,
|
|
406
|
+
contentType: e,
|
|
407
|
+
editable: !r,
|
|
408
|
+
editorProps: {
|
|
409
|
+
attributes: {
|
|
410
|
+
class: "tiptap-prose max-w-[68ch] px-8 py-6 focus:outline-none min-h-[200px]"
|
|
411
|
+
},
|
|
412
|
+
transformPastedHTML: Bt
|
|
413
|
+
},
|
|
414
|
+
onUpdate: ({ editor: u }) => {
|
|
415
|
+
var s, I;
|
|
416
|
+
h.current || (I = f.current) == null || I.call(f, ((s = u.getMarkdown) == null ? void 0 : s.call(u)) ?? u.getHTML());
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
return L(() => {
|
|
420
|
+
!a || a.isDestroyed || a.setEditable(!r);
|
|
421
|
+
}, [a, r]), L(() => {
|
|
422
|
+
var s;
|
|
423
|
+
!a || a.isDestroyed || (((s = a.getMarkdown) == null ? void 0 : s.call(a)) ?? a.getHTML()) === t || (h.current = !0, a.commands.setContent(w, { contentType: e }), h.current = !1);
|
|
424
|
+
}, [a, t]), /* @__PURE__ */ T("div", { className: x("flex h-full flex-col overflow-hidden", c), children: [
|
|
425
|
+
!r && /* @__PURE__ */ i(
|
|
426
|
+
$t,
|
|
427
|
+
{
|
|
428
|
+
editor: a,
|
|
429
|
+
documentPath: d,
|
|
430
|
+
apiBaseUrl: m,
|
|
431
|
+
workspaceRequestId: p,
|
|
432
|
+
rawMode: l,
|
|
433
|
+
onToggleRawMode: () => k((u) => !u)
|
|
434
|
+
}
|
|
435
|
+
),
|
|
436
|
+
/* @__PURE__ */ i("div", { className: "flex-1 overflow-auto", children: l && !r ? /* @__PURE__ */ i(
|
|
437
|
+
"textarea",
|
|
438
|
+
{
|
|
439
|
+
"aria-label": "Raw markdown",
|
|
440
|
+
"data-testid": "markdown-raw-editor",
|
|
441
|
+
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",
|
|
442
|
+
value: t,
|
|
443
|
+
placeholder: o,
|
|
444
|
+
spellCheck: !1,
|
|
445
|
+
onChange: (u) => {
|
|
446
|
+
var s;
|
|
447
|
+
return (s = f.current) == null ? void 0 : s.call(f, u.target.value);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
) : /* @__PURE__ */ i(P, { editor: a }) })
|
|
451
|
+
] });
|
|
452
|
+
}
|
|
453
|
+
export {
|
|
454
|
+
ae as MarkdownEditor,
|
|
455
|
+
M as isSafeUrl,
|
|
456
|
+
N as readFileAsDataUrl,
|
|
457
|
+
Bt as sanitizeHtml
|
|
458
|
+
};
|
|
@@ -2,7 +2,7 @@ import { jsxs as d, jsx as o, Fragment as H } from "react/jsx-runtime";
|
|
|
2
2
|
import { useCallback as b, useMemo as A, useEffect as S, useState as V, Suspense as X, useRef as q } from "react";
|
|
3
3
|
import { LoadingState as Z, ResizeHandle as G, IconButton as $, Button as J, Kbd as Q } from "@hachej/boring-ui-kit";
|
|
4
4
|
import { c as g } from "./utils-B6yFEsav.js";
|
|
5
|
-
import { $ as Y, a6 as ee, E as te, am as ne, ak as re, u as oe } from "./CommandPalette-
|
|
5
|
+
import { $ as Y, a6 as ee, E as te, am as ne, ak as re, u as oe } from "./CommandPalette-CdiVSPYz.js";
|
|
6
6
|
import { Search as ae, Plus as ie } from "lucide-react";
|
|
7
7
|
function be(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 Te, Fragment as x } from "react/jsx-runtime";
|
|
2
2
|
import { useSyncExternalStore as ze, useMemo as v, useRef as K, useState as X, useEffect as y, useCallback as P } from "react";
|
|
3
3
|
import { ChatPanel as Fe, useSessions as Ge } from "@hachej/boring-agent/front";
|
|
4
|
-
import { aj as ke, q as Ye, ak as Qe, u as Xe, al as Ze } from "./CommandPalette-
|
|
5
|
-
import { T as He, C as qe, r as Ee, w as et, W as $e } from "./WorkspaceLoadingState-
|
|
4
|
+
import { aj as ke, q as Ye, ak as Qe, u as Xe, al as Ze } from "./CommandPalette-CdiVSPYz.js";
|
|
5
|
+
import { T as He, C as qe, r as Ee, w as et, W as $e } from "./WorkspaceLoadingState-CLhYOvtL.js";
|
|
6
6
|
function tt() {
|
|
7
7
|
const e = `s${Date.now()}`;
|
|
8
8
|
return {
|
package/dist/testing.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as ka } from "react/jsx-runtime";
|
|
2
2
|
import * as Pa from "react";
|
|
3
3
|
import { createElement as ds, useMemo as Tn, useLayoutEffect as fs, isValidElement as ps, cloneElement as ms, useSyncExternalStore as Ji } from "react";
|
|
4
|
-
import { i as vs, q as bs, ai as hs } from "./CommandPalette-
|
|
4
|
+
import { i as vs, q as bs, ai as hs } from "./CommandPalette-CdiVSPYz.js";
|
|
5
5
|
import { d as ys } from "./panel-DnvDNQac.js";
|
|
6
6
|
import * as Rs from "react-dom/test-utils";
|
|
7
7
|
import Ba from "react-dom";
|
package/dist/workspace.css
CHANGED
|
@@ -2827,6 +2827,10 @@
|
|
|
2827
2827
|
--tw-tracking: -0.01em;
|
|
2828
2828
|
letter-spacing: -0.01em;
|
|
2829
2829
|
}
|
|
2830
|
+
.tracking-\[-0\.02em\] {
|
|
2831
|
+
--tw-tracking: -0.02em;
|
|
2832
|
+
letter-spacing: -0.02em;
|
|
2833
|
+
}
|
|
2830
2834
|
.tracking-\[0\.05em\] {
|
|
2831
2835
|
--tw-tracking: 0.05em;
|
|
2832
2836
|
letter-spacing: 0.05em;
|
|
@@ -3340,6 +3344,14 @@
|
|
|
3340
3344
|
color: var(--boring-muted-foreground);
|
|
3341
3345
|
}
|
|
3342
3346
|
}
|
|
3347
|
+
.placeholder\:text-muted-foreground\/70 {
|
|
3348
|
+
&::placeholder {
|
|
3349
|
+
color: var(--boring-muted-foreground);
|
|
3350
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3351
|
+
color: color-mix(in oklab, var(--boring-muted-foreground) 70%, transparent);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3343
3355
|
.after\:absolute {
|
|
3344
3356
|
&::after {
|
|
3345
3357
|
content: var(--tw-content);
|
package/dist/workspace.d.ts
CHANGED
|
@@ -1018,7 +1018,7 @@ export declare interface LeftTabParams {
|
|
|
1018
1018
|
chromeless?: boolean;
|
|
1019
1019
|
}
|
|
1020
1020
|
|
|
1021
|
-
export declare function MarkdownEditor({ content, onChange, readOnly, placeholder, className, }: MarkdownEditorProps): JSX.Element;
|
|
1021
|
+
export declare function MarkdownEditor({ content, onChange, readOnly, placeholder, className, documentPath, }: MarkdownEditorProps): JSX.Element;
|
|
1022
1022
|
|
|
1023
1023
|
export declare function MarkdownEditorPane({ params, api, className }: MarkdownEditorPaneProps): JSX.Element;
|
|
1024
1024
|
|
|
@@ -1032,6 +1032,8 @@ export declare interface MarkdownEditorProps {
|
|
|
1032
1032
|
readOnly?: boolean;
|
|
1033
1033
|
placeholder?: string;
|
|
1034
1034
|
className?: string;
|
|
1035
|
+
/** Workspace-relative markdown file path, used to make uploaded image links relative. */
|
|
1036
|
+
documentPath?: string;
|
|
1035
1037
|
}
|
|
1036
1038
|
|
|
1037
1039
|
export declare const MAX_PANELS = 50;
|
package/dist/workspace.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var qe = Object.defineProperty;
|
|
2
2
|
var _e = (e, t, r) => t in e ? qe(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
|
|
3
3
|
var ne = (e, t, r) => _e(e, typeof t != "symbol" ? t + "" : t, r);
|
|
4
|
-
import { d as ae, u as Ne, p as Be, P as Ae, a as $e, b as Ke, D as Ve } from "./CommandPalette-
|
|
5
|
-
import { A as xr, C as yr, c as br, e as vr, f as Sr, F as Nr, g as Cr, M as Tr, h as Pr, i as kr, j as Er, k as wr, l as Mr, R as Dr, S as Ir, m as Rr, n as Or, T as Fr, W as Lr, o as zr, q as qr, r as _r, s as Br, t as Ar, v as $r, w as Kr, x as Vr, y as Qr, z as jr, B as Gr, E as Hr, G as Wr, H as Ur, I as Xr, J as Jr, K as Yr, L as Zr, N as ea, O as ta, Q as ra, U as aa, V as na, X as la, Y as oa, Z as sa, _ as ca, $ as ia, a0 as ua, a1 as da, a2 as pa, a3 as fa, a4 as ma, a5 as ga, a6 as ha, a7 as xa, a8 as ya, a9 as ba, aa as va, ab as Sa, ac as Na, ad as Ca, ae as Ta, af as Pa, ag as ka, ah as Ea } from "./CommandPalette-
|
|
4
|
+
import { d as ae, u as Ne, p as Be, P as Ae, a as $e, b as Ke, D as Ve } from "./CommandPalette-CdiVSPYz.js";
|
|
5
|
+
import { A as xr, C as yr, c as br, e as vr, f as Sr, F as Nr, g as Cr, M as Tr, h as Pr, i as kr, j as Er, k as wr, l as Mr, R as Dr, S as Ir, m as Rr, n as Or, T as Fr, W as Lr, o as zr, q as qr, r as _r, s as Br, t as Ar, v as $r, w as Kr, x as Vr, y as Qr, z as jr, B as Gr, E as Hr, G as Wr, H as Ur, I as Xr, J as Jr, K as Yr, L as Zr, N as ea, O as ta, Q as ra, U as aa, V as na, X as la, Y as oa, Z as sa, _ as ca, $ as ia, a0 as ua, a1 as da, a2 as pa, a3 as fa, a4 as ma, a5 as ga, a6 as ha, a7 as xa, a8 as ya, a9 as ba, aa as va, ab as Sa, ac as Na, ad as Ca, ae as Ta, af as Pa, ag as ka, ah as Ea } from "./CommandPalette-CdiVSPYz.js";
|
|
6
6
|
import { jsxs as h, jsx as a, Fragment as Qe } from "react/jsx-runtime";
|
|
7
7
|
import { useSyncExternalStore as je, useState as V, useEffect as U, useRef as w, useCallback as S, useReducer as Ge, useMemo as Z, Suspense as He, Component as We } from "react";
|
|
8
8
|
import { FilterIcon as Ue, XIcon as Xe, ChevronDownIcon as Ce, ChevronRightIcon as Te, Database as Je, BarChart3 as pe, MenuIcon as Ye, PanelLeftOpenIcon as Ze, PanelLeftCloseIcon as et, PinIcon as tt } from "lucide-react";
|
|
@@ -10,10 +10,10 @@ import { EmptyState as Pe, Toolbar as rt, Input as ke, Popover as at, PopoverTri
|
|
|
10
10
|
import { Toaster as Ma, dismissToast as Da, toast as Ia } from "@hachej/boring-ui-kit";
|
|
11
11
|
import { c as H } from "./utils-B6yFEsav.js";
|
|
12
12
|
import { d as we } from "./panel-DnvDNQac.js";
|
|
13
|
-
import { C as Oa, T as Fa, W as La, b as za } from "./WorkspaceLoadingState-
|
|
13
|
+
import { C as Oa, T as Fa, W as La, b as za } from "./WorkspaceLoadingState-CLhYOvtL.js";
|
|
14
14
|
import { C as _a, c as Ba } from "./CodeEditor-DQqOn4xz.js";
|
|
15
|
-
import { FileTree as $a } from "./FileTree-
|
|
16
|
-
import { MarkdownEditor as Va } from "./MarkdownEditor-
|
|
15
|
+
import { FileTree as $a } from "./FileTree-Bgg50HQf.js";
|
|
16
|
+
import { MarkdownEditor as Va } from "./MarkdownEditor-BA37oZKg.js";
|
|
17
17
|
function re(e, t) {
|
|
18
18
|
const { pluginId: r, ...n } = e;
|
|
19
19
|
return t ? { ...n, pluginId: t } : n;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
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.",
|
|
@@ -108,6 +108,7 @@
|
|
|
108
108
|
"@tiptap/extension-task-list": "^3.22.4",
|
|
109
109
|
"@tiptap/extension-text-align": "^3.22.4",
|
|
110
110
|
"@tiptap/extension-underline": "^3.22.4",
|
|
111
|
+
"@tiptap/markdown": "^3.22.4",
|
|
111
112
|
"@tiptap/pm": "^3.22.4",
|
|
112
113
|
"@tiptap/react": "^3.22.4",
|
|
113
114
|
"@tiptap/starter-kit": "^3.22.4",
|
|
@@ -122,11 +123,10 @@
|
|
|
122
123
|
"radix-ui": "^1.4.3",
|
|
123
124
|
"react-arborist": "^3.4.0",
|
|
124
125
|
"tailwind-merge": "^2.0.0",
|
|
125
|
-
"tiptap-markdown": "^0.9.0",
|
|
126
126
|
"zod": "^3.23.0",
|
|
127
127
|
"zustand": "^5.0.0",
|
|
128
|
-
"@hachej/boring-agent": "0.1.
|
|
129
|
-
"@hachej/boring-ui-kit": "0.1.
|
|
128
|
+
"@hachej/boring-agent": "0.1.6",
|
|
129
|
+
"@hachej/boring-ui-kit": "0.1.6"
|
|
130
130
|
},
|
|
131
131
|
"devDependencies": {
|
|
132
132
|
"@tailwindcss/postcss": "^4.0.0",
|
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import { jsxs as A, jsx as t } from "react/jsx-runtime";
|
|
2
|
-
import { useRef as k, useState as y, useEffect as L } from "react";
|
|
3
|
-
import { ReactNodeViewRenderer as S, NodeViewWrapper as B, useEditor as E, EditorContent as U, useEditorState as P } from "@tiptap/react";
|
|
4
|
-
import z from "@tiptap/starter-kit";
|
|
5
|
-
import D from "@tiptap/extension-underline";
|
|
6
|
-
import W from "@tiptap/extension-link";
|
|
7
|
-
import T from "@tiptap/extension-placeholder";
|
|
8
|
-
import F from "@tiptap/extension-task-list";
|
|
9
|
-
import j from "@tiptap/extension-task-item";
|
|
10
|
-
import q from "@tiptap/extension-text-align";
|
|
11
|
-
import V from "@tiptap/extension-highlight";
|
|
12
|
-
import { Table as _ } from "@tiptap/extension-table";
|
|
13
|
-
import { TableRow as $ } from "@tiptap/extension-table-row";
|
|
14
|
-
import { TableHeader as X } from "@tiptap/extension-table-header";
|
|
15
|
-
import { TableCell as K } from "@tiptap/extension-table-cell";
|
|
16
|
-
import O from "@tiptap/extension-image";
|
|
17
|
-
import { c as v } from "./utils-B6yFEsav.js";
|
|
18
|
-
import Q from "@tiptap/extension-code-block-lowlight";
|
|
19
|
-
import { createLowlight as Z, common as G } from "lowlight";
|
|
20
|
-
import { Markdown as J } from "tiptap-markdown";
|
|
21
|
-
import { BoldIcon as Y, ItalicIcon as tt, UnderlineIcon as et, StrikethroughIcon as it, Heading1Icon as rt, Heading2Icon as nt, Heading3Icon as at, ListIcon as ot, ListOrderedIcon as lt, ListChecksIcon as st, QuoteIcon as ct, CodeIcon as ut, LinkIcon as gt, ImageIcon as dt, HighlighterIcon as mt, AlignLeftIcon as ft, AlignCenterIcon as ht, AlignRightIcon as pt, MinusIcon as wt } from "lucide-react";
|
|
22
|
-
import { Toolbar as kt, Input as vt, ToolbarButton as bt, ToolbarSeparator as Lt } from "@hachej/boring-ui-kit";
|
|
23
|
-
const I = 64, x = 2e3, At = O.extend({
|
|
24
|
-
name: "image",
|
|
25
|
-
draggable: !0,
|
|
26
|
-
addAttributes() {
|
|
27
|
-
var a;
|
|
28
|
-
return {
|
|
29
|
-
...((a = this.parent) == null ? void 0 : a.call(this)) ?? {},
|
|
30
|
-
width: {
|
|
31
|
-
default: null,
|
|
32
|
-
parseHTML: (n) => {
|
|
33
|
-
const r = n.getAttribute("width");
|
|
34
|
-
if (r) {
|
|
35
|
-
const s = parseInt(r, 10);
|
|
36
|
-
return Number.isFinite(s) ? s : null;
|
|
37
|
-
}
|
|
38
|
-
const u = n.style.width;
|
|
39
|
-
if (u && u.endsWith("px")) {
|
|
40
|
-
const s = parseInt(u, 10);
|
|
41
|
-
return Number.isFinite(s) ? s : null;
|
|
42
|
-
}
|
|
43
|
-
return null;
|
|
44
|
-
},
|
|
45
|
-
renderHTML: (n) => n.width ? { width: String(n.width) } : {}
|
|
46
|
-
},
|
|
47
|
-
align: {
|
|
48
|
-
default: "left",
|
|
49
|
-
parseHTML: (n) => {
|
|
50
|
-
const r = n.getAttribute("data-align");
|
|
51
|
-
return r === "left" || r === "center" || r === "right" ? r : n.style.marginLeft === "auto" && n.style.marginRight === "auto" ? "center" : n.style.marginLeft === "auto" ? "right" : "left";
|
|
52
|
-
},
|
|
53
|
-
renderHTML: (n) => ({ "data-align": n.align ?? "left" })
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
},
|
|
57
|
-
addNodeView() {
|
|
58
|
-
return S(It);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
function It({ node: i, updateAttributes: a, selected: n }) {
|
|
62
|
-
const r = k(null), u = k(null), [s, d] = y(!1), c = i.attrs.src ?? "", e = i.attrs.alt ?? "", o = i.attrs.title ?? void 0, g = i.attrs.width, m = i.attrs.align ?? "left";
|
|
63
|
-
L(() => {
|
|
64
|
-
if (!s) return;
|
|
65
|
-
const h = (b) => {
|
|
66
|
-
const p = u.current;
|
|
67
|
-
if (!p) return;
|
|
68
|
-
const R = b.clientX - p.x, M = Math.max(I, Math.min(x, p.width + R));
|
|
69
|
-
a({ width: Math.round(M) });
|
|
70
|
-
}, f = () => {
|
|
71
|
-
u.current = null, d(!1);
|
|
72
|
-
};
|
|
73
|
-
return window.addEventListener("pointermove", h), window.addEventListener("pointerup", f), window.addEventListener("pointercancel", f), () => {
|
|
74
|
-
window.removeEventListener("pointermove", h), window.removeEventListener("pointerup", f), window.removeEventListener("pointercancel", f);
|
|
75
|
-
};
|
|
76
|
-
}, [s, a]);
|
|
77
|
-
const H = (h) => {
|
|
78
|
-
var p;
|
|
79
|
-
h.preventDefault(), h.stopPropagation();
|
|
80
|
-
const f = (p = r.current) == null ? void 0 : p.querySelector("img"), b = g ?? (f == null ? void 0 : f.getBoundingClientRect().width) ?? 320;
|
|
81
|
-
u.current = { x: h.clientX, width: b }, d(!0);
|
|
82
|
-
};
|
|
83
|
-
return /* @__PURE__ */ A(
|
|
84
|
-
B,
|
|
85
|
-
{
|
|
86
|
-
ref: r,
|
|
87
|
-
"data-resizable-image": "",
|
|
88
|
-
"data-selected": n ? "true" : void 0,
|
|
89
|
-
className: v(
|
|
90
|
-
"relative block max-w-full align-baseline",
|
|
91
|
-
"[&>img]:block [&>img]:max-w-full [&>img]:h-auto [&>img]:rounded-md",
|
|
92
|
-
m === "left" && "mr-auto",
|
|
93
|
-
m === "center" && "mx-auto",
|
|
94
|
-
m === "right" && "ml-auto",
|
|
95
|
-
n && "ring-2 ring-[color:var(--accent)] ring-offset-1 ring-offset-background"
|
|
96
|
-
),
|
|
97
|
-
style: { width: g ? `${g}px` : void 0 },
|
|
98
|
-
children: [
|
|
99
|
-
/* @__PURE__ */ t("img", { src: c, alt: e, title: o, draggable: !1 }),
|
|
100
|
-
/* @__PURE__ */ t(
|
|
101
|
-
"span",
|
|
102
|
-
{
|
|
103
|
-
role: "slider",
|
|
104
|
-
"aria-label": "Resize image",
|
|
105
|
-
"aria-valuenow": g ?? 0,
|
|
106
|
-
"aria-valuemin": I,
|
|
107
|
-
"aria-valuemax": x,
|
|
108
|
-
"data-testid": "resize-handle",
|
|
109
|
-
onPointerDown: H,
|
|
110
|
-
className: v(
|
|
111
|
-
"absolute right-0 bottom-0 h-3 w-3 translate-x-1/2 translate-y-1/2 cursor-nwse-resize",
|
|
112
|
-
"rounded-full border border-background bg-[color:var(--accent)] shadow",
|
|
113
|
-
"opacity-0 transition-opacity duration-150 ease-out",
|
|
114
|
-
(n || s) && "opacity-100"
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
)
|
|
118
|
-
]
|
|
119
|
-
}
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
const xt = Z(G), Ct = [
|
|
123
|
-
/<script[\s>][\s\S]*?<\/script>/gi,
|
|
124
|
-
/<iframe[\s>][\s\S]*?<\/iframe>/gi,
|
|
125
|
-
/\s+on\w+\s*=\s*["'][^"']*["']/gi,
|
|
126
|
-
/\s+on\w+\s*=\s*\S+/gi,
|
|
127
|
-
/href\s*=\s*["']?\s*javascript:[^"'\s>]*/gi,
|
|
128
|
-
/src\s*=\s*["']?\s*javascript:[^"'\s>]*/gi
|
|
129
|
-
];
|
|
130
|
-
function Nt(i) {
|
|
131
|
-
let a = i;
|
|
132
|
-
for (const n of Ct)
|
|
133
|
-
a = a.replace(n, "");
|
|
134
|
-
return a;
|
|
135
|
-
}
|
|
136
|
-
const C = [
|
|
137
|
-
z.configure({
|
|
138
|
-
codeBlock: !1,
|
|
139
|
-
link: !1,
|
|
140
|
-
underline: !1
|
|
141
|
-
}),
|
|
142
|
-
D,
|
|
143
|
-
W.configure({
|
|
144
|
-
openOnClick: !0,
|
|
145
|
-
autolink: !0,
|
|
146
|
-
linkOnPaste: !0,
|
|
147
|
-
defaultProtocol: "https",
|
|
148
|
-
HTMLAttributes: { rel: "noopener noreferrer nofollow", target: "_blank" }
|
|
149
|
-
}),
|
|
150
|
-
T.configure({
|
|
151
|
-
placeholder: "Start writing..."
|
|
152
|
-
}),
|
|
153
|
-
F,
|
|
154
|
-
j.configure({ nested: !0 }),
|
|
155
|
-
q.configure({
|
|
156
|
-
types: ["heading", "paragraph"]
|
|
157
|
-
}),
|
|
158
|
-
V,
|
|
159
|
-
_.configure({
|
|
160
|
-
resizable: !0
|
|
161
|
-
}),
|
|
162
|
-
$,
|
|
163
|
-
X,
|
|
164
|
-
K,
|
|
165
|
-
At.configure({
|
|
166
|
-
inline: !1,
|
|
167
|
-
allowBase64: !0
|
|
168
|
-
}),
|
|
169
|
-
Q.configure({ lowlight: xt }),
|
|
170
|
-
J.configure({
|
|
171
|
-
html: !0,
|
|
172
|
-
transformPastedText: !0,
|
|
173
|
-
transformCopiedText: !0
|
|
174
|
-
})
|
|
175
|
-
];
|
|
176
|
-
function l({ onClick: i, active: a, disabled: n, title: r, children: u }) {
|
|
177
|
-
return /* @__PURE__ */ t(
|
|
178
|
-
bt,
|
|
179
|
-
{
|
|
180
|
-
type: "button",
|
|
181
|
-
size: "icon-xs",
|
|
182
|
-
onClick: i,
|
|
183
|
-
disabled: n,
|
|
184
|
-
title: r,
|
|
185
|
-
"aria-pressed": a,
|
|
186
|
-
className: v(
|
|
187
|
-
"text-muted-foreground/70",
|
|
188
|
-
a && "bg-[color:var(--accent-soft)] text-[color:var(--accent)]"
|
|
189
|
-
),
|
|
190
|
-
children: u
|
|
191
|
-
}
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
function w() {
|
|
195
|
-
return /* @__PURE__ */ t(Lt, { className: "mx-2 h-3.5" });
|
|
196
|
-
}
|
|
197
|
-
function N(i) {
|
|
198
|
-
const a = i.trim().toLowerCase();
|
|
199
|
-
return !a.startsWith("javascript:") && !a.startsWith("data:text/html");
|
|
200
|
-
}
|
|
201
|
-
function Tt(i) {
|
|
202
|
-
return new Promise((a, n) => {
|
|
203
|
-
const r = new FileReader();
|
|
204
|
-
r.onload = () => a(r.result), r.onerror = () => n(r.error ?? new Error("Read failed")), r.readAsDataURL(i);
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
function Ht({ editor: i }) {
|
|
208
|
-
const a = (e) => {
|
|
209
|
-
if (i) {
|
|
210
|
-
if (i.isActive("image")) {
|
|
211
|
-
i.chain().focus().updateAttributes("image", { align: e }).run();
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
i.chain().focus().setTextAlign(e).run();
|
|
215
|
-
}
|
|
216
|
-
}, n = k(null), r = P({
|
|
217
|
-
editor: i,
|
|
218
|
-
selector: ({ editor: e }) => e ? {
|
|
219
|
-
bold: e.isActive("bold"),
|
|
220
|
-
italic: e.isActive("italic"),
|
|
221
|
-
underline: e.isActive("underline"),
|
|
222
|
-
strike: e.isActive("strike"),
|
|
223
|
-
h1: e.isActive("heading", { level: 1 }),
|
|
224
|
-
h2: e.isActive("heading", { level: 2 }),
|
|
225
|
-
h3: e.isActive("heading", { level: 3 }),
|
|
226
|
-
bulletList: e.isActive("bulletList"),
|
|
227
|
-
orderedList: e.isActive("orderedList"),
|
|
228
|
-
taskList: e.isActive("taskList"),
|
|
229
|
-
blockquote: e.isActive("blockquote"),
|
|
230
|
-
codeBlock: e.isActive("codeBlock"),
|
|
231
|
-
link: e.isActive("link"),
|
|
232
|
-
highlight: e.isActive("highlight"),
|
|
233
|
-
alignLeft: e.isActive("image") ? (e.getAttributes("image").align ?? "left") === "left" : e.isActive({ textAlign: "left" }),
|
|
234
|
-
alignCenter: e.isActive("image") ? e.getAttributes("image").align === "center" : e.isActive({ textAlign: "center" }),
|
|
235
|
-
alignRight: e.isActive("image") ? e.getAttributes("image").align === "right" : e.isActive({ textAlign: "right" })
|
|
236
|
-
} : null
|
|
237
|
-
});
|
|
238
|
-
if (!i || !r) return null;
|
|
239
|
-
const u = () => {
|
|
240
|
-
const e = window.prompt("URL:");
|
|
241
|
-
e && N(e) && i.chain().focus().extendMarkRange("link").setLink({ href: e }).run();
|
|
242
|
-
}, s = () => {
|
|
243
|
-
const e = window.prompt("Image URL:");
|
|
244
|
-
e && N(e) && i.chain().focus().setImage({ src: e }).run();
|
|
245
|
-
}, d = (e) => {
|
|
246
|
-
var o;
|
|
247
|
-
if (e != null && e.shiftKey) {
|
|
248
|
-
s();
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
(o = n.current) == null || o.click();
|
|
252
|
-
}, c = async (e) => {
|
|
253
|
-
var g;
|
|
254
|
-
const o = (g = e.target.files) == null ? void 0 : g[0];
|
|
255
|
-
if (e.target.value = "", !(!o || !o.type.startsWith("image/")))
|
|
256
|
-
try {
|
|
257
|
-
const m = await Tt(o);
|
|
258
|
-
i.chain().focus().setImage({ src: m, alt: o.name }).run();
|
|
259
|
-
} catch {
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
return /* @__PURE__ */ A(kt, { className: "border-b border-border/60 bg-background px-3 py-1.5", "aria-label": "Formatting toolbar", children: [
|
|
263
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleBold().run(), active: r.bold, title: "Bold", children: /* @__PURE__ */ t(Y, { className: "h-4 w-4" }) }),
|
|
264
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleItalic().run(), active: r.italic, title: "Italic", children: /* @__PURE__ */ t(tt, { className: "h-4 w-4" }) }),
|
|
265
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleUnderline().run(), active: r.underline, title: "Underline", children: /* @__PURE__ */ t(et, { className: "h-4 w-4" }) }),
|
|
266
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleStrike().run(), active: r.strike, title: "Strikethrough", children: /* @__PURE__ */ t(it, { className: "h-4 w-4" }) }),
|
|
267
|
-
/* @__PURE__ */ t(w, {}),
|
|
268
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleHeading({ level: 1 }).run(), active: r.h1, title: "Heading 1", children: /* @__PURE__ */ t(rt, { className: "h-4 w-4" }) }),
|
|
269
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleHeading({ level: 2 }).run(), active: r.h2, title: "Heading 2", children: /* @__PURE__ */ t(nt, { className: "h-4 w-4" }) }),
|
|
270
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleHeading({ level: 3 }).run(), active: r.h3, title: "Heading 3", children: /* @__PURE__ */ t(at, { className: "h-4 w-4" }) }),
|
|
271
|
-
/* @__PURE__ */ t(w, {}),
|
|
272
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleBulletList().run(), active: r.bulletList, title: "Bullet list", children: /* @__PURE__ */ t(ot, { className: "h-4 w-4" }) }),
|
|
273
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleOrderedList().run(), active: r.orderedList, title: "Ordered list", children: /* @__PURE__ */ t(lt, { className: "h-4 w-4" }) }),
|
|
274
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleTaskList().run(), active: r.taskList, title: "Task list", children: /* @__PURE__ */ t(st, { className: "h-4 w-4" }) }),
|
|
275
|
-
/* @__PURE__ */ t(w, {}),
|
|
276
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleBlockquote().run(), active: r.blockquote, title: "Quote", children: /* @__PURE__ */ t(ct, { className: "h-4 w-4" }) }),
|
|
277
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleCodeBlock().run(), active: r.codeBlock, title: "Code block", children: /* @__PURE__ */ t(ut, { className: "h-4 w-4" }) }),
|
|
278
|
-
/* @__PURE__ */ t(l, { onClick: u, active: r.link, title: "Link", children: /* @__PURE__ */ t(gt, { className: "h-4 w-4" }) }),
|
|
279
|
-
/* @__PURE__ */ t(
|
|
280
|
-
l,
|
|
281
|
-
{
|
|
282
|
-
onClick: d,
|
|
283
|
-
title: "Image (click to upload, Shift+click for URL)",
|
|
284
|
-
children: /* @__PURE__ */ t(dt, { className: "h-4 w-4" })
|
|
285
|
-
}
|
|
286
|
-
),
|
|
287
|
-
/* @__PURE__ */ t(
|
|
288
|
-
vt,
|
|
289
|
-
{
|
|
290
|
-
ref: n,
|
|
291
|
-
"data-testid": "image-file-input",
|
|
292
|
-
type: "file",
|
|
293
|
-
accept: "image/*",
|
|
294
|
-
className: "hidden",
|
|
295
|
-
onChange: c
|
|
296
|
-
}
|
|
297
|
-
),
|
|
298
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().toggleHighlight().run(), active: r.highlight, title: "Highlight", children: /* @__PURE__ */ t(mt, { className: "h-4 w-4" }) }),
|
|
299
|
-
/* @__PURE__ */ t(w, {}),
|
|
300
|
-
/* @__PURE__ */ t(l, { onClick: () => a("left"), active: r.alignLeft, title: "Align left", children: /* @__PURE__ */ t(ft, { className: "h-4 w-4" }) }),
|
|
301
|
-
/* @__PURE__ */ t(l, { onClick: () => a("center"), active: r.alignCenter, title: "Center align", children: /* @__PURE__ */ t(ht, { className: "h-4 w-4" }) }),
|
|
302
|
-
/* @__PURE__ */ t(l, { onClick: () => a("right"), active: r.alignRight, title: "Align right", children: /* @__PURE__ */ t(pt, { className: "h-4 w-4" }) }),
|
|
303
|
-
/* @__PURE__ */ t(w, {}),
|
|
304
|
-
/* @__PURE__ */ t(l, { onClick: () => i.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: /* @__PURE__ */ t(wt, { className: "h-4 w-4" }) })
|
|
305
|
-
] });
|
|
306
|
-
}
|
|
307
|
-
function Gt({
|
|
308
|
-
content: i,
|
|
309
|
-
onChange: a,
|
|
310
|
-
readOnly: n = !1,
|
|
311
|
-
placeholder: r,
|
|
312
|
-
className: u
|
|
313
|
-
}) {
|
|
314
|
-
const s = k(a);
|
|
315
|
-
s.current = a;
|
|
316
|
-
const d = k(!1), c = E({
|
|
317
|
-
extensions: r ? [
|
|
318
|
-
...C.filter((e) => e.name !== "placeholder"),
|
|
319
|
-
T.configure({ placeholder: r })
|
|
320
|
-
] : C,
|
|
321
|
-
content: i,
|
|
322
|
-
editable: !n,
|
|
323
|
-
editorProps: {
|
|
324
|
-
attributes: {
|
|
325
|
-
class: "tiptap-prose max-w-[68ch] px-8 py-6 focus:outline-none min-h-[200px]"
|
|
326
|
-
},
|
|
327
|
-
transformPastedHTML: Nt
|
|
328
|
-
},
|
|
329
|
-
onUpdate: ({ editor: e }) => {
|
|
330
|
-
var o, g, m;
|
|
331
|
-
d.current || (m = s.current) == null || m.call(s, ((g = (o = e.storage.markdown) == null ? void 0 : o.getMarkdown) == null ? void 0 : g.call(o)) ?? e.getHTML());
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
return L(() => {
|
|
335
|
-
!c || c.isDestroyed || c.setEditable(!n);
|
|
336
|
-
}, [c, n]), L(() => {
|
|
337
|
-
var o, g;
|
|
338
|
-
!c || c.isDestroyed || (((g = (o = c.storage.markdown) == null ? void 0 : o.getMarkdown) == null ? void 0 : g.call(o)) ?? c.getHTML()) === i || (d.current = !0, c.commands.setContent(i), d.current = !1);
|
|
339
|
-
}, [c, i]), /* @__PURE__ */ A("div", { className: v("flex h-full flex-col overflow-hidden", u), children: [
|
|
340
|
-
!n && /* @__PURE__ */ t(Ht, { editor: c }),
|
|
341
|
-
/* @__PURE__ */ t("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ t(U, { editor: c }) })
|
|
342
|
-
] });
|
|
343
|
-
}
|
|
344
|
-
export {
|
|
345
|
-
Gt as MarkdownEditor,
|
|
346
|
-
N as isSafeUrl,
|
|
347
|
-
Tt as readFileAsDataUrl,
|
|
348
|
-
Nt as sanitizeHtml
|
|
349
|
-
};
|