vfs-kit 1.0.1 → 1.0.2

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.
Files changed (61) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +145 -35
  3. package/dist/VfsAdapter-BWjniD9Y.d.mts +57 -0
  4. package/dist/VfsAdapter-DOBt_TyL.d.ts +57 -0
  5. package/dist/VfsEngine-B6nhgyjQ.d.mts +152 -0
  6. package/dist/VfsEngine-DLx0iUpi.d.ts +152 -0
  7. package/dist/VfsNode-D10gxL5W.d.mts +48 -0
  8. package/dist/VfsNode-D10gxL5W.d.ts +48 -0
  9. package/dist/adapters/index.d.mts +201 -0
  10. package/dist/adapters/index.d.ts +201 -0
  11. package/dist/adapters/index.js +1159 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/index.mjs +1159 -0
  14. package/dist/adapters/index.mjs.map +1 -0
  15. package/dist/chunk-2FEJBM4N.js +60 -0
  16. package/dist/chunk-2FEJBM4N.js.map +1 -0
  17. package/dist/chunk-7OQI6PNM.mjs +60 -0
  18. package/dist/chunk-7OQI6PNM.mjs.map +1 -0
  19. package/dist/chunk-ALWOZGZI.mjs +23 -0
  20. package/dist/chunk-ALWOZGZI.mjs.map +1 -0
  21. package/dist/chunk-POSVS4C7.mjs +531 -0
  22. package/dist/chunk-POSVS4C7.mjs.map +1 -0
  23. package/dist/chunk-R3ROYAMW.js +23 -0
  24. package/dist/chunk-R3ROYAMW.js.map +1 -0
  25. package/dist/chunk-SWRBVSS6.mjs +16 -0
  26. package/dist/chunk-SWRBVSS6.mjs.map +1 -0
  27. package/dist/chunk-U2CKTXY7.js +16 -0
  28. package/dist/chunk-U2CKTXY7.js.map +1 -0
  29. package/dist/chunk-WZVVI3HX.js +531 -0
  30. package/dist/chunk-WZVVI3HX.js.map +1 -0
  31. package/dist/components/index.d.mts +193 -0
  32. package/dist/components/index.d.ts +193 -0
  33. package/dist/components/index.js +1197 -0
  34. package/dist/components/index.js.map +1 -0
  35. package/dist/components/index.mjs +1197 -0
  36. package/dist/components/index.mjs.map +1 -0
  37. package/dist/hooks/index.d.mts +120 -0
  38. package/dist/hooks/index.d.ts +120 -0
  39. package/dist/hooks/index.js +51 -0
  40. package/dist/hooks/index.js.map +1 -0
  41. package/dist/hooks/index.mjs +51 -0
  42. package/dist/hooks/index.mjs.map +1 -0
  43. package/dist/index.d.mts +42 -0
  44. package/dist/index.d.ts +38 -3
  45. package/dist/index.js +528 -13
  46. package/dist/index.js.map +1 -0
  47. package/dist/index.mjs +530 -0
  48. package/dist/index.mjs.map +1 -0
  49. package/dist/useVfsTabs-ZHDaLrM1.d.mts +39 -0
  50. package/dist/useVfsTabs-ZHDaLrM1.d.ts +39 -0
  51. package/package.json +59 -61
  52. package/dist/index.cjs +0 -43
  53. package/dist/index.d.cts +0 -7
  54. package/index.js +0 -7
  55. package/src/components/TreeView.tsx +0 -5
  56. package/src/components/index.ts +0 -1
  57. package/src/hooks/index.ts +0 -1
  58. package/src/hooks/useVfs.ts +0 -3
  59. package/src/index.ts +0 -2
  60. package/tsconfig.json +0 -44
  61. package/tsup.config.ts +0 -10
