cursedbelt 5.34.0 → 5.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/file-tree/FileTree.d.ts +27 -1
- package/dist/react/file-tree/FileTree.d.ts.map +1 -1
- package/dist/react/file-tree/FileTree.js +183 -9
- package/dist/react/file-tree/FileTree.js.map +1 -1
- package/dist/react/file-tree/FolderViewMenus.d.ts +88 -0
- package/dist/react/file-tree/FolderViewMenus.d.ts.map +1 -0
- package/dist/react/file-tree/FolderViewMenus.js +121 -0
- package/dist/react/file-tree/FolderViewMenus.js.map +1 -0
- package/dist/react/file-tree/FolderViewPanels.d.ts +78 -0
- package/dist/react/file-tree/FolderViewPanels.d.ts.map +1 -0
- package/dist/react/file-tree/FolderViewPanels.js +155 -0
- package/dist/react/file-tree/FolderViewPanels.js.map +1 -0
- package/dist/react/file-tree/fileTree.css +146 -0
- package/dist/react/file-tree/folderView.d.ts +117 -0
- package/dist/react/file-tree/folderView.d.ts.map +1 -0
- package/dist/react/file-tree/folderView.js +230 -0
- package/dist/react/file-tree/folderView.js.map +1 -0
- package/dist/react/file-tree/folderViewPanels.css +217 -0
- package/dist/react/file-tree/index.d.ts +2 -0
- package/dist/react/file-tree/index.d.ts.map +1 -1
- package/dist/react/file-tree/index.js +9 -0
- package/dist/react/file-tree/index.js.map +1 -1
- package/dist/react/file-tree/useFolderView.d.ts +56 -0
- package/dist/react/file-tree/useFolderView.d.ts.map +1 -0
- package/dist/react/file-tree/useFolderView.js +79 -0
- package/dist/react/file-tree/useFolderView.js.map +1 -0
- package/dist/react/filter-rail/FilterRail.d.ts +7 -0
- package/dist/react/filter-rail/FilterRail.d.ts.map +1 -1
- package/dist/react/filter-rail/FilterRail.js +8 -1
- package/dist/react/filter-rail/FilterRail.js.map +1 -1
- package/dist/react/filter-rail/RailSection.d.ts +7 -1
- package/dist/react/filter-rail/RailSection.d.ts.map +1 -1
- package/dist/react/filter-rail/RailSection.js +5 -3
- package/dist/react/filter-rail/RailSection.js.map +1 -1
- package/dist/react/filter-rail/headerContextMenu.d.ts +8 -0
- package/dist/react/filter-rail/headerContextMenu.d.ts.map +1 -0
- package/dist/react/filter-rail/headerContextMenu.js +31 -0
- package/dist/react/filter-rail/headerContextMenu.js.map +1 -0
- package/dist/react/media/denseGallery.css +46 -0
- package/dist/react/media-gallery/rememberedPreference.d.ts +10 -1
- package/dist/react/media-gallery/rememberedPreference.d.ts.map +1 -1
- package/dist/react/media-gallery/rememberedPreference.js +12 -3
- package/dist/react/media-gallery/rememberedPreference.js.map +1 -1
- package/package.json +1 -1
- package/scripts/guardrails-baseline.json +1 -1
- package/src/react/file-tree/FileTree.tsx +323 -4
- package/src/react/file-tree/FolderViewMenus.tsx +242 -0
- package/src/react/file-tree/FolderViewPanels.tsx +402 -0
- package/src/react/file-tree/fileTree.css +146 -0
- package/src/react/file-tree/folderView.spec.ts +174 -0
- package/src/react/file-tree/folderView.ts +316 -0
- package/src/react/file-tree/folderViewPanels.css +217 -0
- package/src/react/file-tree/folderViewTree.spec.tsx +252 -0
- package/src/react/file-tree/index.ts +14 -0
- package/src/react/file-tree/useFolderView.ts +152 -0
- package/src/react/filter-rail/FilterRail.tsx +35 -6
- package/src/react/filter-rail/RailSection.tsx +10 -2
- package/src/react/filter-rail/headerContextMenu.spec.tsx +62 -0
- package/src/react/filter-rail/headerContextMenu.ts +37 -0
- package/src/react/media/denseGallery.css +46 -0
- package/src/react/media-gallery/rememberedPreference.ts +10 -2
|
@@ -161,7 +161,11 @@
|
|
|
161
161
|
*/
|
|
162
162
|
import type { DragEvent as ReactDragEvent, JSX, ReactNode } from 'react';
|
|
163
163
|
import { type AccessMarkCopy, type FileTreeDrop, type FileTreeNode } from 'cursedbelt-core/file-tree/file-tree-model';
|
|
164
|
+
import { type FileTreeMenuItem } from './FolderViewMenus.js';
|
|
165
|
+
import type { FolderView } from './useFolderView.js';
|
|
164
166
|
import './fileTree.css';
|
|
167
|
+
/** Fetch the right-click panels now — for a spec, which must not race the chunk. */
|
|
168
|
+
export declare const preloadFileTreePanels: () => Promise<void>;
|
|
165
169
|
export interface FileTreeProps {
|
|
166
170
|
nodes: readonly FileTreeNode[];
|
|
167
171
|
/** The row drawn as selected — usually "what the main pane is showing". */
|
|
@@ -467,6 +471,28 @@ export interface FileTreeProps {
|
|
|
467
471
|
x: number;
|
|
468
472
|
y: number;
|
|
469
473
|
}) => void;
|
|
474
|
+
/**
|
|
475
|
+
* The row's menu on **right-click** (and ⌃-click, and Shift+F10 when {@link onRowMenu} is not
|
|
476
|
+
* wired) — drawn by the tree at the pointer, VS Code's and Finder's gesture.
|
|
477
|
+
*
|
|
478
|
+
* Owner, 2026-09-30: *"add an option to the right click menu to hide a folder"*. Hand it the
|
|
479
|
+
* SAME list your ⋯ menu draws (the shape is `DropdownMenu`'s), so the two can never offer
|
|
480
|
+
* different things; {@link folderView}'s "Hide folder" and "Tags…" are appended to it on a
|
|
481
|
+
* folder. Omit both and a right-click is the browser's, as it always was.
|
|
482
|
+
*/
|
|
483
|
+
rowMenu?: (node: FileTreeNode) => readonly FileTreeMenuItem[];
|
|
484
|
+
/**
|
|
485
|
+
* Items for the right-click on the BLANK space under the rows — "New folder", say. Drawn above
|
|
486
|
+
* {@link folderView}'s own view items in the same menu.
|
|
487
|
+
*/
|
|
488
|
+
backgroundMenu?: () => readonly FileTreeMenuItem[];
|
|
489
|
+
/**
|
|
490
|
+
* Hidden folders and folder tags — `useFolderView({ key })`. Wiring it is what puts "Hide
|
|
491
|
+
* folder" and "Tags…" on a folder's right-click, "Show hidden folders" and "Filter by tag" on
|
|
492
|
+
* the blank space's, ⇧⌘. on the keyboard, the tag dots on tagged rows and the strip that says
|
|
493
|
+
* when this device is narrowing the tree. See `folderView.ts` for the rules.
|
|
494
|
+
*/
|
|
495
|
+
folderView?: FolderView | null;
|
|
470
496
|
/** Trailing controls for a row — the tool shelf. Quiet at rest, never invisible. */
|
|
471
497
|
renderTools?: (node: FileTreeNode) => ReactNode;
|
|
472
498
|
/** Leading glyph. Defaults to a folder/file mark. */
|
|
@@ -548,5 +574,5 @@ export interface FileTreeProps {
|
|
|
548
574
|
*/
|
|
549
575
|
scroll?: 'own' | 'host';
|
|
550
576
|
}
|
|
551
|
-
export declare function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelectionChange, onOpen, collapsed: collapsedProp, onCollapsedChange, expandOnReveal, onRevealExpand, pinnedIds, onPinnedChange, pinnedLabel, onMove, onMoveMany, onDropOutside, describeDropOutside, allowReorder, lockedReason, canDrop, takesDrop, unavailableReason, renamingId, onRenameStart, onRename, onRenameCancel, onDelete, onDeleteMany, onCopy, canCopy, draft, onDraftCommit, onDraftCancel, draftPlaceholder, onWrapStart, canWrap, onRowMenu, renderTools, renderIcon, thumbnailTransform, renderAccessory, onDropExternal, acceptsExternalDrag, accessCopy, nameTooltips, markPath, filter, empty, ariaLabel, className, scroll, }: FileTreeProps): JSX.Element;
|
|
577
|
+
export declare function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelectionChange, onOpen, collapsed: collapsedProp, onCollapsedChange, expandOnReveal, onRevealExpand, pinnedIds, onPinnedChange, pinnedLabel, onMove, onMoveMany, onDropOutside, describeDropOutside, allowReorder, lockedReason, canDrop, takesDrop, unavailableReason, renamingId, onRenameStart, onRename, onRenameCancel, onDelete, onDeleteMany, onCopy, canCopy, draft, onDraftCommit, onDraftCancel, draftPlaceholder, onWrapStart, canWrap, onRowMenu, rowMenu, backgroundMenu, folderView, renderTools, renderIcon, thumbnailTransform, renderAccessory, onDropExternal, acceptsExternalDrag, accessCopy, nameTooltips, markPath, filter, empty, ariaLabel, className, scroll, }: FileTreeProps): JSX.Element;
|
|
552
578
|
//# sourceMappingURL=FileTree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileTree.d.ts","sourceRoot":"","sources":["../../../src/react/file-tree/FileTree.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgKG;AACH,OAAO,KAAK,EACV,SAAS,IAAI,cAAc,EAC3B,GAAG,EAEH,SAAS,EACV,MAAM,OAAO,CAAC;AAEf,OAAO,EACL,KAAK,cAAc,EAKnB,KAAK,YAAY,EACjB,KAAK,YAAY,EAOlB,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"FileTree.d.ts","sourceRoot":"","sources":["../../../src/react/file-tree/FileTree.tsx"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,19 @@ import { Input } from '../components/Input.js';
|
|
|
6
6
|
import { Tooltip } from '../components/Tooltip.js';
|
|
7
7
|
import { draggedIdsOf, nodesByIds, planWrap, refuseCopy, refuseWrap, resolveMultiDrop, selectionRange, toggleSelected, topmostSelected, } from './fileTreeSelection.js';
|
|
8
8
|
import { useInView } from '../media/previewGate.js';
|
|
9
|
+
import { lazyPart } from '../components/DataTable/lazyPart.js';
|
|
10
|
+
import { applyFolderView, tagFilterActive } from './folderView.js';
|
|
11
|
+
import { FolderViewStrip, folderTargets, folderViewMenuItems, RowTagDots, withFolderItems, } from './FolderViewMenus.js';
|
|
9
12
|
import './fileTree.css';
|
|
13
|
+
/**
|
|
14
|
+
* The right-click panels — row menu, view menu, tag editor — fetched on demand. They reach
|
|
15
|
+
* Radix's Popover and the belt's ScrollArea, which a tree nobody right-clicks never needs, so
|
|
16
|
+
* they stay out of an app's first chunk; `preload` at idle makes the first right-click draw at
|
|
17
|
+
* once anyway. See `FolderViewPanels.tsx`.
|
|
18
|
+
*/
|
|
19
|
+
const TreePanel = lazyPart(() => import('./FolderViewPanels.js').then((m) => m.TreePanel));
|
|
20
|
+
/** Fetch the right-click panels now — for a spec, which must not race the chunk. */
|
|
21
|
+
export const preloadFileTreePanels = () => TreePanel.preload();
|
|
10
22
|
/** How far a press travels before it stops being a click and becomes a drag. */
|
|
11
23
|
const DRAG_THRESHOLD = 4;
|
|
12
24
|
/** How near the top or bottom of the list the pointer scrolls it. */
|
|
@@ -96,7 +108,7 @@ function RowGlyph({ node, open, renderIcon, transform, }) {
|
|
|
96
108
|
return icon;
|
|
97
109
|
return (_jsx("img", { ref: ref, className: 'cbft-thumb', src: seen || inView ? src : undefined, alt: '', "aria-hidden": 'true', loading: 'lazy', decoding: 'async', draggable: false, onError: () => setFailed(src), ...(transform ? { style: { transform } } : {}) }, src));
|
|
98
110
|
}
|
|
99
|
-
export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelectionChange, onOpen, collapsed: collapsedProp, onCollapsedChange, expandOnReveal = false, onRevealExpand, pinnedIds, onPinnedChange, pinnedLabel = 'Pinned', onMove, onMoveMany, onDropOutside, describeDropOutside, allowReorder = false, lockedReason, canDrop, takesDrop, unavailableReason, renamingId, onRenameStart, onRename, onRenameCancel, onDelete, onDeleteMany, onCopy, canCopy, draft, onDraftCommit, onDraftCancel, draftPlaceholder, onWrapStart, canWrap, onRowMenu, renderTools, renderIcon, thumbnailTransform, renderAccessory, onDropExternal, acceptsExternalDrag, accessCopy, nameTooltips = true, markPath = true, filter, empty = 'Nothing here yet.', ariaLabel = 'Files', className, scroll = 'own', }) {
|
|
111
|
+
export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelectionChange, onOpen, collapsed: collapsedProp, onCollapsedChange, expandOnReveal = false, onRevealExpand, pinnedIds, onPinnedChange, pinnedLabel = 'Pinned', onMove, onMoveMany, onDropOutside, describeDropOutside, allowReorder = false, lockedReason, canDrop, takesDrop, unavailableReason, renamingId, onRenameStart, onRename, onRenameCancel, onDelete, onDeleteMany, onCopy, canCopy, draft, onDraftCommit, onDraftCancel, draftPlaceholder, onWrapStart, canWrap, onRowMenu, rowMenu, backgroundMenu, folderView = null, renderTools, renderIcon, thumbnailTransform, renderAccessory, onDropExternal, acceptsExternalDrag, accessCopy, nameTooltips = true, markPath = true, filter, empty = 'Nothing here yet.', ariaLabel = 'Files', className, scroll = 'own', }) {
|
|
100
112
|
const scrollRef = useRef(null);
|
|
101
113
|
/** The whole tree, pinned section included — "outside" for `onDropOutside` is outside this. */
|
|
102
114
|
const rootRef = useRef(null);
|
|
@@ -247,7 +259,19 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
247
259
|
if (!clipboard)
|
|
248
260
|
mirrored.current = null;
|
|
249
261
|
}, [clipboard]);
|
|
250
|
-
|
|
262
|
+
/*
|
|
263
|
+
* Hidden folders and the tag filter come off FIRST, before the search: a search that found
|
|
264
|
+
* things inside a hidden folder would be the folder un-hiding itself. See `folderView.ts`.
|
|
265
|
+
*/
|
|
266
|
+
const viewed = useMemo(() => (folderView ? applyFolderView(nodes, folderView.marks, folderView.local) : null), [nodes, folderView]);
|
|
267
|
+
const viewedNodes = viewed?.nodes ?? nodes;
|
|
268
|
+
const shown = useMemo(() => (filter ? filterFileTree(viewedNodes, filter) : viewedNodes), [viewedNodes, filter]);
|
|
269
|
+
/**
|
|
270
|
+
* What the pinned section is built from — the tree WITHOUT the folder view. A pin is the
|
|
271
|
+
* person saying *"keep it there until I unpin it"*, and hiding the folder it lives in, or
|
|
272
|
+
* narrowing this device to another tag, is not unpinning it.
|
|
273
|
+
*/
|
|
274
|
+
const pinSource = useMemo(() => (viewed ? (filter ? filterFileTree(nodes, filter) : nodes) : shown), [viewed, filter, nodes, shown]);
|
|
251
275
|
/*
|
|
252
276
|
* A search shows everything it kept — a match hidden inside a collapsed folder is a match
|
|
253
277
|
* the person cannot see, which reads as "not found".
|
|
@@ -273,7 +297,7 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
273
297
|
const pinnedRows = useMemo(() => {
|
|
274
298
|
if (pinned.length === 0)
|
|
275
299
|
return [];
|
|
276
|
-
const all = new Map(flattenFileTree(
|
|
300
|
+
const all = new Map(flattenFileTree(pinSource, []).map((row) => [row.node.id, row]));
|
|
277
301
|
const out = [];
|
|
278
302
|
for (const id of pinned) {
|
|
279
303
|
const real = all.get(id);
|
|
@@ -281,7 +305,7 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
281
305
|
out.push({ ...real, depth: 0, expandable: false, expanded: false });
|
|
282
306
|
}
|
|
283
307
|
return out;
|
|
284
|
-
}, [pinned,
|
|
308
|
+
}, [pinned, pinSource]);
|
|
285
309
|
/**
|
|
286
310
|
* The whole selection, singular or plural — `[selectedId]` for a consumer that never
|
|
287
311
|
* passed {@link FileTreeProps.selectedIds}, which is every consumer that existed before
|
|
@@ -863,6 +887,71 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
863
887
|
if (id)
|
|
864
888
|
rowEl(id, pinnedCopy)?.focus();
|
|
865
889
|
}, [rowEl]);
|
|
890
|
+
// ── Right-click menus ─────────────────────────────────────────────────────────────────
|
|
891
|
+
/**
|
|
892
|
+
* The row menu open at the pointer, or the view menu when the tree owns it alone (no
|
|
893
|
+
* {@link FileTreeProps.folderView}, whose hook holds the view menu so the APP's header can
|
|
894
|
+
* open it too).
|
|
895
|
+
*/
|
|
896
|
+
const [ctxMenu, setCtxMenu] = useState(null);
|
|
897
|
+
/** Whether a row has a right-click menu at all — otherwise the browser's stays. */
|
|
898
|
+
const hasRowMenu = useCallback((node) => Boolean(rowMenu) || (folderView !== null && node.kind === 'folder'), [rowMenu, folderView]);
|
|
899
|
+
const openRowMenu = useCallback((node, pinnedCopy, at) => {
|
|
900
|
+
setFocused({ id: node.id, pinned: pinnedCopy });
|
|
901
|
+
setCtxMenu({ kind: 'row', node, pinned: pinnedCopy, at });
|
|
902
|
+
}, []);
|
|
903
|
+
const openViewMenu = useCallback((at) => {
|
|
904
|
+
if (folderView)
|
|
905
|
+
folderView.openViewMenu(at);
|
|
906
|
+
else
|
|
907
|
+
setCtxMenu({ kind: 'view', at });
|
|
908
|
+
}, [folderView]);
|
|
909
|
+
/*
|
|
910
|
+
* The blank space under the rows answers a right-click with the VIEW menu. A native listener
|
|
911
|
+
* rather than a JSX one because the scroller is the tree's frame, not a control — giving it a
|
|
912
|
+
* role to hang a handler on would announce it as one. A row answers its own menu; a press on
|
|
913
|
+
* a row's tools, or on a row with no menu, keeps the browser's.
|
|
914
|
+
*/
|
|
915
|
+
const wantsBlankMenu = Boolean(folderView || backgroundMenu);
|
|
916
|
+
useEffect(() => {
|
|
917
|
+
const scroller = scrollRef.current;
|
|
918
|
+
if (!scroller || !wantsBlankMenu)
|
|
919
|
+
return;
|
|
920
|
+
const onContextMenu = (event) => {
|
|
921
|
+
if (event.target instanceof Element && event.target.closest('.cbft-row'))
|
|
922
|
+
return;
|
|
923
|
+
event.preventDefault();
|
|
924
|
+
openViewMenu({ x: event.clientX, y: event.clientY });
|
|
925
|
+
};
|
|
926
|
+
scroller.addEventListener('contextmenu', onContextMenu);
|
|
927
|
+
return () => scroller.removeEventListener('contextmenu', onContextMenu);
|
|
928
|
+
}, [wantsBlankMenu, openViewMenu]);
|
|
929
|
+
/** Fetch the panels once the page is idle, if this tree has any menu to open. */
|
|
930
|
+
const hasMenus = wantsBlankMenu || Boolean(rowMenu);
|
|
931
|
+
useEffect(() => {
|
|
932
|
+
if (!hasMenus)
|
|
933
|
+
return;
|
|
934
|
+
const load = () => void TreePanel.preload().catch(() => { });
|
|
935
|
+
const idle = globalThis.requestIdleCallback;
|
|
936
|
+
if (idle) {
|
|
937
|
+
const handle = idle(load, { timeout: 4000 });
|
|
938
|
+
return () => globalThis.cancelIdleCallback?.(handle);
|
|
939
|
+
}
|
|
940
|
+
const timer = setTimeout(load, 1500);
|
|
941
|
+
return () => clearTimeout(timer);
|
|
942
|
+
}, [hasMenus]);
|
|
943
|
+
/**
|
|
944
|
+
* Put the keyboard back on the row a menu was opened from — but only if the menu left it on
|
|
945
|
+
* `<body>`. An item that opened ANOTHER panel (Tags…) has already moved focus into it, and
|
|
946
|
+
* taking it back would leave the person typing into nothing.
|
|
947
|
+
*/
|
|
948
|
+
const refocusAfterMenu = useCallback((id, pinnedCopy) => {
|
|
949
|
+
requestAnimationFrame(() => {
|
|
950
|
+
const at = globalThis.document?.activeElement;
|
|
951
|
+
if (!at || at === globalThis.document.body)
|
|
952
|
+
rowEl(id, pinnedCopy)?.focus();
|
|
953
|
+
});
|
|
954
|
+
}, [rowEl]);
|
|
866
955
|
/*
|
|
867
956
|
* ── The keyboard comes back from a rename ─────────────────────────────────────────────
|
|
868
957
|
*
|
|
@@ -961,6 +1050,27 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
961
1050
|
onRowMenu(row.node, { x: box?.right ?? 0, y: box?.bottom ?? 0 });
|
|
962
1051
|
return;
|
|
963
1052
|
}
|
|
1053
|
+
// No menu of the consumer's own: the tree's right-click menu answers the same keys.
|
|
1054
|
+
if (hasRowMenu(row.node) &&
|
|
1055
|
+
(event.key === 'ContextMenu' || (event.shiftKey && event.key === 'F10'))) {
|
|
1056
|
+
event.preventDefault();
|
|
1057
|
+
const box = rowEl(row.node.id, pinnedCopy)?.getBoundingClientRect();
|
|
1058
|
+
openRowMenu(row.node, pinnedCopy, {
|
|
1059
|
+
x: (box?.left ?? 0) + 24,
|
|
1060
|
+
y: box?.bottom ?? 0,
|
|
1061
|
+
});
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
/*
|
|
1065
|
+
* ⇧⌘. — show or leave out hidden folders. Finder's own chord for hidden files, so a Mac
|
|
1066
|
+
* user already has it in their hands. By `code`: with Shift held, `key` is `>` on a US
|
|
1067
|
+
* keyboard and something else on others.
|
|
1068
|
+
*/
|
|
1069
|
+
if (folderView && event.code === 'Period' && event.shiftKey && (event.metaKey || event.ctrlKey)) {
|
|
1070
|
+
event.preventDefault();
|
|
1071
|
+
folderView.setShowHidden(!folderView.local.showHidden);
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
964
1074
|
/*
|
|
965
1075
|
* ── ⌃⌘T — pin, and unpin ────────────────────────────────────────────────────────
|
|
966
1076
|
*
|
|
@@ -1289,6 +1399,9 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
1289
1399
|
onPinnedChange,
|
|
1290
1400
|
onRenameStart,
|
|
1291
1401
|
onRowMenu,
|
|
1402
|
+
hasRowMenu,
|
|
1403
|
+
openRowMenu,
|
|
1404
|
+
folderView,
|
|
1292
1405
|
onSelect,
|
|
1293
1406
|
onWrapStart,
|
|
1294
1407
|
mirror,
|
|
@@ -1547,7 +1660,8 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
1547
1660
|
refs.current.set(node.id, el);
|
|
1548
1661
|
else
|
|
1549
1662
|
refs.current.delete(node.id);
|
|
1550
|
-
}, key: node.id, "data-id": node.id, className: 'cbft-row', "data-selected": isSelected || undefined, "data-cut": cut?.has(node.id) || undefined, "data-dragged": isDragged || undefined, "data-into": isDropTarget || undefined, "data-marker": marker ?? undefined, "data-pinned": isPinned || undefined, "data-pinned-copy": pinnedCopy || undefined, "data-ancestor": openPath.path.has(node.id) || undefined, "data-holds-open": (row.expandable && !row.expanded && openPath.holder === node.id) || undefined, "data-access": node.access && node.access !== 'normal' ? node.access : undefined, "data-matched": node.matched || undefined,
|
|
1663
|
+
}, key: node.id, "data-id": node.id, className: 'cbft-row', "data-selected": isSelected || undefined, "data-cut": cut?.has(node.id) || undefined, "data-dragged": isDragged || undefined, "data-into": isDropTarget || undefined, "data-marker": marker ?? undefined, "data-pinned": isPinned || undefined, "data-pinned-copy": pinnedCopy || undefined, "data-ancestor": openPath.path.has(node.id) || undefined, "data-holds-open": (row.expandable && !row.expanded && openPath.holder === node.id) || undefined, "data-access": node.access && node.access !== 'normal' ? node.access : undefined, "data-matched": node.matched || undefined, "data-hidden": viewed?.hiddenMarks.get(node.id), "data-menu-open": (ctxMenu?.kind === 'row' && ctxMenu.node.id === node.id && ctxMenu.pinned === pinnedCopy) ||
|
|
1664
|
+
undefined, style: { '--cbft-depth': row.depth }, onPointerDown: (event) => {
|
|
1551
1665
|
if (inTools(event.target))
|
|
1552
1666
|
return;
|
|
1553
1667
|
// A finger on the row is a SCROLL; only the grip picks it up. See `startsDrag`.
|
|
@@ -1569,7 +1683,13 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
1569
1683
|
if (inTools(event.target))
|
|
1570
1684
|
return;
|
|
1571
1685
|
(onOpen ?? onSelect)(node);
|
|
1572
|
-
}, onKeyDown: (event) => onKeyDown(event, row, list, pinnedCopy), onFocus: () => setFocused({ id: node.id, pinned: pinnedCopy }),
|
|
1686
|
+
}, onKeyDown: (event) => onKeyDown(event, row, list, pinnedCopy), onFocus: () => setFocused({ id: node.id, pinned: pinnedCopy }), onContextMenu: (event) => {
|
|
1687
|
+
if (inTools(event.target) || !hasRowMenu(node))
|
|
1688
|
+
return;
|
|
1689
|
+
event.preventDefault();
|
|
1690
|
+
event.stopPropagation();
|
|
1691
|
+
openRowMenu(node, pinnedCopy, { x: event.clientX, y: event.clientY });
|
|
1692
|
+
}, ...externalHandlers(node) },
|
|
1573
1693
|
row.expandable ? (_jsx("span", { className: 'cbft-twisty', "data-open": row.expanded || undefined, "aria-hidden": 'true', onPointerDown: (event) => event.stopPropagation(), onClick: (event) => {
|
|
1574
1694
|
event.stopPropagation();
|
|
1575
1695
|
toggle(node.id);
|
|
@@ -1578,6 +1698,8 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
1578
1698
|
// VS Code's field: the whole name is there, and only the part before the
|
|
1579
1699
|
// suffix is selected, so typing replaces the name and keeps the type.
|
|
1580
1700
|
node.suffix ? node.name.length : undefined)) : (_jsx(Tooltip, { content: nameTooltips ? node.name : undefined, children: _jsxs("span", { className: 'cbft-name', children: [node.name, node.suffix ? _jsx("span", { className: 'cbft-suffix', children: node.suffix }) : null] }) })),
|
|
1701
|
+
viewed?.hiddenMarks.get(node.id) === 'self' ? (_jsx("span", { className: 'cbft-hidden-mark', role: 'img', "aria-label": 'Hidden', children: _jsxs("svg", { viewBox: '0 0 24 24', width: '12', height: '12', fill: 'none', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', focusable: 'false', "aria-hidden": 'true', children: [_jsx("path", { d: 'M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68' }), _jsx("path", { d: 'M6.61 6.61A13.53 13.53 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61' }), _jsx("path", { d: 'M14.12 14.12a3 3 0 1 1-4.24-4.24' }), _jsx("path", { d: 'm2 2 20 20' })] }) })) : null,
|
|
1702
|
+
folderView && node.kind === 'folder' ? (_jsx(RowTagDots, { tags: folderView.marks.tags[node.id] ?? [] })) : null,
|
|
1581
1703
|
node.access === 'private' || node.access === 'locked' ? (_jsx(Tooltip, { content: accessMarkCopy(node.access, accessCopy), children: _jsx("span", { className: 'cbft-access', role: 'img', "aria-label": 'Private', children: "\uD83D\uDD12" }) })) : null,
|
|
1582
1704
|
renderAccessory ? renderAccessory(node) : null,
|
|
1583
1705
|
node.count !== undefined ? _jsx("span", { className: 'cbft-count', children: node.count }) : null,
|
|
@@ -1605,14 +1727,66 @@ export function FileTree({ nodes, selectedId, onSelect, selectedIds, onSelection
|
|
|
1605
1727
|
// being made in a place, and the place is where the folder actually lives.
|
|
1606
1728
|
return !pinnedCopy && draft && draft.parentId === node.id ? (_jsxs(Fragment, { children: [body, draftRow(row.depth + 1)] }, node.id)) : (body);
|
|
1607
1729
|
};
|
|
1608
|
-
|
|
1730
|
+
/** The open right-click menu or tag editor, if any — see `FolderViewMenus.tsx`. */
|
|
1731
|
+
const treeMenus = () => {
|
|
1732
|
+
const out = [];
|
|
1733
|
+
if (ctxMenu?.kind === 'row') {
|
|
1734
|
+
const { node, pinned: pinnedCopy, at } = ctxMenu;
|
|
1735
|
+
const close = () => {
|
|
1736
|
+
setCtxMenu(null);
|
|
1737
|
+
refocusAfterMenu(node.id, pinnedCopy);
|
|
1738
|
+
};
|
|
1739
|
+
const own = rowMenu?.(node) ?? [];
|
|
1740
|
+
const ids = folderTargets(node, selection, (id) => findFileTreeNode(nodes, id)?.kind === 'folder');
|
|
1741
|
+
const fv = folderView
|
|
1742
|
+
? folderViewMenuItems(folderView, node, ids, viewed?.hiddenMarks.get(node.id) ?? null)
|
|
1743
|
+
: [];
|
|
1744
|
+
const items = withFolderItems(own, fv);
|
|
1745
|
+
if (items.length > 0)
|
|
1746
|
+
out.push(_jsx(TreePanel, { kind: 'row', at: at, label: `Actions for ${node.name}`, items: items, onClose: close }, 'row-menu'));
|
|
1747
|
+
}
|
|
1748
|
+
const viewAt = folderView?.panel?.kind === 'view'
|
|
1749
|
+
? folderView.panel.at
|
|
1750
|
+
: ctxMenu?.kind === 'view'
|
|
1751
|
+
? ctxMenu.at
|
|
1752
|
+
: null;
|
|
1753
|
+
if (viewAt) {
|
|
1754
|
+
const close = () => {
|
|
1755
|
+
setCtxMenu(null);
|
|
1756
|
+
folderView?.closePanel();
|
|
1757
|
+
};
|
|
1758
|
+
const folderIds = flattenFileTree(shown, [])
|
|
1759
|
+
.filter((r) => r.expandable)
|
|
1760
|
+
.map((r) => r.node.id);
|
|
1761
|
+
out.push(_jsx(TreePanel, { kind: 'view', view: folderView, at: viewAt, hiddenCount: viewed?.hiddenCount ?? 0, extraItems: backgroundMenu?.() ?? [], onCollapseAll: folderIds.length > 0 ? () => shutFolders(folderIds) : null, onClose: close }, 'view-menu'));
|
|
1762
|
+
}
|
|
1763
|
+
if (folderView?.panel?.kind === 'tags') {
|
|
1764
|
+
const { ids } = folderView.panel;
|
|
1765
|
+
const names = ids.map((id) => findFileTreeNode(nodes, id)?.name ?? '').filter(Boolean);
|
|
1766
|
+
let at = folderView.panel.at;
|
|
1767
|
+
if (!at) {
|
|
1768
|
+
// Opened from a ⋯ menu, which has no pointer to give: under the first folder's row.
|
|
1769
|
+
const box = (rowEl(ids[0] ?? '', false) ?? rootRef.current)?.getBoundingClientRect();
|
|
1770
|
+
at = { x: (box?.left ?? 0) + 24, y: box?.bottom ?? 0 };
|
|
1771
|
+
}
|
|
1772
|
+
out.push(_jsx(TreePanel, { kind: 'tags', view: folderView, ids: ids, names: names.length > 0 ? names : ['this folder'], at: at, onClose: () => {
|
|
1773
|
+
folderView.closePanel();
|
|
1774
|
+
if (ids[0])
|
|
1775
|
+
refocusAfterMenu(ids[0], false);
|
|
1776
|
+
} }, `tags:${ids.join(',')}`));
|
|
1777
|
+
}
|
|
1778
|
+
return out;
|
|
1779
|
+
};
|
|
1780
|
+
return (_jsxs("div", { ref: rootRef, onPaste: onPaste, className: `cbft${scroll === 'host' ? ' cbft--host-scroll' : ''}${className ? ` ${className}` : ''}`, "data-quiet-path": markPath ? undefined : true, children: [folderView ? _jsx(FolderViewStrip, { view: folderView, onOpenMenu: openViewMenu }) : null, pinnedRows.length > 0 ? (_jsxs("div", { className: 'cbft-pinned', children: [_jsx("div", { className: 'cbft-pinned-head', children: pinnedLabel }), _jsx("div", { role: 'tree', "aria-label": pinnedLabel, ...(onSelectionChange ? { 'aria-multiselectable': true } : {}), className: `cbft-pinned-list${drag?.active ? ' cbft-list-dragging' : ''}`, children: pinnedRows.map((row) => renderRow(row, true)) })] })) : null, _jsx("div", { className: 'cbft-scroll', ref: scrollRef, "data-into-root": (drag?.active && drag.offer.target?.kind === 'root') ||
|
|
1609
1781
|
externalOverId === EXTERNAL_OVER_ROOT ||
|
|
1610
1782
|
undefined, ...externalHandlers(null), onPointerUp: () => {
|
|
1611
1783
|
// Releasing over the blank space means the top level; the pointer capture keeps
|
|
1612
1784
|
// the row's own listeners running, so this only has to not swallow the event.
|
|
1613
|
-
}, children: _jsxs("div", { role: 'tree', "aria-label": ariaLabel, ...(onSelectionChange ? { 'aria-multiselectable': true } : {}), className: `cbft-list${drag?.active ? ' cbft-list-dragging' : ''}`, children: [rows.length === 0 && !draft ? _jsx("div", { className: 'cbft-empty', children:
|
|
1785
|
+
}, children: _jsxs("div", { role: 'tree', "aria-label": ariaLabel, ...(onSelectionChange ? { 'aria-multiselectable': true } : {}), className: `cbft-list${drag?.active ? ' cbft-list-dragging' : ''}`, children: [rows.length === 0 && !draft ? (_jsx("div", { className: 'cbft-empty', children: folderView && tagFilterActive(folderView.local) && nodes.length > 0
|
|
1786
|
+
? 'No folders carry these tags. Right-click here to change the filter.'
|
|
1787
|
+
: empty })) : null, draft && draft.parentId === null ? draftRow(0) : null, rows.map((row) => renderRow(row, false)), draft && draft.parentId !== null && !rows.some((r) => r.node.id === draft.parentId)
|
|
1614
1788
|
? draftRow(0)
|
|
1615
|
-
: null] }) }), drag?.active ? (_jsxs("div", { className: 'cbft-chip', "data-refused": drag.offer.refused || undefined, style: { left: `${drag.x}px`, top: `${drag.y}px` }, "aria-hidden": 'true', children: [_jsx("span", { className: 'cbft-chip-name', children: drag.ids.length > 1 ? `${drag.ids.length} items` : nameOf(shown, drag.id) }), _jsx("span", { className: 'cbft-chip-where', children: drag.offer.reason ?? describeDrop(shown, drag.offer.target) })] })) : null, _jsx("span", { className: 'cbft-sr', role: 'status', "aria-live": 'polite', children: drag?.active ? (drag.offer.reason ?? describeDrop(shown, drag.offer.target)) : notice })] }));
|
|
1789
|
+
: null] }) }), drag?.active ? (_jsxs("div", { className: 'cbft-chip', "data-refused": drag.offer.refused || undefined, style: { left: `${drag.x}px`, top: `${drag.y}px` }, "aria-hidden": 'true', children: [_jsx("span", { className: 'cbft-chip-name', children: drag.ids.length > 1 ? `${drag.ids.length} items` : nameOf(shown, drag.id) }), _jsx("span", { className: 'cbft-chip-where', children: drag.offer.reason ?? describeDrop(shown, drag.offer.target) })] })) : null, treeMenus(), _jsx("span", { className: 'cbft-sr', role: 'status', "aria-live": 'polite', children: drag?.active ? (drag.offer.reason ?? describeDrop(shown, drag.offer.target)) : notice })] }));
|
|
1616
1790
|
}
|
|
1617
1791
|
/**
|
|
1618
1792
|
* Whether an event landed on the consumer's own row controls.
|