mirror of
https://github.com/anomalyco/opencode.git
synced 2026-10-23 15:40:52 +00:00
204 lines
12 KiB
Diff
204 lines
12 KiB
Diff
diff --git a/dist/model/FileTreeController.js b/dist/model/FileTreeController.js
|
|
index efa8b6a2fd70e0d1f1dec1d90ee87268c72f56c4..8979be3c9549e650b017ace5be2e84c2af3f163f 100644
|
|
--- a/dist/model/FileTreeController.js
|
|
+++ b/dist/model/FileTreeController.js
|
|
@@ -1056,8 +1056,8 @@ var FileTreeController = class FileTreeController {
|
|
this.#setExpandedPaths(expandedPaths);
|
|
return focusCandidate ?? this.#focusedPath;
|
|
}
|
|
- #emit() {
|
|
- for (const listener of this.#listeners) listener();
|
|
+ #emit(event) {
|
|
+ for (const listener of this.#listeners) listener(event);
|
|
}
|
|
#emitMutation(event) {
|
|
this.#mutationListeners.get(event.operation)?.forEach((listener) => {
|
|
@@ -1153,7 +1153,7 @@ var FileTreeController = class FileTreeController {
|
|
const searchFocusCandidate = this.#searchValue != null && this.#searchValue.length > 0 ? this.#refreshActiveSearchState() : this.#searchValue === "" ? this.#focusedPath : focusPathCandidate;
|
|
const shouldBuildFullProjection = this.#searchValue != null || event.operation !== "expand" && event.operation !== "collapse";
|
|
this.#rebuildVisibleProjection(searchFocusCandidate, shouldBuildFullProjection);
|
|
- this.#emit();
|
|
+ this.#emit(event);
|
|
const mutationEvent = toTreesMutationEvent(event);
|
|
if (mutationEvent != null) this.#emitMutation(mutationEvent);
|
|
});
|
|
diff --git a/dist/model/internalTypes.d.ts b/dist/model/internalTypes.d.ts
|
|
index 5b0fdd5a3b483439ae256795f3dad5a32182ab78..84ba867b12003fb57602c19234c262385f6ee704 100644
|
|
--- a/dist/model/internalTypes.d.ts
|
|
+++ b/dist/model/internalTypes.d.ts
|
|
@@ -4,7 +4,10 @@ import { FileTreeCompositionOptions, FileTreePublicId, FileTreeRenderOptions, Fi
|
|
import { FileTreeController } from "./FileTreeController.js";
|
|
|
|
//#region src/model/internalTypes.d.ts
|
|
-type FileTreeControllerListener = () => void;
|
|
+type FileTreeControllerListener = (event?: {
|
|
+ operation: 'expand' | 'collapse';
|
|
+ path: string;
|
|
+}) => void;
|
|
interface FileTreeStickyRowCandidate {
|
|
row: FileTreeVisibleRow;
|
|
subtreeEndIndex: number;
|
|
diff --git a/dist/model/publicTypes.d.ts b/dist/model/publicTypes.d.ts
|
|
index 7c851604626d34fcb838cd0381abfccfcc7728cf..4e93d2072d3550af080bc98a36e293b05c1a6a10 100644
|
|
--- a/dist/model/publicTypes.d.ts
|
|
+++ b/dist/model/publicTypes.d.ts
|
|
@@ -170,6 +170,11 @@ type FileTreeOptionSurface = FileTreeRenderOptions & {
|
|
gitStatus?: readonly GitStatusEntry[];
|
|
id?: string;
|
|
icons?: FileTreeIcons;
|
|
+ middleTruncate?: boolean;
|
|
+ onExpansionChange?: (change: {
|
|
+ expanded: boolean;
|
|
+ path: FileTreePublicId;
|
|
+ }) => void;
|
|
onSelectionChange?: FileTreeSelectionChangeListener;
|
|
renderRowDecoration?: FileTreeRowDecorationRenderer;
|
|
search?: boolean;
|
|
diff --git a/dist/render/FileTree.js b/dist/render/FileTree.js
|
|
index 305714319d9d988bfc025ecaaca662562a3a0ff7..8ab6a7b9b7734b1fa2e17c96743eeb013d4d838c 100644
|
|
--- a/dist/render/FileTree.js
|
|
+++ b/dist/render/FileTree.js
|
|
@@ -62,6 +62,7 @@ var FileTree = class {
|
|
#composition;
|
|
#controller;
|
|
#id;
|
|
+ #onExpansionChange;
|
|
#onSelectionChange;
|
|
#renderRowDecoration;
|
|
#renamingEnabled;
|
|
@@ -79,16 +80,18 @@ var FileTree = class {
|
|
#appliedUnsafeCSS;
|
|
#selectionVersion;
|
|
#selectionSubscription = null;
|
|
+ #expansionSubscription = null;
|
|
#wrapper;
|
|
#wroteHostItemHeight = false;
|
|
#wroteHostDensityFactor = false;
|
|
constructor(options) {
|
|
- const { composition, density, fileTreeSearchMode, gitStatus, id, initialSearchQuery, icons, itemHeight, onSearchChange, onSelectionChange, overscan, renderRowDecoration, renaming, search, searchBlurBehavior, searchFakeFocus, stickyFolders, unsafeCSS, initialVisibleRowCount, ...controllerOptions } = options;
|
|
+ const { composition, density, fileTreeSearchMode, gitStatus, id, initialSearchQuery, icons, itemHeight, middleTruncate, onExpansionChange, onSearchChange, onSelectionChange, overscan, renderRowDecoration, renaming, search, searchBlurBehavior, searchFakeFocus, stickyFolders, unsafeCSS, initialVisibleRowCount, ...controllerOptions } = options;
|
|
this.#composition = composition;
|
|
this.#id = createClientId(id);
|
|
this.#gitStatusState = resolveFileTreeGitStatusState(gitStatus);
|
|
this.#icons = icons;
|
|
this.#unsafeCSS = unsafeCSS;
|
|
+ this.#onExpansionChange = onExpansionChange;
|
|
this.#onSelectionChange = onSelectionChange;
|
|
this.#renderRowDecoration = renderRowDecoration;
|
|
this.#renamingEnabled = renaming != null && renaming !== false;
|
|
@@ -98,6 +101,7 @@ var FileTree = class {
|
|
this.#density = resolveFileTreeDensity(density, itemHeight);
|
|
this.#viewOptions = {
|
|
itemHeight: this.#density.itemHeight,
|
|
+ middleTruncate,
|
|
overscan,
|
|
stickyFolders,
|
|
initialVisibleRowCount
|
|
@@ -113,6 +117,10 @@ var FileTree = class {
|
|
this.#selectionSubscription = this.#onSelectionChange == null ? null : this.subscribe(() => {
|
|
this.#emitSelectionChange();
|
|
});
|
|
+ this.#expansionSubscription = this.#onExpansionChange == null ? null : this.#controller.subscribe((event) => {
|
|
+ if (event?.operation !== "expand" && event?.operation !== "collapse") return;
|
|
+ this.#onExpansionChange?.({ path: event.path, expanded: event.operation === "expand" });
|
|
+ });
|
|
}
|
|
unmount() {
|
|
if (this.#wrapper != null) {
|
|
@@ -132,6 +140,8 @@ var FileTree = class {
|
|
this.unmount();
|
|
this.#selectionSubscription?.();
|
|
this.#selectionSubscription = null;
|
|
+ this.#expansionSubscription?.();
|
|
+ this.#expansionSubscription = null;
|
|
this.#controller.destroy();
|
|
}
|
|
getFileTreeContainer() {
|
|
@@ -296,6 +306,7 @@ var FileTree = class {
|
|
itemHeight: this.#viewOptions.itemHeight
|
|
}),
|
|
itemHeight: this.#viewOptions.itemHeight,
|
|
+ middleTruncate: this.#viewOptions.middleTruncate,
|
|
overscan: this.#viewOptions.overscan,
|
|
stickyFolders: this.#viewOptions.stickyFolders
|
|
};
|
|
diff --git a/dist/render/FileTreeView.js b/dist/render/FileTreeView.js
|
|
index 7d3b818c43a7621ab9170da32b180232ed3c9472..222e49fe7130452d028f4204fde57b0398ce2d34 100644
|
|
--- a/dist/render/FileTreeView.js
|
|
+++ b/dist/render/FileTreeView.js
|
|
@@ -360,7 +360,7 @@ function focusFirstMenuElement(menuElement) {
|
|
"[tabindex]:not([tabindex=\"-1\"])"
|
|
].join(", ")) ?? menuElement);
|
|
}
|
|
-function renderFileTreeRowContent(row, resolveIcon, { actionLaneEnabled = false, customDecoration = null, decorationLaneEnabled = false, dragTargetFlattenedSegmentPath = null, gitDecoration = null, gitLaneActive = false, renameInput = null, showDecorativeActionAffordance = false } = {}) {
|
|
+function renderFileTreeRowContent(row, resolveIcon, { actionLaneEnabled = false, customDecoration = null, decorationLaneEnabled = false, dragTargetFlattenedSegmentPath = null, gitDecoration = null, gitLaneActive = false, middleTruncate = true, renameInput = null, showDecorativeActionAffordance = false } = {}) {
|
|
const targetPath = getFileTreeRowPath(row);
|
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
row.depth > 0 ? /* @__PURE__ */ jsx("div", {
|
|
@@ -376,11 +376,12 @@ function renderFileTreeRowContent(row, resolveIcon, { actionLaneEnabled = false,
|
|
}),
|
|
/* @__PURE__ */ jsx("div", {
|
|
"data-item-section": "content",
|
|
- children: row.isFlattened ? formatFlattenedSegments(row, renameInput, dragTargetFlattenedSegmentPath) : renameInput ?? /* @__PURE__ */ jsx(MiddleTruncate, {
|
|
+ title: middleTruncate ? void 0 : row.name,
|
|
+ children: row.isFlattened ? formatFlattenedSegments(row, renameInput, dragTargetFlattenedSegmentPath) : renameInput ?? (middleTruncate ? /* @__PURE__ */ jsx(MiddleTruncate, {
|
|
minimumLength: 5,
|
|
split: "extension",
|
|
children: row.name
|
|
- })
|
|
+ }) : row.name)
|
|
}),
|
|
decorationLaneEnabled ? /* @__PURE__ */ jsx("div", {
|
|
"data-item-section": "decoration",
|
|
@@ -401,7 +402,7 @@ function renderFileTreeRowContent(row, resolveIcon, { actionLaneEnabled = false,
|
|
] });
|
|
}
|
|
function renderStyledRow(frame, row, key, options = {}) {
|
|
- const { controller, renameView, visualFocusPath, contextHoverPath, draggedPathSet, dragTarget, dragAndDropEnabled, shouldSuppressContextMenu, handleRowDragStart, handleRowDragEnd, handleRowTouchStart, instanceId, itemHeight, gitStatusByPath, ignoredGitDirectories, ignoredInheritanceCache, directoriesWithGitChanges, gitLaneActive, contextMenuEnabled, contextMenuTriggerMode, contextMenuButtonTriggerEnabled, contextMenuButtonVisibility, contextMenuRightClickEnabled, registerRenameInput, registerButton, resolveIcon, renderDecorationForRow, openContextMenuForRow, onRowClick, onKeyDown } = frame;
|
|
+ const { controller, renameView, visualFocusPath, contextHoverPath, draggedPathSet, dragTarget, dragAndDropEnabled, shouldSuppressContextMenu, handleRowDragStart, handleRowDragEnd, handleRowTouchStart, instanceId, itemHeight, middleTruncate, gitStatusByPath, ignoredGitDirectories, ignoredInheritanceCache, directoriesWithGitChanges, gitLaneActive, contextMenuEnabled, contextMenuTriggerMode, contextMenuButtonTriggerEnabled, contextMenuButtonVisibility, contextMenuRightClickEnabled, registerRenameInput, registerButton, resolveIcon, renderDecorationForRow, openContextMenuForRow, onRowClick, onKeyDown } = frame;
|
|
const targetPath = getFileTreeRowPath(row);
|
|
const { isParked = false, mode = "flow", style } = options;
|
|
const isSticky = mode === "sticky";
|
|
@@ -433,6 +434,7 @@ function renderStyledRow(frame, row, key, options = {}) {
|
|
dragTargetFlattenedSegmentPath: dragTarget?.flattenedSegmentPath ?? null,
|
|
gitDecoration,
|
|
gitLaneActive,
|
|
+ middleTruncate,
|
|
renameInput,
|
|
showDecorativeActionAffordance
|
|
});
|
|
@@ -517,7 +519,7 @@ function renderRangeChildren(frame, range, hiddenRowPaths) {
|
|
if (range.end < range.start) return [];
|
|
return frame.controller.getVisibleRows(range.start, range.end).filter((row) => !hiddenRowPaths.has(getFileTreeRowPath(row))).map((row, slotIndex) => renderStyledRow(frame, row, range.start + slotIndex));
|
|
}
|
|
-function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDirectories, directoriesWithGitChanges, icons, instanceId, itemHeight = FILE_TREE_DEFAULT_ITEM_HEIGHT, overscan = 10, renamingEnabled = false, renderRowDecoration, searchBlurBehavior = "close", searchEnabled = false, searchFakeFocus = false, slotHost, stickyFolders = false, initialViewportHeight = 420 }) {
|
|
+function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDirectories, directoriesWithGitChanges, icons, instanceId, itemHeight = FILE_TREE_DEFAULT_ITEM_HEIGHT, middleTruncate = true, overscan = 10, renamingEnabled = false, renderRowDecoration, searchBlurBehavior = "close", searchEnabled = false, searchFakeFocus = false, slotHost, stickyFolders = false, initialViewportHeight = 420 }) {
|
|
"use no memo";
|
|
const contextMenuAnchorRef = useRef(null);
|
|
const contextMenuTriggerRef = useRef(null);
|
|
@@ -653,7 +655,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
const getTriggerAnchorButton = useCallback((path) => {
|
|
return getContextMenuAnchorButton(path, stickyRowButtonRefs.current, rowButtonRefs.current);
|
|
}, []);
|
|
- const gitLaneActive = gitStatusByPath != null || ignoredGitDirectories != null || directoriesWithGitChanges != null;
|
|
+ const gitLaneActive = true;
|
|
const { resolveIcon } = useMemo(() => createFileTreeIconResolver(icons), [icons]);
|
|
const renameView = controller[FILE_TREE_RENAME_VIEW]();
|
|
const renamingPath = renameView.getPath();
|
|
@@ -1272,7 +1274,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
const update = () => {
|
|
const nextItemCount = controller.getVisibleCount();
|
|
const nextViewportHeight = getCachedViewportHeight(measuredViewportHeightRef.current, initialViewportHeight);
|
|
- const maxScrollTop = Math.max(0, nextItemCount * itemHeight - nextViewportHeight);
|
|
+ const maxScrollTop = Math.max(0, nextItemCount * itemHeight - nextViewportHeight, scrollElement.scrollHeight - scrollElement.clientHeight);
|
|
if (scrollElement.scrollTop > maxScrollTop) scrollElement.scrollTop = maxScrollTop;
|
|
setLayoutState(computeFileTreeViewLayoutState({
|
|
controller,
|
|
@@ -1752,6 +1754,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
ignoredInheritanceCache,
|
|
instanceId,
|
|
itemHeight,
|
|
+ middleTruncate,
|
|
onKeyDown: handleTreeKeyDown,
|
|
onRowClick: handleRowClick,
|
|
openContextMenuForRow,
|