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 strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
+
3
+
4
+
5
+
6
+
7
+ var _chunkWZVVI3HXjs = require('../chunk-WZVVI3HX.js');
8
+ require('../chunk-U2CKTXY7.js');
9
+
10
+
11
+
12
+
13
+
14
+ var _chunk2FEJBM4Njs = require('../chunk-2FEJBM4N.js');
15
+
16
+ // src/react/components/inline-input.tsx
17
+ var _react = require('react');
18
+ var _jsxruntime = require('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 = _react.useRef.call(void 0, null);
30
+ const [value, setValue] = _react.useState.call(void 0, initialValue);
31
+ const [error, setError] = _react.useState.call(void 0, null);
32
+ const committed = _react.useRef.call(void 0, false);
33
+ _react.useEffect.call(void 0, () => {
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__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { display: "flex", alignItems: "center", gap: 4, width: "100%" }, children: [
76
+ icon && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { flexShrink: 0, display: "flex", alignItems: "center" }, children: icon }),
77
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { flex: 1, position: "relative" }, children: [
78
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0, "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
+
112
+
113
+ function FileRendererBase({
114
+ node,
115
+ content: externalContent,
116
+ children,
117
+ fallback,
118
+ onLoad,
119
+ onError
120
+ }) {
121
+ const [content, setContent] = _react.useState.call(void 0, externalContent != null ? externalContent : null);
122
+ const [loading, setLoading] = _react.useState.call(void 0, false);
123
+ const [error, setError] = _react.useState.call(void 0, null);
124
+ _react.useEffect.call(void 0, () => {
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__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: fallback != null ? fallback : null });
138
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.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 } = _chunkWZVVI3HXjs.useVfsEngine.call(void 0, workspaceId);
149
+ const [activeNode, setActiveNode] = _react.useState.call(void 0, null);
150
+ const [content, setContent] = _react.useState.call(void 0, null);
151
+ const [loading, setLoading] = _react.useState.call(void 0, false);
152
+ const [error, setError] = _react.useState.call(void 0, null);
153
+ _react.useEffect.call(void 0, () => {
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 = () => _chunk2FEJBM4Njs.__async.call(void 0, 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__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: fallback != null ? fallback : null });
195
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: children({ node: activeNode, content, loading, error }) });
196
+ }
197
+
198
+ // src/react/components/tab-list.tsx
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+ var _core = require('@dnd-kit/core');
207
+
208
+
209
+
210
+
211
+
212
+ var _sortable = require('@dnd-kit/sortable');
213
+ var _utilities = require('@dnd-kit/utilities');
214
+
215
+ function DefaultTab({
216
+ tab,
217
+ isActive,
218
+ onSetActive,
219
+ onClose,
220
+ dragHandleProps
221
+ }) {
222
+ const handles = dragHandleProps(tab.id);
223
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
224
+ "div",
225
+ _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, 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__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { fontSize: 13 }, children: [
239
+ tab.isDirty ? `\u25CF ${tab.title}` : tab.title,
240
+ tab.isLocked ? " \u{1F512}" : ""
241
+ ] }),
242
+ !tab.isLocked && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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
+ } = _sortable.useSortable.call(void 0, { id: tab.id });
273
+ const style = {
274
+ transform: _utilities.CSS.Transform.toString(transform),
275
+ transition,
276
+ opacity: isDragging ? 0.4 : 1,
277
+ flexShrink: 0
278
+ };
279
+ const mergedDragHandleProps = (tabId) => _chunk2FEJBM4Njs.__spreadValues.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, dragHandleProps(tabId)), attributes), listeners);
280
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setNodeRef, style, children: renderTab ? null : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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 = _core.useSensors.call(void 0,
305
+ _core.useSensor.call(void 0, _core.PointerSensor, { activationConstraint: { distance: 5 } }),
306
+ _core.useSensor.call(void 0, _core.KeyboardSensor, { coordinateGetter: _sortable.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__ */ _jsxruntime.jsx.call(void 0,
327
+ "div",
328
+ {
329
+ className,
330
+ style: { display: "flex", overflow: "hidden" },
331
+ children: children ? children(renderProps) : tabs.map((tab) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0,
346
+ _core.DndContext,
347
+ {
348
+ sensors,
349
+ collisionDetection: _core.closestCenter,
350
+ onDragEnd: handleDragEnd,
351
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
352
+ _sortable.SortableContext,
353
+ {
354
+ items: tabs.map((t) => t.id),
355
+ strategy: _sortable.horizontalListSortingStrategy,
356
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
357
+ "div",
358
+ {
359
+ className,
360
+ style: { display: "flex", overflow: "hidden" },
361
+ children: children ? tabs.map((tab) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0,
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 = _chunkWZVVI3HXjs.useVfsTabs.call(void 0, { workspaceIds });
396
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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(_chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, props), {
409
+ dragHandleProps: props.dragHandleProps
410
+ })) : void 0
411
+ }
412
+ );
413
+ }
414
+
415
+ // src/react/components/file-tree/file-tree.tsx
416
+
417
+
418
+ // src/react/components/file-tree/file-tree-base.tsx
419
+
420
+
421
+
422
+
423
+
424
+
425
+
426
+
427
+
428
+
429
+
430
+
431
+
432
+
433
+
434
+
435
+
436
+ var _reactvirtual = require('@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
+
498
+
499
+
500
+
501
+
502
+
503
+ function DefaultFolderOverlay({
504
+ isBlocked,
505
+ isEmpty
506
+ }) {
507
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0, 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__ */ _jsxruntime.jsx.call(void 0, "div", { style: _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, baseStyle), { top: headerTop, height: headerHeight }), children: content });
552
+ if (mode === "body") return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, baseStyle), { top: headerTop + headerHeight, height: bodyHeight }), children: content });
553
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, baseStyle), { top: headerTop, height: headerHeight + bodyHeight }), children: content });
554
+ }
555
+ function InlineCreateRow({ kind, level, onSubmit, onCancel }) {
556
+ const inputRef = _react.useRef.call(void 0, null);
557
+ const committed = _react.useRef.call(void 0, false);
558
+ _react.useEffect.call(void 0, () => {
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__ */ _jsxruntime.jsxs.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0, "span", { style: { fontSize: 12, flexShrink: 0, color: "#60a5fa" }, children: kind === "folder" ? "\u25B6" : "\xB7" }),
588
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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 } = _core.useDraggable.call(void 0, { id: flatNode.node.id });
626
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setNodeRef, style: { opacity: isDragging ? 0.35 : 1 }, children: renderContent({ dragHandleProps: _chunk2FEJBM4Njs.__spreadValues.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, attributes), listeners), isDragging }) });
627
+ }
628
+ function DroppableNode({
629
+ flatNode,
630
+ children
631
+ }) {
632
+ const { setNodeRef } = _core.useDroppable.call(void 0, { id: flatNode.node.id });
633
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setNodeRef, children });
634
+ }
635
+ function RootDropZone({ children }) {
636
+ const { setNodeRef } = _core.useDroppable.call(void 0, { id: ROOT_DROP_ID });
637
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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] = _react.useState.call(void 0, false);
651
+ const { node, level } = flatNode;
652
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
653
+ "div",
654
+ _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, 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__ */ _jsxruntime.jsx.call(void 0, "span", { style: { marginRight: 6, fontSize: 12 }, children: node.kind === "folder" ? flatNode.isOpen ? "\u25BC" : "\u25B6" : "\xB7" }),
670
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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
+
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 = _react.useRef.call(void 0, null);
723
+ const hoverTimer = _react.useRef.call(void 0, null);
724
+ const [activeId, setActiveId] = _react.useState.call(void 0, null);
725
+ const [dropTarget, setDropTarget] = _react.useState.call(void 0, null);
726
+ const [scrollTop, setScrollTop] = _react.useState.call(void 0, 0);
727
+ _react.useEffect.call(void 0, () => {
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 = _core.useSensors.call(void 0,
738
+ _core.useSensor.call(void 0, _core.PointerSensor, { activationConstraint: { distance: 6 } }),
739
+ _core.useSensor.call(void 0, _core.KeyboardSensor, { coordinateGetter: _sortable.sortableKeyboardCoordinates })
740
+ );
741
+ const handleDragStart = _react.useCallback.call(void 0, (e) => {
742
+ setActiveId(String(e.active.id));
743
+ setDropTarget(null);
744
+ }, []);
745
+ const handleDragOver = _react.useCallback.call(void 0, (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 = _react.useCallback.call(void 0, (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 = _react.useCallback.call(void 0, () => {
781
+ if (hoverTimer.current) clearTimeout(hoverTimer.current);
782
+ setActiveId(null);
783
+ setDropTarget(null);
784
+ }, []);
785
+ const focusedIndex = _react.useRef.call(void 0, 0);
786
+ const defaultKeyHandler = _react.useCallback.call(void 0, (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 = _react.useCallback.call(void 0, (e, node) => {
848
+ if (customKeyDown) customKeyDown(e, node, defaultKeyHandler);
849
+ else defaultKeyHandler(e, node);
850
+ }, [customKeyDown, defaultKeyHandler]);
851
+ const dropZoneData = _react.useMemo.call(void 0, () => {
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 = _react.useMemo.call(void 0, () => {
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 = _react.useMemo.call(void 0, () => {
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 = _react.useCallback.call(void 0, (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__ */ _jsxruntime.jsx.call(void 0,
908
+ "div",
909
+ {
910
+ onKeyDown: isRenaming ? void 0 : (e) => handleKeyDown(e, node),
911
+ tabIndex: isRenaming ? -1 : 0,
912
+ children: renderNode ? renderNode(nodeProps) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DefaultNode, _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, nodeProps), { renderActions, onOpen }))
913
+ }
914
+ );
915
+ if (!draggable) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: content }, node.id);
916
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DroppableNode, { flatNode, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
917
+ DraggableNode,
918
+ {
919
+ flatNode,
920
+ renderContent: ({ dragHandleProps, isDragging: dndDragging }) => renderNode ? renderNode(_chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, nodeProps), { dragHandleProps, isDragging: dndDragging })) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DefaultNode, _chunk2FEJBM4Njs.__spreadProps.call(void 0, _chunk2FEJBM4Njs.__spreadValues.call(void 0, {}, 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 = _reactvirtual.useVirtualizer.call(void 0, {
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__ */ _jsxruntime.jsx.call(void 0, "div", { style: { height: tanstackVirtualizer.getTotalSize(), position: "relative" }, children: virtualItems.map((vItem) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsxs.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0, RootDropZone, { children: renderList() }),
1014
+ dropZoneData && folderOverlay && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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__ */ _jsxruntime.jsx.call(void 0, _core.DragOverlay, { dropAnimation: null, children: activeId ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "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__ */ _jsxruntime.jsxs.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0,
1056
+ _core.DndContext,
1057
+ {
1058
+ sensors,
1059
+ collisionDetection: _core.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
+
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 = _chunk2FEJBM4Njs.__objRest.call(void 0, _b, [
1082
+ "workspaceId",
1083
+ "inlineCreate",
1084
+ "onCancelCreate"
1085
+ ]);
1086
+ var _a2, _b2, _c;
1087
+ const { tree, fs, status } = _chunkWZVVI3HXjs.useVfsEngine.call(void 0, workspaceId);
1088
+ const workspaceIds = _react.useMemo.call(void 0,
1089
+ () => workspaceId ? [workspaceId] : void 0,
1090
+ [workspaceId]
1091
+ );
1092
+ const tabs = _chunkWZVVI3HXjs.useVfsTabs.call(void 0, { workspaceIds });
1093
+ const selection = _chunkWZVVI3HXjs.useVfsSelection.call(void 0, );
1094
+ const expanded = _chunkWZVVI3HXjs.useVfsExpanded.call(void 0, { workspaceIds });
1095
+ const [treeState, setTreeState] = _react.useState.call(void 0, EMPTY_TREE);
1096
+ const [renamingId, setRenamingId] = _react.useState.call(void 0, null);
1097
+ _react.useEffect.call(void 0, () => {
1098
+ let cancelled = false;
1099
+ const sync = () => _chunk2FEJBM4Njs.__async.call(void 0, 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) => _chunk2FEJBM4Njs.__async.call(void 0, 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 = _react.useMemo.call(void 0, () => {
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 = _react.useCallback.call(void 0, (kind, parentId, name) => _chunk2FEJBM4Njs.__async.call(void 0, 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 = _react.useCallback.call(void 0, (ids, targetId) => _chunk2FEJBM4Njs.__async.call(void 0, null, null, function* () {
1155
+ yield fs.move(ids, targetId);
1156
+ }), [fs]);
1157
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1158
+ FileTreeBase,
1159
+ _chunk2FEJBM4Njs.__spreadValues.call(void 0, {
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
+
1189
+
1190
+
1191
+
1192
+
1193
+
1194
+
1195
+
1196
+ exports.FileRenderer = FileRenderer; exports.FileRendererBase = FileRendererBase; exports.FileTree = FileTree; exports.FileTreeBase = FileTreeBase; exports.InlineInput = InlineInput; exports.TabList = TabList; exports.TabListBase = TabListBase;
1197
+ //# sourceMappingURL=index.js.map