@@ -0,0 +1,1197 @@
1
+ "use client";
2
+ import {
3
+ useVfsEngine,
4
+ useVfsExpanded,
5
+ useVfsSelection,
6
+ useVfsTabs
7
+ } from "../chunk-POSVS4C7.mjs";
8
+ import "../chunk-SWRBVSS6.mjs";
9
+ import {
10
+ __async,
11
+ __objRest,
12
+ __spreadProps,
13
+ __spreadValues
14
+ } from "../chunk-7OQI6PNM.mjs";
15
+
16
+ // src/react/components/inline-input.tsx
17
+ import { useEffect, useRef, useState } from "react";
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ function InlineInput({
20
+ initialValue = "",
21
+ onSubmit,
22
+ onComplete,
23
+ validate,
24
+ icon,
25
+ className,
26
+ selectOnMount = true,
27
+ trim = true
28
+ }) {
29
+ const inputRef = useRef(null);
30
+ const [value, setValue] = useState(initialValue);
31
+ const [error, setError] = useState(null);
32
+ const committed = useRef(false);
33
+ useEffect(() => {
34
+ const el = inputRef.current;
35
+ if (!el) return;
36
+ el.focus();
37
+ if (selectOnMount) el.select();
38
+ }, [selectOnMount]);
39
+ const commit = () => {
40
+ var _a;
41
+ if (committed.current) return;
42
+ const final = trim ? value.trim() : value;
43
+ if (!final) {
44
+ onComplete();
45
+ return;
46
+ }
47
+ if (validate) {
48
+ const err = validate(final);
49
+ if (err) {
50
+ setError(err);
51
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
52
+ return;
53
+ }
54
+ }
55
+ committed.current = true;
56
+ onSubmit(final);
57
+ onComplete();
58
+ };
59
+ const cancel = () => {
60
+ if (committed.current) return;
61
+ committed.current = true;
62
+ onComplete();
63
+ };
64
+ const onKeyDown = (e) => {
65
+ if (e.key === "Enter") {
66
+ e.preventDefault();
67
+ commit();
68
+ }
69
+ if (e.key === "Escape") {
70
+ e.preventDefault();
71
+ cancel();
72
+ }
73
+ e.stopPropagation();
74
+ };
75
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4, width: "100%" }, children: [
76
+ icon && /* @__PURE__ */ jsx("span", { style: { flexShrink: 0, display: "flex", alignItems: "center" }, children: icon }),
77
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, position: "relative" }, children: [
78
+ /* @__PURE__ */ jsx(
79
+ "input",
80
+ {
81
+ ref: inputRef,
82
+ value,
83
+ onChange: (e) => {
84
+ setValue(e.target.value);
85
+ setError(null);
86
+ },
87
+ onKeyDown,
88
+ onBlur: commit,
89
+ className,
90
+ style: { width: "100%", boxSizing: "border-box" },
91
+ spellCheck: false,
92
+ autoComplete: "off",
93
+ autoCorrect: "off"
94
+ }
95
+ ),
96
+ error && /* @__PURE__ */ jsx("div", { style: {
97
+ position: "absolute",
98
+ top: "100%",
99
+ left: 0,
100
+ zIndex: 100,
101
+ fontSize: 11,
102
+ color: "#f87171",
103
+ whiteSpace: "nowrap",
104
+ pointerEvents: "none"
105
+ }, children: error })
106
+ ] })
107
+ ] });
108
+ }
109
+
110
+ // src/react/components/file-renderer.tsx
111
+ import { useEffect as useEffect2, useState as useState2 } from "react";
112
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
113
+ function FileRendererBase({
114
+ node,
115
+ content: externalContent,
116
+ children,
117
+ fallback,
118
+ onLoad,
119
+ onError
120
+ }) {
121
+ const [content, setContent] = useState2(externalContent != null ? externalContent : null);
122
+ const [loading, setLoading] = useState2(false);
123
+ const [error, setError] = useState2(null);
124
+ useEffect2(() => {
125
+ if (externalContent !== void 0) {
126
+ setContent(externalContent);
127
+ setError(null);
128
+ return;
129
+ }
130
+ if (!node) {
131
+ setContent(null);
132
+ setError(null);
133
+ return;
134
+ }
135
+ setContent(null);
136
+ }, [node == null ? void 0 : node.id, externalContent]);
137
+ if (!node) return /* @__PURE__ */ jsx2(Fragment, { children: fallback != null ? fallback : null });
138
+ return /* @__PURE__ */ jsx2(Fragment, { children: children({ node, content, loading, error }) });
139
+ }
140
+ function FileRenderer({
141
+ workspaceId,
142
+ activeNodeId,
143
+ children,
144
+ fallback,
145
+ onLoad,
146
+ onError
147
+ }) {
148
+ const { tree } = useVfsEngine(workspaceId);
149
+ const [activeNode, setActiveNode] = useState2(null);
150
+ const [content, setContent] = useState2(null);
151
+ const [loading, setLoading] = useState2(false);
152
+ const [error, setError] = useState2(null);
153
+ useEffect2(() => {
154
+ if (!activeNodeId) {
155
+ setActiveNode(null);
156
+ setContent(null);
157
+ setError(null);
158
+ setLoading(false);
159
+ return;
160
+ }
161
+ let cancelled = false;
162
+ const resolveAndLoad = () => __async(null, null, function* () {
163
+ setContent(null);
164
+ setError(null);
165
+ setLoading(true);
166
+ try {
167
+ const node = yield tree.getNode(activeNodeId);
168
+ if (cancelled) return;
169
+ if (!node || node.kind !== "file") {
170
+ setActiveNode(null);
171
+ setLoading(false);
172
+ return;
173
+ }
174
+ const fileNode = node;
175
+ setActiveNode(fileNode);
176
+ const bytes = yield tree.readFile(activeNodeId);
177
+ if (cancelled) return;
178
+ setContent(bytes);
179
+ onLoad == null ? void 0 : onLoad(fileNode, bytes);
180
+ } catch (err) {
181
+ if (cancelled) return;
182
+ const e = err instanceof Error ? err : new Error(String(err));
183
+ setError(e);
184
+ onError == null ? void 0 : onError(activeNode, e);
185
+ } finally {
186
+ if (!cancelled) setLoading(false);
187
+ }
188
+ });
189
+ resolveAndLoad();
190
+ return () => {
191
+ cancelled = true;
192
+ };
193
+ }, [activeNodeId]);
194
+ if (!activeNode) return /* @__PURE__ */ jsx2(Fragment, { children: fallback != null ? fallback : null });
195
+ return /* @__PURE__ */ jsx2(Fragment, { children: children({ node: activeNode, content, loading, error }) });
196
+ }
197
+
198
+ // src/react/components/tab-list.tsx
199
+ import {
200
+ DndContext,
201
+ closestCenter,
202
+ KeyboardSensor,
203
+ PointerSensor,
204
+ useSensor,
205
+ useSensors
206
+ } from "@dnd-kit/core";
207
+ import {
208
+ SortableContext,
209
+ horizontalListSortingStrategy,
210
+ useSortable,
211
+ sortableKeyboardCoordinates
212
+ } from "@dnd-kit/sortable";
213
+ import { CSS } from "@dnd-kit/utilities";
214
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
215
+ function DefaultTab({
216
+ tab,
217
+ isActive,
218
+ onSetActive,
219
+ onClose,
220
+ dragHandleProps
221
+ }) {
222
+ const handles = dragHandleProps(tab.id);
223
+ return /* @__PURE__ */ jsxs2(
224
+ "div",
225
+ __spreadProps(__spreadValues({}, handles), {
226
+ onClick: () => onSetActive(tab.id),
227
+ style: {
228
+ display: "flex",
229
+ alignItems: "center",
230
+ gap: 6,
231
+ padding: "4px 12px",
232
+ cursor: "pointer",
233
+ userSelect: "none",
234
+ borderBottom: isActive ? "2px solid #3b82f6" : "2px solid transparent",
235
+ opacity: 1
236
+ },
237
+ children: [
238
+ /* @__PURE__ */ jsxs2("span", { style: { fontSize: 13 }, children: [
239
+ tab.isDirty ? `\u25CF ${tab.title}` : tab.title,
240
+ tab.isLocked ? " \u{1F512}" : ""
241
+ ] }),
242
+ !tab.isLocked && /* @__PURE__ */ jsx3(
243
+ "button",
244
+ {
245
+ onClick: (e) => {
246
+ e.stopPropagation();
247
+ onClose(tab.id);
248
+ },
249
+ style: { background: "none", border: "none", cursor: "pointer", padding: 0, lineHeight: 1 },
250
+ children: "\xD7"
251
+ }
252
+ )
253
+ ]
254
+ })
255
+ );
256
+ }
257
+ function SortableTabWrapper({
258
+ tab,
259
+ isActive,
260
+ onSetActive,
261
+ onClose,
262
+ renderTab,
263
+ dragHandleProps
264
+ }) {
265
+ const {
266
+ attributes,
267
+ listeners,
268
+ setNodeRef,
269
+ transform,
270
+ transition,
271
+ isDragging
272
+ } = useSortable({ id: tab.id });
273
+ const style = {
274
+ transform: CSS.Transform.toString(transform),
275
+ transition,
276
+ opacity: isDragging ? 0.4 : 1,
277
+ flexShrink: 0
278
+ };
279
+ const mergedDragHandleProps = (tabId) => __spreadValues(__spreadValues(__spreadValues({}, dragHandleProps(tabId)), attributes), listeners);
280
+ return /* @__PURE__ */ jsx3("div", { ref: setNodeRef, style, children: renderTab ? null : /* @__PURE__ */ jsx3(
281
+ DefaultTab,
282
+ {
283
+ tab,
284
+ isActive,
285
+ onSetActive,
286
+ onClose,
287
+ dragHandleProps: mergedDragHandleProps
288
+ }
289
+ ) });
290
+ }
291
+ function TabListBase({
292
+ tabs,
293
+ activeTabId,
294
+ onReorder,
295
+ onClose,
296
+ onSetActive,
297
+ onLock,
298
+ onUnlock,
299
+ sortable = false,
300
+ children,
301
+ className
302
+ }) {
303
+ var _a;
304
+ const sensors = useSensors(
305
+ useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
306
+ useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
307
+ );
308
+ const handleDragEnd = (event) => {
309
+ const { active, over } = event;
310
+ if (over && active.id !== over.id) {
311
+ onReorder(String(active.id), String(over.id));
312
+ }
313
+ };
314
+ const dragHandleProps = (_tabId) => ({});
315
+ const renderProps = {
316
+ tabs,
317
+ activeTabId,
318
+ activeTab: (_a = tabs.find((t) => t.id === activeTabId)) != null ? _a : null,
319
+ dragHandleProps,
320
+ onClose,
321
+ onSetActive,
322
+ onLock,
323
+ onUnlock
324
+ };
325
+ if (!sortable) {
326
+ return /* @__PURE__ */ jsx3(
327
+ "div",
328
+ {
329
+ className,
330
+ style: { display: "flex", overflow: "hidden" },
331
+ children: children ? children(renderProps) : tabs.map((tab) => /* @__PURE__ */ jsx3(
332
+ DefaultTab,
333
+ {
334
+ tab,
335
+ isActive: tab.id === activeTabId,
336
+ onSetActive,
337
+ onClose,
338
+ dragHandleProps
339
+ },
340
+ tab.id
341
+ ))
342
+ }
343
+ );
344
+ }
345
+ return /* @__PURE__ */ jsx3(
346
+ DndContext,
347
+ {
348
+ sensors,
349
+ collisionDetection: closestCenter,
350
+ onDragEnd: handleDragEnd,
351
+ children: /* @__PURE__ */ jsx3(
352
+ SortableContext,
353
+ {
354
+ items: tabs.map((t) => t.id),
355
+ strategy: horizontalListSortingStrategy,
356
+ children: /* @__PURE__ */ jsx3(
357
+ "div",
358
+ {
359
+ className,
360
+ style: { display: "flex", overflow: "hidden" },
361
+ children: children ? tabs.map((tab) => /* @__PURE__ */ jsx3(
362
+ SortableTabWrapper,
363
+ {
364
+ tab,
365
+ isActive: tab.id === activeTabId,
366
+ onSetActive,
367
+ onClose,
368
+ dragHandleProps
369
+ },
370
+ tab.id
371
+ )) : tabs.map((tab) => /* @__PURE__ */ jsx3(
372
+ SortableTabWrapper,
373
+ {
374
+ tab,
375
+ isActive: tab.id === activeTabId,
376
+ onSetActive,
377
+ onClose,
378
+ dragHandleProps
379
+ },
380
+ tab.id
381
+ ))
382
+ }
383
+ )
384
+ }
385
+ )
386
+ }
387
+ );
388
+ }
389
+ function TabList({
390
+ workspaceIds,
391
+ sortable,
392
+ children,
393
+ className
394
+ }) {
395
+ const tabs = useVfsTabs({ workspaceIds });
396
+ return /* @__PURE__ */ jsx3(
397
+ TabListBase,
398
+ {
399
+ tabs: tabs.tabs,
400
+ activeTabId: tabs.activeTabId,
401
+ onReorder: tabs.reorder,
402
+ onClose: tabs.close,
403
+ onSetActive: tabs.setActive,
404
+ onLock: tabs.lock,
405
+ onUnlock: tabs.unlock,
406
+ sortable,
407
+ className,
408
+ children: children ? (props) => children(__spreadProps(__spreadValues({}, props), {
409
+ dragHandleProps: props.dragHandleProps
410
+ })) : void 0
411
+ }
412
+ );
413
+ }
414
+
415
+ // src/react/components/file-tree/file-tree.tsx
416
+ import { useEffect as useEffect5, useCallback as useCallback2, useState as useState5, useMemo as useMemo2 } from "react";
417
+
418
+ // src/react/components/file-tree/file-tree-base.tsx
419
+ import {
420
+ useRef as useRef3,
421
+ useEffect as useEffect4,
422
+ useCallback,
423
+ useState as useState4,
424
+ useMemo
425
+ } from "react";
426
+ import {
427
+ DndContext as DndContext2,
428
+ DragOverlay,
429
+ PointerSensor as PointerSensor2,
430
+ KeyboardSensor as KeyboardSensor2,
431
+ useSensor as useSensor2,
432
+ useSensors as useSensors2,
433
+ pointerWithin
434
+ } from "@dnd-kit/core";
435
+ import { sortableKeyboardCoordinates as sortableKeyboardCoordinates2 } from "@dnd-kit/sortable";
436
+ import { useVirtualizer } from "@tanstack/react-virtual";
437
+
438
+ // src/react/components/file-tree/helpers.ts
439
+ var ROOT_DROP_ID = "@@root-drop-zone";
440
+ function flattenTree(rootIds, nodes, childIndex, expanded) {
441
+ const result = [];
442
+ const visited = /* @__PURE__ */ new Set();
443
+ function walk(ids, level) {
444
+ var _a;
445
+ for (const id of ids) {
446
+ if (visited.has(id)) continue;
447
+ const node = nodes.get(id);
448
+ if (!node || node.deletedAt !== null) continue;
449
+ visited.add(id);
450
+ const children = (_a = childIndex.get(id)) != null ? _a : [];
451
+ const isOpen = expanded.has(id);
452
+ const hasChildren = children.length > 0;
453
+ result.push({ node, level, index: result.length, isOpen, hasChildren });
454
+ if (isOpen && hasChildren) walk(children, level + 1);
455
+ }
456
+ }
457
+ walk(rootIds, 0);
458
+ return result;
459
+ }
460
+ function isDescendantOf(draggedId, targetId, nodes) {
461
+ let current = nodes.get(targetId);
462
+ while (current == null ? void 0 : current.parentId) {
463
+ if (current.parentId === draggedId) return true;
464
+ current = nodes.get(current.parentId);
465
+ }
466
+ return false;
467
+ }
468
+ function resolveDropTarget(overId, draggedId, nodes) {
469
+ var _a;
470
+ if (overId === ROOT_DROP_ID) return { folderId: null, blocked: false };
471
+ const overNode = nodes.get(overId);
472
+ if (!overNode) return null;
473
+ const folderId = overNode.kind === "folder" ? overNode.id : (_a = overNode.parentId) != null ? _a : null;
474
+ const blocked = folderId !== null && (folderId === draggedId || isDescendantOf(draggedId, folderId, nodes));
475
+ return { folderId, blocked };
476
+ }
477
+ function measureVisibleSubtree(folderIndex, flatNodes) {
478
+ const folderLevel = flatNodes[folderIndex].level;
479
+ let rowCount = 0;
480
+ for (let i = folderIndex + 1; i < flatNodes.length; i++) {
481
+ if (flatNodes[i].level <= folderLevel) break;
482
+ rowCount++;
483
+ }
484
+ return { rowCount };
485
+ }
486
+ function resolveInlineCreateParent(selection, activeNodeId, nodes) {
487
+ var _a, _b;
488
+ const candidateId = (_a = activeNodeId != null ? activeNodeId : selection[selection.length - 1]) != null ? _a : null;
489
+ if (!candidateId) return null;
490
+ const node = nodes.get(candidateId);
491
+ if (!node) return null;
492
+ if (node.kind === "folder") return node.id;
493
+ return (_b = node.parentId) != null ? _b : null;
494
+ }
495
+
496
+ // src/react/components/file-tree/components.tsx
497
+ import { useRef as useRef2, useEffect as useEffect3, useState as useState3 } from "react";
498
+ import {
499
+ useDraggable,
500
+ useDroppable
501
+ } from "@dnd-kit/core";
502
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
503
+ function DefaultFolderOverlay({
504
+ isBlocked,
505
+ isEmpty
506
+ }) {
507
+ return /* @__PURE__ */ jsx4("div", { style: {
508
+ position: "absolute",
509
+ inset: 0,
510
+ pointerEvents: "none",
511
+ borderRadius: 3,
512
+ border: `1px solid ${isBlocked ? "#ef4444" : "#3b82f6"}`,
513
+ background: isBlocked ? "rgba(239,68,68,0.07)" : "rgba(59,130,246,0.08)",
514
+ display: isEmpty ? "flex" : "block",
515
+ alignItems: "center",
516
+ justifyContent: "center",
517
+ fontSize: 11,
518
+ color: isBlocked ? "#ef4444" : "#3b82f6"
519
+ }, children: isEmpty && !isBlocked && /* @__PURE__ */ jsx4("span", { style: { pointerEvents: "none" }, children: "drop here" }) });
520
+ }
521
+ function DropZoneOverlay({
522
+ scrollTop,
523
+ folderIndex,
524
+ rowCount,
525
+ itemHeight,
526
+ emptyStateHeight,
527
+ mode,
528
+ isBlocked,
529
+ targetFolder,
530
+ renderOverlay
531
+ }) {
532
+ const headerTop = folderIndex * itemHeight - scrollTop;
533
+ const headerHeight = itemHeight;
534
+ const isEmpty = rowCount === 0;
535
+ const bodyHeight = isEmpty ? emptyStateHeight : rowCount * itemHeight;
536
+ const renderProps = {
537
+ targetFolder,
538
+ visibleRowCount: rowCount,
539
+ isEmpty,
540
+ mode,
541
+ isBlocked
542
+ };
543
+ const content = renderOverlay ? renderOverlay(renderProps) : /* @__PURE__ */ jsx4(DefaultFolderOverlay, { isBlocked, isEmpty });
544
+ const baseStyle = {
545
+ position: "absolute",
546
+ left: 0,
547
+ right: 0,
548
+ pointerEvents: "none",
549
+ zIndex: 10
550
+ };
551
+ if (mode === "header") return /* @__PURE__ */ jsx4("div", { style: __spreadProps(__spreadValues({}, baseStyle), { top: headerTop, height: headerHeight }), children: content });
552
+ if (mode === "body") return /* @__PURE__ */ jsx4("div", { style: __spreadProps(__spreadValues({}, baseStyle), { top: headerTop + headerHeight, height: bodyHeight }), children: content });
553
+ return /* @__PURE__ */ jsx4("div", { style: __spreadProps(__spreadValues({}, baseStyle), { top: headerTop, height: headerHeight + bodyHeight }), children: content });
554
+ }
555
+ function InlineCreateRow({ kind, level, onSubmit, onCancel }) {
556
+ const inputRef = useRef2(null);
557
+ const committed = useRef2(false);
558
+ useEffect3(() => {
559
+ var _a;
560
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
561
+ }, []);
562
+ const commit = () => {
563
+ var _a, _b;
564
+ if (committed.current) return;
565
+ const val = (_b = (_a = inputRef.current) == null ? void 0 : _a.value.trim()) != null ? _b : "";
566
+ if (!val) {
567
+ onCancel();
568
+ return;
569
+ }
570
+ committed.current = true;
571
+ onSubmit(val);
572
+ };
573
+ const cancel = () => {
574
+ if (committed.current) return;
575
+ committed.current = true;
576
+ onCancel();
577
+ };
578
+ return /* @__PURE__ */ jsxs3("div", { style: {
579
+ paddingLeft: level * 12 + 8,
580
+ display: "flex",
581
+ alignItems: "center",
582
+ gap: 6,
583
+ height: 28,
584
+ background: "rgba(59,130,246,0.08)",
585
+ borderLeft: "2px solid #3b82f6"
586
+ }, children: [
587
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 12, flexShrink: 0, color: "#60a5fa" }, children: kind === "folder" ? "\u25B6" : "\xB7" }),
588
+ /* @__PURE__ */ jsx4(
589
+ "input",
590
+ {
591
+ ref: inputRef,
592
+ defaultValue: "",
593
+ onKeyDown: (e) => {
594
+ e.stopPropagation();
595
+ if (e.key === "Enter") {
596
+ e.preventDefault();
597
+ commit();
598
+ }
599
+ if (e.key === "Escape") {
600
+ e.preventDefault();
601
+ cancel();
602
+ }
603
+ },
604
+ onBlur: cancel,
605
+ style: {
606
+ flex: 1,
607
+ background: "transparent",
608
+ border: "none",
609
+ outline: "none",
610
+ fontSize: 13,
611
+ color: "#d4d4d4",
612
+ padding: 0,
613
+ fontFamily: "inherit"
614
+ },
615
+ spellCheck: false,
616
+ autoComplete: "off"
617
+ }
618
+ )
619
+ ] });
620
+ }
621
+ function DraggableNode({
622
+ flatNode,
623
+ renderContent
624
+ }) {
625
+ const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id: flatNode.node.id });
626
+ return /* @__PURE__ */ jsx4("div", { ref: setNodeRef, style: { opacity: isDragging ? 0.35 : 1 }, children: renderContent({ dragHandleProps: __spreadValues(__spreadValues({}, attributes), listeners), isDragging }) });
627
+ }
628
+ function DroppableNode({
629
+ flatNode,
630
+ children
631
+ }) {
632
+ const { setNodeRef } = useDroppable({ id: flatNode.node.id });
633
+ return /* @__PURE__ */ jsx4("div", { ref: setNodeRef, children });
634
+ }
635
+ function RootDropZone({ children }) {
636
+ const { setNodeRef } = useDroppable({ id: ROOT_DROP_ID });
637
+ return /* @__PURE__ */ jsx4("div", { ref: setNodeRef, style: { minHeight: "100%", position: "relative" }, children });
638
+ }
639
+ function DefaultNode({
640
+ flatNode,
641
+ isSelected,
642
+ isActive,
643
+ isDragging,
644
+ isDragSession,
645
+ onClick,
646
+ dragHandleProps,
647
+ renderActions,
648
+ onOpen
649
+ }) {
650
+ const [hovered, setHovered] = useState3(false);
651
+ const { node, level } = flatNode;
652
+ return /* @__PURE__ */ jsxs3(
653
+ "div",
654
+ __spreadProps(__spreadValues({}, dragHandleProps), {
655
+ onClick,
656
+ onMouseEnter: () => setHovered(true),
657
+ onMouseLeave: () => setHovered(false),
658
+ style: {
659
+ paddingLeft: level * 12 + 8,
660
+ display: "flex",
661
+ alignItems: "center",
662
+ height: 28,
663
+ cursor: "pointer",
664
+ userSelect: "none",
665
+ backgroundColor: isSelected ? "rgba(59,130,246,0.1)" : isActive ? "rgba(255,255,255,0.05)" : !isDragSession && hovered ? "rgba(255,255,255,0.03)" : "transparent",
666
+ opacity: isDragging ? 0.35 : 1
667
+ },
668
+ children: [
669
+ /* @__PURE__ */ jsx4("span", { style: { marginRight: 6, fontSize: 12 }, children: node.kind === "folder" ? flatNode.isOpen ? "\u25BC" : "\u25B6" : "\xB7" }),
670
+ /* @__PURE__ */ jsx4("span", { style: {
671
+ flex: 1,
672
+ fontSize: 13,
673
+ overflow: "hidden",
674
+ textOverflow: "ellipsis",
675
+ whiteSpace: "nowrap"
676
+ }, children: node.name }),
677
+ renderActions == null ? void 0 : renderActions(node)
678
+ ]
679
+ })
680
+ );
681
+ }
682
+
683
+ // src/react/components/file-tree/file-tree-base.tsx
684
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
685
+ var DEFAULT_EMPTY_HEIGHT = 28;
686
+ function FileTreeBase({
687
+ nodes,
688
+ childIndex,
689
+ rootIds,
690
+ expandedIds,
691
+ selection,
692
+ activeNodeId,
693
+ renamingId,
694
+ onExpand,
695
+ onCollapse,
696
+ onSelect,
697
+ onToggle,
698
+ onRangeSelect,
699
+ onOpen,
700
+ onRename,
701
+ onDelete,
702
+ onMove,
703
+ onReorder,
704
+ onSetRenaming,
705
+ onCreate,
706
+ inlineCreate,
707
+ onCancelCreate,
708
+ sortable = false,
709
+ draggable = false,
710
+ virtualized = false,
711
+ virtualizer: virtualizerOverride,
712
+ itemHeight = 28,
713
+ renderNode,
714
+ renderActions,
715
+ renderEmpty,
716
+ children,
717
+ onKeyDown: customKeyDown,
718
+ className,
719
+ folderOverlay
720
+ }) {
721
+ var _a, _b, _c;
722
+ const containerRef = useRef3(null);
723
+ const hoverTimer = useRef3(null);
724
+ const [activeId, setActiveId] = useState4(null);
725
+ const [dropTarget, setDropTarget] = useState4(null);
726
+ const [scrollTop, setScrollTop] = useState4(0);
727
+ useEffect4(() => {
728
+ const el = containerRef.current;
729
+ if (!el) return;
730
+ const onScroll = () => setScrollTop(el.scrollTop);
731
+ el.addEventListener("scroll", onScroll, { passive: true });
732
+ return () => el.removeEventListener("scroll", onScroll);
733
+ }, []);
734
+ const flatNodes = flattenTree(rootIds, nodes, childIndex, expandedIds);
735
+ const orderedIds = flatNodes.map((f) => f.node.id);
736
+ const isDragSession = activeId !== null;
737
+ const sensors = useSensors2(
738
+ useSensor2(PointerSensor2, { activationConstraint: { distance: 6 } }),
739
+ useSensor2(KeyboardSensor2, { coordinateGetter: sortableKeyboardCoordinates2 })
740
+ );
741
+ const handleDragStart = useCallback((e) => {
742
+ setActiveId(String(e.active.id));
743
+ setDropTarget(null);
744
+ }, []);
745
+ const handleDragOver = useCallback((e) => {
746
+ if (!e.over) {
747
+ setDropTarget(null);
748
+ if (hoverTimer.current) clearTimeout(hoverTimer.current);
749
+ return;
750
+ }
751
+ const overId = String(e.over.id);
752
+ const draggedId = String(e.active.id);
753
+ const target = resolveDropTarget(overId, draggedId, nodes);
754
+ setDropTarget(target);
755
+ if ((target == null ? void 0 : target.folderId) && !target.blocked && !expandedIds.has(target.folderId)) {
756
+ if (hoverTimer.current) clearTimeout(hoverTimer.current);
757
+ hoverTimer.current = setTimeout(() => onExpand(target.folderId), 800);
758
+ } else {
759
+ if (hoverTimer.current) clearTimeout(hoverTimer.current);
760
+ }
761
+ }, [nodes, expandedIds, onExpand]);
762
+ const handleDragEnd = useCallback((e) => {
763
+ if (hoverTimer.current) clearTimeout(hoverTimer.current);
764
+ const { active, over } = e;
765
+ setActiveId(null);
766
+ setDropTarget(null);
767
+ const draggedId = String(active.id);
768
+ if (!over) {
769
+ onMove(selection.includes(draggedId) ? selection : [draggedId], null);
770
+ return;
771
+ }
772
+ const overId = String(over.id);
773
+ if (draggedId === overId) return;
774
+ const target = resolveDropTarget(overId, draggedId, nodes);
775
+ if (!target || target.blocked) return;
776
+ const draggedNode = nodes.get(draggedId);
777
+ if (draggedNode && draggedNode.parentId === target.folderId) return;
778
+ onMove(selection.includes(draggedId) ? selection : [draggedId], target.folderId);
779
+ }, [nodes, selection, onMove]);
780
+ const handleDragCancel = useCallback(() => {
781
+ if (hoverTimer.current) clearTimeout(hoverTimer.current);
782
+ setActiveId(null);
783
+ setDropTarget(null);
784
+ }, []);
785
+ const focusedIndex = useRef3(0);
786
+ const defaultKeyHandler = useCallback((e, node) => {
787
+ const idx = flatNodes.findIndex((f) => f.node.id === node.id);
788
+ const flat = flatNodes[idx];
789
+ switch (e.key) {
790
+ case "ArrowDown": {
791
+ e.preventDefault();
792
+ const next = flatNodes[idx + 1];
793
+ if (next) {
794
+ onSelect(next.node.id);
795
+ focusedIndex.current = idx + 1;
796
+ }
797
+ break;
798
+ }
799
+ case "ArrowUp": {
800
+ e.preventDefault();
801
+ const prev = flatNodes[idx - 1];
802
+ if (prev) {
803
+ onSelect(prev.node.id);
804
+ focusedIndex.current = idx - 1;
805
+ }
806
+ break;
807
+ }
808
+ case "ArrowRight": {
809
+ e.preventDefault();
810
+ if (node.kind === "folder") {
811
+ if (flat.isOpen) {
812
+ const first = flatNodes[idx + 1];
813
+ if (first) onSelect(first.node.id);
814
+ } else onExpand(node.id);
815
+ }
816
+ break;
817
+ }
818
+ case "ArrowLeft": {
819
+ e.preventDefault();
820
+ if (node.kind === "folder" && flat.isOpen) onCollapse(node.id);
821
+ else if (node.parentId) onSelect(node.parentId);
822
+ break;
823
+ }
824
+ case "Enter": {
825
+ e.preventDefault();
826
+ onOpen(node);
827
+ break;
828
+ }
829
+ case "F2": {
830
+ e.preventDefault();
831
+ onSetRenaming(node.id);
832
+ break;
833
+ }
834
+ case "Delete":
835
+ case "Backspace": {
836
+ e.preventDefault();
837
+ onDelete(selection.includes(node.id) ? selection : [node.id]);
838
+ break;
839
+ }
840
+ case "Escape": {
841
+ e.preventDefault();
842
+ onSetRenaming(null);
843
+ break;
844
+ }
845
+ }
846
+ }, [flatNodes, onSelect, onExpand, onCollapse, onOpen, onSetRenaming, onDelete, selection]);
847
+ const handleKeyDown = useCallback((e, node) => {
848
+ if (customKeyDown) customKeyDown(e, node, defaultKeyHandler);
849
+ else defaultKeyHandler(e, node);
850
+ }, [customKeyDown, defaultKeyHandler]);
851
+ const dropZoneData = useMemo(() => {
852
+ if (!dropTarget || !folderOverlay || dropTarget.folderId === null) return null;
853
+ const { folderId, blocked } = dropTarget;
854
+ const folderIndex = flatNodes.findIndex((f) => f.node.id === folderId);
855
+ if (folderIndex === -1) return null;
856
+ const { rowCount } = measureVisibleSubtree(folderIndex, flatNodes);
857
+ const targetFolder = nodes.get(folderId);
858
+ if (!targetFolder) return null;
859
+ return { folderIndex, rowCount, targetFolder, blocked };
860
+ }, [dropTarget, folderOverlay, flatNodes, nodes]);
861
+ const inlineInsertIndex = useMemo(() => {
862
+ if (!inlineCreate) return null;
863
+ const { parentId } = inlineCreate;
864
+ if (parentId === null) return 0;
865
+ const folderIdx = flatNodes.findIndex((f) => f.node.id === parentId);
866
+ if (folderIdx === -1) return flatNodes.length;
867
+ return folderIdx + 1;
868
+ }, [inlineCreate, flatNodes]);
869
+ const inlineLevel = useMemo(() => {
870
+ if (!(inlineCreate == null ? void 0 : inlineCreate.parentId)) return 0;
871
+ const fn = flatNodes.find((f) => f.node.id === inlineCreate.parentId);
872
+ return fn ? fn.level + 1 : 0;
873
+ }, [inlineCreate, flatNodes]);
874
+ const renderFlatNode = useCallback((flatNode) => {
875
+ const { node } = flatNode;
876
+ const isSelected = selection.includes(node.id);
877
+ const isActive = activeNodeId === node.id;
878
+ const isDragging = activeId === node.id;
879
+ const isOver = !!dropTarget && dropTarget.folderId === node.id && !dropTarget.blocked;
880
+ const isOverBlocked = !!dropTarget && dropTarget.folderId === node.id && !!dropTarget.blocked;
881
+ const isRenaming = renamingId === node.id;
882
+ const handleClick = (e) => {
883
+ var _a2;
884
+ if (e.ctrlKey || e.metaKey) onToggle(node.id);
885
+ else if (e.shiftKey) onRangeSelect(orderedIds, (_a2 = selection[selection.length - 1]) != null ? _a2 : node.id, node.id);
886
+ else {
887
+ onSelect(node.id);
888
+ if (node.kind === "folder") {
889
+ expandedIds.has(node.id) ? onCollapse(node.id) : onExpand(node.id);
890
+ }
891
+ }
892
+ };
893
+ const nodeProps = {
894
+ flatNode,
895
+ isSelected,
896
+ isActive,
897
+ isDragging,
898
+ isOver,
899
+ isOverBlocked,
900
+ isRenaming,
901
+ isDragSession,
902
+ setRenaming: (v) => onSetRenaming(v ? node.id : null),
903
+ dragHandleProps: {},
904
+ style: {},
905
+ onClick: handleClick
906
+ };
907
+ const content = /* @__PURE__ */ jsx5(
908
+ "div",
909
+ {
910
+ onKeyDown: isRenaming ? void 0 : (e) => handleKeyDown(e, node),
911
+ tabIndex: isRenaming ? -1 : 0,
912
+ children: renderNode ? renderNode(nodeProps) : /* @__PURE__ */ jsx5(DefaultNode, __spreadProps(__spreadValues({}, nodeProps), { renderActions, onOpen }))
913
+ }
914
+ );
915
+ if (!draggable) return /* @__PURE__ */ jsx5("div", { children: content }, node.id);
916
+ return /* @__PURE__ */ jsx5(DroppableNode, { flatNode, children: /* @__PURE__ */ jsx5(
917
+ DraggableNode,
918
+ {
919
+ flatNode,
920
+ renderContent: ({ dragHandleProps, isDragging: dndDragging }) => renderNode ? renderNode(__spreadProps(__spreadValues({}, nodeProps), { dragHandleProps, isDragging: dndDragging })) : /* @__PURE__ */ jsx5(DefaultNode, __spreadProps(__spreadValues({}, nodeProps), { dragHandleProps, isDragging: dndDragging, renderActions, onOpen }))
921
+ }
922
+ ) }, node.id);
923
+ }, [
924
+ selection,
925
+ activeNodeId,
926
+ activeId,
927
+ dropTarget,
928
+ renamingId,
929
+ expandedIds,
930
+ isDragSession,
931
+ onSelect,
932
+ onToggle,
933
+ onRangeSelect,
934
+ onExpand,
935
+ onCollapse,
936
+ onOpen,
937
+ onSetRenaming,
938
+ renderNode,
939
+ renderActions,
940
+ handleKeyDown,
941
+ draggable,
942
+ orderedIds
943
+ ]);
944
+ const tanstackVirtualizer = useVirtualizer({
945
+ count: flatNodes.length,
946
+ getScrollElement: () => containerRef.current,
947
+ estimateSize: () => itemHeight,
948
+ enabled: virtualized && !virtualizerOverride
949
+ });
950
+ const renderList = () => {
951
+ var _a2;
952
+ if (flatNodes.length === 0 && !inlineCreate) return (_a2 = renderEmpty == null ? void 0 : renderEmpty()) != null ? _a2 : null;
953
+ if (virtualizerOverride) {
954
+ const items = flatNodes.map((_, i) => ({
955
+ index: i,
956
+ start: i * virtualizerOverride.itemHeight,
957
+ size: virtualizerOverride.itemHeight
958
+ }));
959
+ return virtualizerOverride.renderItems(
960
+ items,
961
+ flatNodes.length * virtualizerOverride.itemHeight,
962
+ (index) => renderFlatNode(flatNodes[index])
963
+ );
964
+ }
965
+ if (virtualized) {
966
+ const virtualItems = tanstackVirtualizer.getVirtualItems();
967
+ return /* @__PURE__ */ jsx5("div", { style: { height: tanstackVirtualizer.getTotalSize(), position: "relative" }, children: virtualItems.map((vItem) => /* @__PURE__ */ jsx5(
968
+ "div",
969
+ {
970
+ style: {
971
+ position: "absolute",
972
+ top: 0,
973
+ width: "100%",
974
+ height: itemHeight,
975
+ transform: `translateY(${vItem.start}px)`
976
+ },
977
+ children: renderFlatNode(flatNodes[vItem.index])
978
+ },
979
+ vItem.key
980
+ )) });
981
+ }
982
+ const inlineRow = inlineCreate ? /* @__PURE__ */ jsx5(
983
+ InlineCreateRow,
984
+ {
985
+ kind: inlineCreate.kind,
986
+ level: inlineLevel,
987
+ onSubmit: (name) => onCreate(inlineCreate.kind, inlineCreate.parentId, name),
988
+ onCancel: onCancelCreate
989
+ },
990
+ "@@inline-create"
991
+ ) : null;
992
+ if (inlineRow === null) return flatNodes.map(renderFlatNode);
993
+ const rows = [];
994
+ flatNodes.forEach((fn, i) => {
995
+ if (inlineInsertIndex === i) rows.push(inlineRow);
996
+ rows.push(renderFlatNode(fn));
997
+ });
998
+ if (inlineInsertIndex !== null && inlineInsertIndex >= flatNodes.length) rows.push(inlineRow);
999
+ return rows;
1000
+ };
1001
+ if (children) {
1002
+ return /* @__PURE__ */ jsx5("div", { ref: containerRef, className, children: children({ flatNodes, renderNode: renderFlatNode }) });
1003
+ }
1004
+ const emptyStateHeight = (_a = folderOverlay == null ? void 0 : folderOverlay.emptyStateHeight) != null ? _a : DEFAULT_EMPTY_HEIGHT;
1005
+ const treeBody = /* @__PURE__ */ jsxs4(
1006
+ "div",
1007
+ {
1008
+ ref: containerRef,
1009
+ className,
1010
+ style: { overflow: "auto", outline: "none", position: "relative", height: "100%" },
1011
+ tabIndex: -1,
1012
+ children: [
1013
+ /* @__PURE__ */ jsx5(RootDropZone, { children: renderList() }),
1014
+ dropZoneData && folderOverlay && /* @__PURE__ */ jsx5(
1015
+ DropZoneOverlay,
1016
+ {
1017
+ scrollTop,
1018
+ folderIndex: dropZoneData.folderIndex,
1019
+ rowCount: dropZoneData.rowCount,
1020
+ itemHeight,
1021
+ emptyStateHeight,
1022
+ mode: folderOverlay.mode,
1023
+ isBlocked: dropZoneData.blocked,
1024
+ targetFolder: dropZoneData.targetFolder,
1025
+ renderOverlay: folderOverlay.renderOverlay
1026
+ }
1027
+ ),
1028
+ /* @__PURE__ */ jsx5(DragOverlay, { dropAnimation: null, children: activeId ? /* @__PURE__ */ jsxs4("div", { style: {
1029
+ padding: "4px 12px",
1030
+ background: "rgba(30,30,30,0.95)",
1031
+ border: "1px solid #3b82f6",
1032
+ borderRadius: 4,
1033
+ fontSize: 13,
1034
+ color: "#fff",
1035
+ display: "flex",
1036
+ alignItems: "center",
1037
+ gap: 8,
1038
+ boxShadow: "0 4px 16px rgba(0,0,0,0.4)",
1039
+ backdropFilter: "blur(8px)",
1040
+ minWidth: 120,
1041
+ pointerEvents: "none",
1042
+ userSelect: "none"
1043
+ }, children: [
1044
+ (_c = (_b = nodes.get(activeId)) == null ? void 0 : _b.name) != null ? _c : "",
1045
+ selection.length > 1 && /* @__PURE__ */ jsxs4("span", { style: { color: "#555", fontSize: 11 }, children: [
1046
+ "+",
1047
+ selection.length - 1,
1048
+ " more"
1049
+ ] })
1050
+ ] }) : null })
1051
+ ]
1052
+ }
1053
+ );
1054
+ if (!draggable) return treeBody;
1055
+ return /* @__PURE__ */ jsx5(
1056
+ DndContext2,
1057
+ {
1058
+ sensors,
1059
+ collisionDetection: pointerWithin,
1060
+ onDragStart: handleDragStart,
1061
+ onDragOver: handleDragOver,
1062
+ onDragEnd: handleDragEnd,
1063
+ onDragCancel: handleDragCancel,
1064
+ children: treeBody
1065
+ }
1066
+ );
1067
+ }
1068
+
1069
+ // src/react/components/file-tree/file-tree.tsx
1070
+ import { jsx as jsx6 } from "react/jsx-runtime";
1071
+ var EMPTY_TREE = () => ({
1072
+ nodes: /* @__PURE__ */ new Map(),
1073
+ childIndex: /* @__PURE__ */ new Map(),
1074
+ rootIds: []
1075
+ });
1076
+ function FileTree(_a) {
1077
+ var _b = _a, {
1078
+ workspaceId,
1079
+ inlineCreate: inlineCreateProp,
1080
+ onCancelCreate
1081
+ } = _b, rest = __objRest(_b, [
1082
+ "workspaceId",
1083
+ "inlineCreate",
1084
+ "onCancelCreate"
1085
+ ]);
1086
+ var _a2, _b2, _c;
1087
+ const { tree, fs, status } = useVfsEngine(workspaceId);
1088
+ const workspaceIds = useMemo2(
1089
+ () => workspaceId ? [workspaceId] : void 0,
1090
+ [workspaceId]
1091
+ );
1092
+ const tabs = useVfsTabs({ workspaceIds });
1093
+ const selection = useVfsSelection();
1094
+ const expanded = useVfsExpanded({ workspaceIds });
1095
+ const [treeState, setTreeState] = useState5(EMPTY_TREE);
1096
+ const [renamingId, setRenamingId] = useState5(null);
1097
+ useEffect5(() => {
1098
+ let cancelled = false;
1099
+ const sync = () => __async(null, null, function* () {
1100
+ const roots = yield tree.getChildren(null);
1101
+ if (cancelled) return;
1102
+ const newNodes = /* @__PURE__ */ new Map();
1103
+ const newIndex = /* @__PURE__ */ new Map();
1104
+ const visited = /* @__PURE__ */ new Set();
1105
+ const walk = (parentId) => __async(null, null, function* () {
1106
+ const children = yield tree.getChildren(parentId);
1107
+ if (cancelled) return;
1108
+ newIndex.set(parentId != null ? parentId : "@@root", children.map((c) => c.id));
1109
+ for (const child of children) {
1110
+ if (visited.has(child.id)) continue;
1111
+ visited.add(child.id);
1112
+ newNodes.set(child.id, child);
1113
+ if (child.kind === "folder") {
1114
+ yield walk(child.id);
1115
+ if (cancelled) return;
1116
+ }
1117
+ }
1118
+ });
1119
+ yield walk(null);
1120
+ if (cancelled) return;
1121
+ setTreeState({
1122
+ nodes: newNodes,
1123
+ childIndex: newIndex,
1124
+ rootIds: roots.map((r) => r.id)
1125
+ });
1126
+ });
1127
+ sync();
1128
+ return () => {
1129
+ cancelled = true;
1130
+ };
1131
+ }, [status.version]);
1132
+ const resolvedInlineCreate = useMemo2(() => {
1133
+ var _a3, _b3;
1134
+ if (!inlineCreateProp) return null;
1135
+ const parentId = resolveInlineCreateParent(
1136
+ selection.selection,
1137
+ (_b3 = (_a3 = tabs.activeTab) == null ? void 0 : _a3.nodeId) != null ? _b3 : null,
1138
+ treeState.nodes
1139
+ );
1140
+ if (parentId && !expanded.expandedIds.has(parentId)) {
1141
+ expanded.expand(parentId);
1142
+ }
1143
+ return { kind: inlineCreateProp.kind, parentId };
1144
+ }, [inlineCreateProp, selection.selection, (_a2 = tabs.activeTab) == null ? void 0 : _a2.nodeId, treeState.nodes, expanded]);
1145
+ const handleCreate = useCallback2((kind, parentId, name) => __async(null, null, function* () {
1146
+ if (kind === "file") {
1147
+ yield fs.createFile(parentId, name);
1148
+ } else {
1149
+ yield fs.createFolder(parentId, name);
1150
+ if (parentId) expanded.expand(parentId);
1151
+ }
1152
+ onCancelCreate == null ? void 0 : onCancelCreate();
1153
+ }), [fs, expanded, onCancelCreate]);
1154
+ const handleMove = useCallback2((ids, targetId) => __async(null, null, function* () {
1155
+ yield fs.move(ids, targetId);
1156
+ }), [fs]);
1157
+ return /* @__PURE__ */ jsx6(
1158
+ FileTreeBase,
1159
+ __spreadValues({
1160
+ nodes: treeState.nodes,
1161
+ childIndex: treeState.childIndex,
1162
+ rootIds: treeState.rootIds,
1163
+ expandedIds: expanded.expandedIds,
1164
+ selection: selection.selection,
1165
+ activeNodeId: (_c = (_b2 = tabs.activeTab) == null ? void 0 : _b2.nodeId) != null ? _c : null,
1166
+ renamingId,
1167
+ onExpand: expanded.expand,
1168
+ onCollapse: expanded.collapse,
1169
+ onSelect: selection.select,
1170
+ onToggle: selection.toggle,
1171
+ onRangeSelect: selection.selectRange,
1172
+ onOpen: (node) => {
1173
+ if (node.kind === "file") tabs.open(node.id, workspaceId != null ? workspaceId : "");
1174
+ else expanded.toggle(node.id);
1175
+ },
1176
+ onRename: (id, newName) => fs.rename(id, newName),
1177
+ onDelete: (ids) => fs.delete(ids),
1178
+ onMove: handleMove,
1179
+ onReorder: (parentId, orderedIds) => fs.reorder(parentId, orderedIds),
1180
+ onSetRenaming: setRenamingId,
1181
+ onCreate: handleCreate,
1182
+ inlineCreate: resolvedInlineCreate,
1183
+ onCancelCreate: onCancelCreate != null ? onCancelCreate : (() => {
1184
+ })
1185
+ }, rest)
1186
+ );
1187
+ }
1188
+ export {
1189
+ FileRenderer,
1190
+ FileRendererBase,
1191
+ FileTree,
1192
+ FileTreeBase,
1193
+ InlineInput,
1194
+ TabList,
1195
+ TabListBase
1196
+ };
1197
+ //# sourceMappingURL=index.mjs.map