/* Copyright 2026 Marimo. All rights reserved. */ import { FileIcon, FolderIcon } from "lucide-react"; import type { RefObject } from "react"; import { Tree, type NodeRendererProps, type RowRendererProps, type TreeApi, } from "react-arborist"; import { Spinner } from "@/components/icons/spinner"; import { cn } from "@/utils/cn"; import { useTreeDndManager } from "./dnd-wrapper"; import { FileTreeRow } from "./file-tree-row"; import type { FileTreeNode } from "./requesting-tree"; import type { useFileSearch } from "./use-file-search"; export function FileSearchResults({ treeRef, search, height, onReveal, }: { treeRef: RefObject | null>; search: ReturnType; height: number; onReveal: (node: FileTreeNode) => Promise; }) { const dndManager = useTreeDndManager(); const { state, refetch } = search; if (state.status === "idle") { return null; } if (state.status === "error") { return (
Could not search files.{" "}
); } if (state.status === "loading") { return (
Searching files…
); } const { files, hasMore, isPartial } = state; const count = files.length; return (
{ if ( event.key === "Enter" && event.target instanceof HTMLElement && event.target.closest('[role="tree"]') ) { event.preventDefault(); event.stopPropagation(); treeRef.current?.focusedNode?.activate(); } }} > {isPartial && (
Some locations could not be searched.{" "}
)}

{files.length ? `${count} ${count === 1 ? "match" : "matches"}` : "No matching files or folders."} {hasMore && " · Refine your search for more results."}

ref={treeRef} data={files} childrenAccessor={() => null} width="100%" height={Math.max(0, height - 48 - (isPartial ? 48 : 0))} rowHeight={48} overscanCount={8} dndManager={dndManager} disableDrag={true} disableDrop={true} disableEdit={true} disableMultiSelection={true} selectionFollowsFocus={true} rowClassName="outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring" renderRow={SearchResultRow} onActivate={(node) => { void onReveal(node.data); }} > {SearchResult}

Enter or double-click to open · Esc to clear

); } function SearchResultRow(props: RowRendererProps) { return ; } function SearchResult({ node }: NodeRendererProps) { const Icon = node.data.isDirectory ? FolderIcon : FileIcon; return (
{ event.stopPropagation(); node.activate(); }} title={node.data.path} >
{node.data.name}
{node.data.path}
); }