@hachej/boring-workspace 0.1.31 → 0.1.33

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.
@@ -0,0 +1,289 @@
1
+ import { jsx as c, jsxs as z } from "react/jsx-runtime";
2
+ import { useRef as D, useEffect as A, useMemo as M, useCallback as w, createContext as S, useContext as $ } from "react";
3
+ import { Tree as E } from "react-arborist";
4
+ import { FolderOpenIcon as J, FolderIcon as K, ChevronRightIcon as U, Loader2Icon as V } from "lucide-react";
5
+ import { L as X } from "./WorkspaceProvider-CuIZx1ua.js";
6
+ import { EmptyState as Y, Input as Z } from "@hachej/boring-ui-kit";
7
+ import { c as N } from "./utils-B6yFEsav.js";
8
+ import { createDragDropManager as y } from "dnd-core";
9
+ import { HTML5Backend as G } from "react-dnd-html5-backend";
10
+ const F = Symbol.for("@hachej/boring-workspace/file-tree-dnd-manager");
11
+ function H() {
12
+ const e = globalThis;
13
+ return e[F] ?? (e[F] = y(
14
+ G,
15
+ typeof window > "u" ? void 0 : window
16
+ )), e[F];
17
+ }
18
+ const P = /* @__PURE__ */ new Set(), C = S({
19
+ onContextMenu: void 0,
20
+ editing: null,
21
+ pendingPaths: P,
22
+ onSubmitEdit: void 0,
23
+ onCancelEdit: void 0
24
+ });
25
+ function Q({
26
+ initialValue: e,
27
+ onSubmit: u,
28
+ onCancel: s,
29
+ isDraft: f
30
+ }) {
31
+ const r = D(null), a = D(!1);
32
+ A(() => {
33
+ const t = r.current;
34
+ if (t)
35
+ if (t.focus(), !f && e.includes(".")) {
36
+ const o = e.lastIndexOf(".");
37
+ t.setSelectionRange(0, o);
38
+ } else
39
+ t.select();
40
+ }, [e, f]);
41
+ const l = () => {
42
+ var o;
43
+ if (a.current) return;
44
+ a.current = !0;
45
+ const t = ((o = r.current) == null ? void 0 : o.value.trim()) ?? "";
46
+ !t || t === e ? s() : u(t);
47
+ };
48
+ return /* @__PURE__ */ c(
49
+ Z,
50
+ {
51
+ ref: r,
52
+ type: "text",
53
+ defaultValue: e,
54
+ "data-testid": "file-tree-edit-input",
55
+ "aria-label": f ? "Name" : "Rename",
56
+ onPointerDown: (t) => t.stopPropagation(),
57
+ onClick: (t) => t.stopPropagation(),
58
+ onKeyDown: (t) => {
59
+ t.stopPropagation(), t.key === "Enter" ? (t.preventDefault(), l()) : t.key === "Escape" && (t.preventDefault(), a.current = !0, s());
60
+ },
61
+ onBlur: l,
62
+ className: "h-5 min-w-0 flex-1 rounded-sm border-[color:var(--accent)]/60 px-1 text-[13px] leading-[1.2] focus-visible:ring-[color:var(--accent)]"
63
+ }
64
+ );
65
+ }
66
+ function tt(e, u) {
67
+ if (!(u != null && u.trim())) return e.length;
68
+ const s = u.trim().toLowerCase(), f = (r) => {
69
+ var l;
70
+ let a = 0;
71
+ for (const t of r) {
72
+ const o = t.name.toLowerCase().includes(s), p = (l = t.children) != null && l.length ? f(t.children) : 0;
73
+ (o || p > 0) && (a += 1);
74
+ }
75
+ return a;
76
+ };
77
+ return f(e);
78
+ }
79
+ function et({ node: e, style: u, dragHandle: s }) {
80
+ const { onContextMenu: f, editing: r, pendingPaths: a, onSubmitEdit: l, onCancelEdit: t } = $(C), o = e.data, p = o.kind === "dir", h = (r == null ? void 0 : r.path) === o.path, b = a.has(o.path), k = p ? e.isOpen ? J : K : X(o.name || "untitled");
81
+ return /* @__PURE__ */ z(
82
+ "div",
83
+ {
84
+ ref: s,
85
+ style: u,
86
+ className: N(
87
+ "group relative mx-1 flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[13px] leading-[1.4] cursor-pointer select-none text-foreground",
88
+ "transition-colors duration-150 ease-[cubic-bezier(0.22,1,0.36,1)]",
89
+ !h && "hover:bg-foreground/[0.04]",
90
+ e.isSelected && !h && "bg-[oklch(from_var(--accent)_l_c_h/0.10)] text-foreground font-medium",
91
+ e.willReceiveDrop && "bg-foreground/5 outline outline-1 outline-border"
92
+ ),
93
+ onClick: (d) => {
94
+ h || (d.stopPropagation(), p ? e.toggle() : (e.select(), e.activate()));
95
+ },
96
+ onContextMenu: (d) => {
97
+ h || o.isDraft || (d.preventDefault(), d.stopPropagation(), f == null || f(d, o));
98
+ },
99
+ children: [
100
+ p ? /* @__PURE__ */ c(
101
+ U,
102
+ {
103
+ className: N(
104
+ "h-3 w-3 shrink-0 text-muted-foreground/70 transition-transform duration-150 ease-[cubic-bezier(0.22,1,0.36,1)]",
105
+ e.isOpen && "rotate-90"
106
+ ),
107
+ strokeWidth: 2
108
+ }
109
+ ) : /* @__PURE__ */ c("span", { className: "w-3 shrink-0" }),
110
+ /* @__PURE__ */ c(
111
+ k,
112
+ {
113
+ className: N(
114
+ "h-4 w-4 shrink-0",
115
+ e.isSelected ? "text-[color:var(--accent)]" : "text-muted-foreground/80"
116
+ ),
117
+ strokeWidth: 1.5
118
+ }
119
+ ),
120
+ h ? /* @__PURE__ */ c(
121
+ Q,
122
+ {
123
+ initialValue: (r == null ? void 0 : r.initialValue) ?? o.name ?? "",
124
+ isDraft: !!(r != null && r.isDraft),
125
+ onSubmit: (d) => l == null ? void 0 : l(o.path, d),
126
+ onCancel: () => t == null ? void 0 : t()
127
+ }
128
+ ) : /* @__PURE__ */ c(
129
+ "span",
130
+ {
131
+ className: N(
132
+ "truncate",
133
+ b && "text-muted-foreground italic"
134
+ ),
135
+ children: o.name
136
+ }
137
+ ),
138
+ b && !h && /* @__PURE__ */ c(
139
+ V,
140
+ {
141
+ "data-testid": "file-tree-pending-spinner",
142
+ "aria-label": "Pending",
143
+ className: "ml-auto h-3 w-3 shrink-0 animate-spin text-muted-foreground/70",
144
+ strokeWidth: 2
145
+ }
146
+ )
147
+ ]
148
+ }
149
+ );
150
+ }
151
+ function lt({
152
+ files: e,
153
+ selectedPath: u,
154
+ searchQuery: s,
155
+ height: f = 400,
156
+ editing: r,
157
+ revealPath: a,
158
+ pendingPaths: l,
159
+ onSelect: t,
160
+ onExpand: o,
161
+ onCollapse: p,
162
+ onContextMenu: h,
163
+ onSubmitEdit: b,
164
+ onCancelEdit: k,
165
+ onRevealHandled: d,
166
+ onDragDrop: T,
167
+ className: I
168
+ }) {
169
+ const v = D(null);
170
+ A(() => {
171
+ if (!(r != null && r.isDraft)) return;
172
+ const n = requestAnimationFrame(() => {
173
+ var i;
174
+ (i = v.current) == null || i.scrollTo(r.path);
175
+ });
176
+ return () => cancelAnimationFrame(n);
177
+ }, [r == null ? void 0 : r.isDraft, r == null ? void 0 : r.path]), A(() => {
178
+ if (!a) return;
179
+ let n = 0;
180
+ const i = requestAnimationFrame(() => {
181
+ const m = v.current;
182
+ if (!m) return;
183
+ m.openParents(a);
184
+ const x = m.get(a);
185
+ x && (x.isInternal && x.open(), n = requestAnimationFrame(() => {
186
+ var g;
187
+ (g = v.current) == null || g.scrollTo(a), d == null || d(a);
188
+ }));
189
+ });
190
+ return () => {
191
+ cancelAnimationFrame(i), cancelAnimationFrame(n);
192
+ };
193
+ }, [e, d, a]);
194
+ const L = M(
195
+ () => u || void 0,
196
+ [u]
197
+ ), j = w(
198
+ (n) => {
199
+ n.data.kind === "file" && (t == null || t(n.data.path));
200
+ },
201
+ [t]
202
+ ), O = w(
203
+ (n) => {
204
+ var m;
205
+ const i = (m = v.current) == null ? void 0 : m.get(n);
206
+ i && (i.isOpen ? o == null || o(i.data.path) : p == null || p(i.data.path));
207
+ },
208
+ [o, p]
209
+ ), R = w(
210
+ (n) => {
211
+ if (!T) return;
212
+ const i = !n.parentNode || n.parentNode.isRoot, m = i ? "." : n.parentNode.data.path;
213
+ if (!(!i && n.parentNode.data.kind !== "dir"))
214
+ for (const x of n.dragNodes) {
215
+ const g = x.data.path;
216
+ if (m === g || m !== "." && m.startsWith(g + "/")) return;
217
+ T(g, m);
218
+ }
219
+ },
220
+ [T]
221
+ ), W = w(
222
+ (n) => {
223
+ if (!n.parentNode || n.parentNode.isRoot) return !1;
224
+ if (n.parentNode.data.kind !== "dir") return !0;
225
+ for (const i of n.dragNodes)
226
+ if (n.parentNode.data.path === i.data.path || n.parentNode.data.path.startsWith(i.data.path + "/")) return !0;
227
+ return !1;
228
+ },
229
+ []
230
+ ), q = w(
231
+ (n, i) => n.data.name.toLowerCase().includes(i.toLowerCase()),
232
+ []
233
+ ), B = M(
234
+ () => ({
235
+ onContextMenu: h,
236
+ editing: r ?? null,
237
+ pendingPaths: l ?? P,
238
+ onSubmitEdit: b,
239
+ onCancelEdit: k
240
+ }),
241
+ [h, r, l, b, k]
242
+ ), _ = M(
243
+ () => tt(e, s),
244
+ [e, s]
245
+ );
246
+ return e.length === 0 ? /* @__PURE__ */ c(
247
+ "div",
248
+ {
249
+ className: N(
250
+ "flex h-full items-center justify-center text-sm text-muted-foreground",
251
+ I
252
+ ),
253
+ children: "No files"
254
+ }
255
+ ) : _ === 0 ? /* @__PURE__ */ c("div", { className: N("flex h-full items-center justify-center p-6", I), children: /* @__PURE__ */ c(
256
+ Y,
257
+ {
258
+ className: "min-h-0 border-0",
259
+ title: "No matching files",
260
+ description: s != null && s.trim() ? `No files match “${s.trim()}”.` : "No files match the current filter."
261
+ }
262
+ ) }) : /* @__PURE__ */ c(C.Provider, { value: B, children: /* @__PURE__ */ c("div", { "data-boring-workspace-part": "file-tree", className: N("file-tree", I), children: /* @__PURE__ */ c(
263
+ E,
264
+ {
265
+ ref: v,
266
+ data: e,
267
+ idAccessor: "path",
268
+ childrenAccessor: "children",
269
+ openByDefault: !1,
270
+ width: "100%",
271
+ height: f,
272
+ rowHeight: 26,
273
+ indent: 14,
274
+ selection: L,
275
+ searchTerm: s ?? "",
276
+ searchMatch: q,
277
+ onActivate: j,
278
+ onToggle: O,
279
+ onMove: R,
280
+ disableDrop: W,
281
+ disableEdit: !0,
282
+ dndManager: H(),
283
+ children: et
284
+ }
285
+ ) }) });
286
+ }
287
+ export {
288
+ lt as FileTree
289
+ };
@@ -15,7 +15,7 @@ import { TableHeader as ut } from "@tiptap/extension-table-header";
15
15
  import { TableCell as gt } from "@tiptap/extension-table-cell";
16
16
  import dt from "@tiptap/extension-image";
17
17
  import { c as S } from "./utils-B6yFEsav.js";
18
- import { _ as j, aq as _ } from "./WorkspaceProvider-0V-2x7AH.js";
18
+ import { _ as j, aq as _ } from "./WorkspaceProvider-CuIZx1ua.js";
19
19
  import { uploadFile as ft } from "@hachej/boring-agent/front";
20
20
  import mt from "@tiptap/extension-code-block-lowlight";
21
21
  import { createLowlight as pt, common as ht } from "lowlight";