momoi-explorer 0.8.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/index.ts","../src/ui/FileExplorer.tsx","../src/react/TreeProvider.tsx","../src/core/event-processor.ts","../src/core/flatten.ts","../src/core/selection.ts","../src/core/sort.ts","../src/core/filter.ts","../src/core/search.ts","../src/core/tree.ts","../src/react/context.ts","../src/react/useFileTree.ts","../src/react/useContextMenu.ts","../src/react/useExplorerKeybindings.ts","../src/core/keybindings.ts","../src/react/useExplorerFocus.ts","../src/ui/TreeNodeRow.tsx","../src/ui/InlineRename.tsx","../src/ui/ContextMenu.tsx","../src/ui/TreeFilterBar.tsx","../src/ui/QuickOpen.tsx"],"sourcesContent":["export { FileExplorer } from './FileExplorer'\nexport { TreeNodeRow } from './TreeNodeRow'\nexport { ContextMenu } from './ContextMenu'\nexport { InlineRename } from './InlineRename'\nexport { TreeFilterBar } from './TreeFilterBar'\nexport { QuickOpen } from './QuickOpen'\nexport type { FileExplorerProps } from './FileExplorer'\nexport type { TreeNodeRowProps } from './TreeNodeRow'\nexport type { ContextMenuProps } from './ContextMenu'\nexport type { InlineRenameProps } from './InlineRename'\nexport type { TreeFilterBarProps } from './TreeFilterBar'\nexport type { QuickOpenProps } from './QuickOpen'\n","import type React from 'react'\r\nimport { useCallback, useEffect, useMemo } from 'react'\r\nimport { Virtuoso } from 'react-virtuoso'\r\nimport type { FileSystemAdapter, FileTreeController, FileTreeOptions, MenuItemDef, TreeEvent, TreeNode } from '../core/types'\r\nimport { TreeProvider } from '../react/TreeProvider'\r\nimport { useFileTree } from '../react/useFileTree'\r\nimport { useContextMenu } from '../react/useContextMenu'\r\nimport { useExplorerKeybindings, type InputServiceLike } from '../react/useExplorerKeybindings'\r\nimport { useExplorerFocus } from '../react/useExplorerFocus'\r\nimport { TreeNodeRow } from './TreeNodeRow'\r\nimport { ContextMenu } from './ContextMenu'\r\nimport { TreeFilterBar } from './TreeFilterBar'\r\nimport { InlineRename } from './InlineRename'\r\n\r\n/** {@link FileExplorer} に渡すprops */\r\nexport interface FileExplorerProps {\r\n /** ファイルシステム操作の実装 */\r\n adapter: FileSystemAdapter\r\n /** ツリーのルートディレクトリパス */\r\n rootPath: string\r\n /** ファイル/フォルダのソート関数 */\r\n sort?: FileTreeOptions['sort']\r\n /** 表示対象を絞り込むフィルタ関数 */\r\n filter?: FileTreeOptions['filter']\r\n /** ファイル監視の設定 */\r\n watchOptions?: FileTreeOptions['watchOptions']\r\n /** ツリー操作イベント(展開・選択・リネーム等)のコールバック */\r\n onEvent?: (event: TreeEvent) => void\r\n /** ファイルをダブルクリックで開いた際のコールバック */\r\n onOpen?: (path: string) => void\r\n /** ノードアイコンのカスタムレンダラー */\r\n renderIcon?: (node: TreeNode, isExpanded: boolean) => React.ReactNode\r\n /** ノード右端に表示するバッジのカスタムレンダラー */\r\n renderBadge?: (node: TreeNode) => React.ReactNode\r\n /** 右クリックメニューの項目を返す関数。選択中ノード群が渡される */\r\n contextMenuItems?: (nodes: TreeNode[]) => MenuItemDef[]\r\n /** ツリーフィルタバーを表示するか */\r\n showFilterBar?: boolean\r\n /** コントローラの参照を受け取るコールバック(QuickOpen等で使用) */\r\n onControllerReady?: (controller: FileTreeController) => void\r\n /** momoi-keybindのInputServiceインスタンス。キーバインドを有効化する */\r\n inputService?: InputServiceLike | null\r\n /** momoi-keybindを使わない場合のキーボードイベントハンドラ */\r\n onKeyDown?: (e: React.KeyboardEvent) => void\r\n /** ルート要素に付与するCSSクラス */\r\n className?: string\r\n /** ルート要素に付与するインラインスタイル */\r\n style?: React.CSSProperties\r\n}\r\n\r\n/** 新規作成行のアイテム型 */\r\ninterface CreateRowItem {\r\n type: 'create'\r\n parentPath: string\r\n isDirectory: boolean\r\n depth: number\r\n}\r\n\r\n/** 通常ノード行のアイテム型 */\r\ninterface NodeRowItem {\r\n type: 'node'\r\n node: TreeNode\r\n depth: number\r\n}\r\n\r\ntype RowItem = NodeRowItem | CreateRowItem\r\n\r\nfunction FileExplorerInner({\r\n onOpen,\r\n renderIcon,\r\n renderBadge,\r\n contextMenuItems,\r\n showFilterBar,\r\n onControllerReady,\r\n inputService,\r\n onKeyDown,\r\n}: Pick<FileExplorerProps, 'onOpen' | 'renderIcon' | 'renderBadge' | 'contextMenuItems' | 'showFilterBar' | 'onControllerReady' | 'inputService' | 'onKeyDown'>): React.JSX.Element {\r\n const { flatList, expandedPaths, selectedPaths, renamingPath, creatingState, rootPath, controller } = useFileTree()\r\n\r\n useEffect(() => {\r\n onControllerReady?.(controller)\r\n }, [controller, onControllerReady])\r\n\r\n // momoi-keybind接続\r\n useExplorerKeybindings(inputService ?? null)\r\n const focusProps = useExplorerFocus(inputService ?? null)\r\n\r\n const ctxMenu = useContextMenu()\r\n\r\n // flatListに新規作成行を挿入したリストを生成\r\n const rowItems = useMemo<RowItem[]>(() => {\r\n const items: RowItem[] = flatList.map((f) => ({\r\n type: 'node' as const,\r\n node: f.node,\r\n depth: f.depth,\r\n }))\r\n\r\n if (!creatingState) return items\r\n\r\n const { parentPath, isDirectory, insertAfterPath } = creatingState\r\n\r\n if (insertAfterPath) {\r\n // 指定ノードの直後に挿入(ファイル選択時のNew File)\r\n const idx = items.findIndex((item) => item.type === 'node' && (item as NodeRowItem).node.path === insertAfterPath)\r\n if (idx !== -1) {\r\n items.splice(idx + 1, 0, { type: 'create', parentPath, isDirectory, depth: items[idx].depth })\r\n }\r\n } else if (parentPath === rootPath) {\r\n // ルート末尾に挿入(選択なし時)\r\n items.push({ type: 'create', parentPath, isDirectory, depth: 0 })\r\n } else {\r\n // 親フォルダの子の先頭に挿入(フォルダ選択時)\r\n const parentIdx = items.findIndex((item) => item.type === 'node' && (item as NodeRowItem).node.path === parentPath)\r\n if (parentIdx !== -1) {\r\n const parentDepth = items[parentIdx].depth\r\n items.splice(parentIdx + 1, 0, { type: 'create', parentPath, isDirectory, depth: parentDepth + 1 })\r\n }\r\n }\r\n\r\n return items\r\n }, [flatList, creatingState, rootPath])\r\n\r\n const handleClick = useCallback((path: string, isDirectory: boolean, e: React.MouseEvent) => {\r\n if (e.shiftKey) {\r\n controller.select(path, 'range')\r\n } else if (e.ctrlKey || e.metaKey) {\r\n controller.select(path, 'toggle')\r\n } else {\r\n controller.select(path, 'replace')\r\n // シングルクリックでフォルダ展開/折りたたみ(VSCode方式)\r\n if (isDirectory) {\r\n controller.toggleExpand(path)\r\n }\r\n }\r\n }, [controller])\r\n\r\n const handleDoubleClick = useCallback((path: string, isDirectory: boolean) => {\r\n // ダブルクリックはファイルを開くだけ(フォルダは無視)\r\n if (!isDirectory) {\r\n onOpen?.(path)\r\n }\r\n }, [onOpen])\r\n\r\n const handleContextMenu = useCallback((e: React.MouseEvent, path: string) => {\r\n if (!selectedPaths.has(path)) {\r\n controller.select(path, 'replace')\r\n }\r\n ctxMenu.show(e, path)\r\n }, [controller, selectedPaths, ctxMenu])\r\n\r\n // 空白エリアの右クリック(nodes=[]で呼ばれる)\r\n const handleBackgroundContextMenu = useCallback((e: React.MouseEvent) => {\r\n e.preventDefault()\r\n controller.clearSelection()\r\n ctxMenu.show(e, '')\r\n }, [controller, ctxMenu])\r\n\r\n const menuItems = useMemo(() => {\r\n if (!ctxMenu.isVisible || !contextMenuItems) return []\r\n // targetPath が空 = 空白エリアクリック → nodes=[]\r\n if (ctxMenu.targetPath === '') return contextMenuItems([])\r\n const targetNodes = flatList\r\n .filter((f) => selectedPaths.has(f.node.path))\r\n .map((f) => f.node)\r\n return contextMenuItems(targetNodes)\r\n }, [ctxMenu.isVisible, ctxMenu.targetPath, contextMenuItems, flatList, selectedPaths])\r\n\r\n return (\r\n <div\r\n style={{ height: '100%', outline: 'none' }}\r\n onContextMenu={handleBackgroundContextMenu}\r\n onKeyDown={onKeyDown}\r\n onFocus={focusProps.onFocus}\r\n onBlur={focusProps.onBlur}\r\n tabIndex={focusProps.tabIndex}\r\n >\r\n {showFilterBar && <TreeFilterBar />}\r\n <Virtuoso\r\n totalCount={rowItems.length}\r\n fixedItemHeight={22}\r\n increaseViewportBy={200}\r\n computeItemKey={(index) => {\r\n const item = rowItems[index]\r\n return item.type === 'create' ? `__create__${item.parentPath}` : item.node.path\r\n }}\r\n itemContent={(index) => {\r\n const item = rowItems[index]\r\n\r\n if (item.type === 'create') {\r\n return (\r\n <div className=\"momoi-explorer-row\">\r\n {/* TreeNodeRowと同じインデント構造 */}\r\n <span className=\"momoi-explorer-indent\">\r\n {Array.from({ length: item.depth }, (_, i) => (\r\n <span key={i} className=\"momoi-explorer-indent-guide\" />\r\n ))}\r\n </span>\r\n <span className=\"momoi-explorer-chevron\" data-is-dir=\"false\">\r\n <svg viewBox=\"0 0 16 16\"><path d=\"M6 4l4 4-4 4\" stroke=\"currentColor\" strokeWidth=\"1.5\" fill=\"none\" /></svg>\r\n </span>\r\n <span className=\"momoi-explorer-icon\">\r\n {item.isDirectory ? '📁' : '📄'}\r\n </span>\r\n <InlineRename\r\n currentName=\"\"\r\n onCommit={(name) => controller.commitCreate(name)}\r\n onCancel={() => controller.cancelCreate()}\r\n />\r\n </div>\r\n )\r\n }\r\n\r\n const { node, depth } = item\r\n return (\r\n <TreeNodeRow\r\n node={node}\r\n depth={depth}\r\n isExpanded={expandedPaths.has(node.path)}\r\n isSelected={selectedPaths.has(node.path)}\r\n isRenaming={renamingPath === node.path}\r\n onClick={(e) => handleClick(node.path, node.isDirectory, e)}\r\n onDoubleClick={() => handleDoubleClick(node.path, node.isDirectory)}\r\n onContextMenu={(e) => handleContextMenu(e, node.path)}\r\n onToggleExpand={() => controller.toggleExpand(node.path)}\r\n onCommitRename={(name) => controller.commitRename(name)}\r\n onCancelRename={() => controller.cancelRename()}\r\n renderIcon={renderIcon}\r\n renderBadge={renderBadge}\r\n />\r\n )\r\n }}\r\n />\r\n {ctxMenu.isVisible && menuItems.length > 0 && (\r\n <ContextMenu\r\n items={menuItems}\r\n x={ctxMenu.x}\r\n y={ctxMenu.y}\r\n onClose={ctxMenu.hide}\r\n />\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * TreeProvider を内包するオールインワンのファイルエクスプローラーコンポーネント。\r\n * これ単体でファイルツリーUIが動作する。仮想スクロール対応。\r\n *\r\n * @example\r\n * ```tsx\r\n * import { FileExplorer } from 'momoi-explorer/ui'\r\n * import 'momoi-explorer/ui/style.css'\r\n *\r\n * <FileExplorer\r\n * adapter={myAdapter}\r\n * rootPath=\"/home/user/project\"\r\n * onOpen={(path) => openFile(path)}\r\n * />\r\n * ```\r\n */\r\nexport function FileExplorer({\r\n adapter,\r\n rootPath,\r\n sort,\r\n filter,\r\n watchOptions,\r\n onEvent,\r\n onOpen,\r\n renderIcon,\r\n renderBadge,\r\n contextMenuItems,\r\n showFilterBar,\r\n onControllerReady,\r\n inputService,\r\n onKeyDown,\r\n className,\r\n style,\r\n}: FileExplorerProps): React.JSX.Element {\r\n return (\r\n <div className={`momoi-explorer ${className ?? ''}`} style={style}>\r\n <TreeProvider\r\n adapter={adapter}\r\n rootPath={rootPath}\r\n sort={sort}\r\n filter={filter}\r\n watchOptions={watchOptions}\r\n onEvent={onEvent}\r\n >\r\n <FileExplorerInner\r\n onOpen={onOpen}\r\n renderIcon={renderIcon}\r\n renderBadge={renderBadge}\r\n contextMenuItems={contextMenuItems}\r\n showFilterBar={showFilterBar}\r\n onControllerReady={onControllerReady}\r\n inputService={inputService}\r\n onKeyDown={onKeyDown}\r\n />\r\n </TreeProvider>\r\n </div>\r\n )\r\n}\r\n","import type React from 'react'\r\nimport { useEffect, useMemo, useRef, useState } from 'react'\r\nimport type { FileSystemAdapter, FileTreeController, FileTreeOptions, TreeEvent, TreeState } from '../core/types'\r\nimport { createFileTree } from '../core/tree'\r\nimport { TreeContext } from './context'\r\nimport type { ReactNode } from 'react'\r\n\r\n/** {@link TreeProvider} に渡すprops */\r\nexport interface TreeProviderProps {\r\n /** ファイルシステム操作の実装 */\r\n adapter: FileSystemAdapter\r\n /** ツリーのルートディレクトリパス */\r\n rootPath: string\r\n /** ファイル/フォルダのソート関数 */\r\n sort?: FileTreeOptions['sort']\r\n /** 表示対象を絞り込むフィルタ関数 */\r\n filter?: FileTreeOptions['filter']\r\n /** ファイル監視の設定 */\r\n watchOptions?: FileTreeOptions['watchOptions']\r\n /** ツリー操作イベントのコールバック */\r\n onEvent?: (event: TreeEvent) => void\r\n children: ReactNode\r\n}\r\n\r\n/**\r\n * ファイルツリーのコンテキストプロバイダー。\r\n * 内部で `createFileTree` を呼び出し、マウント時に `loadRoot` でルートを読み込む。\r\n * 子コンポーネントから `useFileTree` / `useTreeNode` でツリー状態にアクセスできる。\r\n */\r\nexport function TreeProvider({\r\n adapter,\r\n rootPath,\r\n sort,\r\n filter,\r\n watchOptions,\r\n onEvent,\r\n children,\r\n}: TreeProviderProps): React.JSX.Element {\r\n const onEventRef = useRef(onEvent)\r\n onEventRef.current = onEvent\r\n\r\n const controller = useMemo<FileTreeController>(() => {\r\n return createFileTree({\r\n adapter,\r\n rootPath,\r\n sort,\r\n filter,\r\n watchOptions,\r\n onEvent: (event) => onEventRef.current?.(event),\r\n })\r\n }, [adapter, rootPath])\r\n\r\n const [state, setState] = useState<TreeState>(() => controller.getState())\r\n\r\n useEffect(() => {\r\n const unsub = controller.subscribe(setState)\r\n controller.loadRoot()\r\n return () => {\r\n unsub()\r\n controller.destroy()\r\n }\r\n }, [controller])\r\n\r\n const value = useMemo(() => ({ controller, state }), [controller, state])\r\n\r\n return (\r\n <TreeContext.Provider value={value}>\r\n {children}\r\n </TreeContext.Provider>\r\n )\r\n}\r\n","// イベント処理ユーティリティ\r\n//\r\n// VSCode準拠のデバウンス・イベント合体・スロットリング\r\n\r\nimport type { RawWatchEvent, WatchEvent, WatchOptions } from './types'\r\n\r\nconst DEFAULT_DEBOUNCE_MS = 75\r\nconst DEFAULT_THROTTLE_CHUNK_SIZE = 500\r\nconst DEFAULT_THROTTLE_DELAY_MS = 200\r\n\r\n/**\r\n * 生イベントを合体する(VSCode EventCoalescer 準拠)。\r\n * - rename → delete(old) + create(new) に分解\r\n * - delete + create(同一パス) → modify に合体\r\n * - create + modify(同一パス) → create を維持\r\n * - 親フォルダ delete → 子の delete を除去\r\n *\r\n * @param raw - アダプタから受け取った生イベントの配列\r\n * @returns 合体処理後のWatchEvent配列\r\n */\r\nexport function coalesceEvents(raw: RawWatchEvent[]): WatchEvent[] {\r\n // rename を分解\r\n const expanded: WatchEvent[] = []\r\n for (const event of raw) {\r\n if (event.type === 'rename' && event.newPath) {\r\n expanded.push({ type: 'delete', path: event.path, isDirectory: event.isDirectory })\r\n expanded.push({ type: 'create', path: event.newPath, isDirectory: event.isDirectory })\r\n } else {\r\n expanded.push({ type: event.type as WatchEvent['type'], path: event.path, isDirectory: event.isDirectory })\r\n }\r\n }\r\n\r\n // 同一パスのイベントを合体\r\n const byPath = new Map<string, WatchEvent>()\r\n for (const event of expanded) {\r\n const existing = byPath.get(event.path)\r\n if (!existing) {\r\n byPath.set(event.path, event)\r\n continue\r\n }\r\n\r\n // delete + create → modify\r\n if (existing.type === 'delete' && event.type === 'create') {\r\n byPath.set(event.path, { type: 'modify', path: event.path, isDirectory: event.isDirectory })\r\n continue\r\n }\r\n\r\n // create + modify → create を維持\r\n if (existing.type === 'create' && event.type === 'modify') {\r\n continue\r\n }\r\n\r\n // create + delete → 相殺して除去\r\n if (existing.type === 'create' && event.type === 'delete') {\r\n byPath.delete(event.path)\r\n continue\r\n }\r\n\r\n // それ以外は後勝ち\r\n byPath.set(event.path, event)\r\n }\r\n\r\n const result = Array.from(byPath.values())\r\n\r\n // 親フォルダ delete がある場合、子の delete を除去\r\n const deletedDirs = new Set<string>()\r\n for (const event of result) {\r\n if (event.type === 'delete' && event.isDirectory) {\r\n deletedDirs.add(event.path)\r\n }\r\n }\r\n\r\n if (deletedDirs.size === 0) return result\r\n\r\n return result.filter((event) => {\r\n if (event.type !== 'delete') return true\r\n for (const dir of deletedDirs) {\r\n if (event.path !== dir && event.path.startsWith(dir + '/')) {\r\n return false\r\n }\r\n }\r\n return true\r\n })\r\n}\r\n\r\n/**\r\n * イベントプロセッサを生成する。\r\n * デバウンス → 合体 → スロットリング → コールバック のパイプラインで処理する。\r\n *\r\n * @param callback - 処理済みイベントを受け取るコールバック\r\n * @param options - デバウンス・合体・スロットリングの設定\r\n * @returns push/flush/destroyメソッドを持つプロセッサオブジェクト\r\n */\r\nexport function createEventProcessor(\r\n callback: (events: WatchEvent[]) => void,\r\n options: WatchOptions = {},\r\n): {\r\n push(events: RawWatchEvent[]): void\r\n flush(): void\r\n destroy(): void\r\n} {\r\n const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS\r\n const shouldCoalesce = options.coalesce ?? true\r\n const throttleChunkSize = options.throttle?.maxChunkSize ?? DEFAULT_THROTTLE_CHUNK_SIZE\r\n const throttleDelayMs = options.throttle?.delayMs ?? DEFAULT_THROTTLE_DELAY_MS\r\n\r\n let buffer: RawWatchEvent[] = []\r\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\r\n let throttleTimer: ReturnType<typeof setTimeout> | null = null\r\n let destroyed = false\r\n\r\n function processBuffer(): void {\r\n if (destroyed || buffer.length === 0) return\r\n\r\n const raw = buffer\r\n buffer = []\r\n\r\n const events = shouldCoalesce ? coalesceEvents(raw) : raw.map((e) => ({\r\n type: e.type === 'rename' ? 'modify' as const : e.type as WatchEvent['type'],\r\n path: e.type === 'rename' && e.newPath ? e.newPath : e.path,\r\n isDirectory: e.isDirectory,\r\n }))\r\n\r\n if (events.length === 0) return\r\n\r\n // スロットリング: 大量イベントをチャンクに分割\r\n if (events.length <= throttleChunkSize) {\r\n callback(events)\r\n return\r\n }\r\n\r\n let offset = 0\r\n function emitChunk(): void {\r\n if (destroyed || offset >= events.length) return\r\n const chunk = events.slice(offset, offset + throttleChunkSize)\r\n offset += throttleChunkSize\r\n callback(chunk)\r\n if (offset < events.length) {\r\n throttleTimer = setTimeout(emitChunk, throttleDelayMs)\r\n }\r\n }\r\n emitChunk()\r\n }\r\n\r\n return {\r\n push(events: RawWatchEvent[]): void {\r\n if (destroyed) return\r\n buffer.push(...events)\r\n if (debounceTimer !== null) {\r\n clearTimeout(debounceTimer)\r\n }\r\n debounceTimer = setTimeout(processBuffer, debounceMs)\r\n },\r\n\r\n flush(): void {\r\n if (debounceTimer !== null) {\r\n clearTimeout(debounceTimer)\r\n debounceTimer = null\r\n }\r\n processBuffer()\r\n },\r\n\r\n destroy(): void {\r\n destroyed = true\r\n if (debounceTimer !== null) clearTimeout(debounceTimer)\r\n if (throttleTimer !== null) clearTimeout(throttleTimer)\r\n buffer = []\r\n },\r\n }\r\n}\r\n","// ツリー → フラットリスト変換(仮想スクロール用)\n\nimport type { FlatNode, TreeNode } from './types'\n\n/**\n * 展開されたツリーをフラットリストに変換する。\n * react-virtuoso等の仮想スクロールに渡すためのもの。\n * matchingPaths が指定された場合、そこに含まれるノードのみ表示する。\n */\nexport function flattenTree(\n nodes: TreeNode[],\n expandedPaths: Set<string>,\n matchingPaths?: Set<string> | null,\n): FlatNode[] {\n const result: FlatNode[] = []\n\n function walk(children: TreeNode[], depth: number): void {\n for (const node of children) {\n if (matchingPaths && !matchingPaths.has(node.path)) continue\n\n result.push({ node, depth })\n if (node.isDirectory && node.children) {\n // 検索中はマッチしたディレクトリを自動展開\n if (matchingPaths || expandedPaths.has(node.path)) {\n walk(node.children, depth + 1)\n }\n }\n }\n }\n\n walk(nodes, 0)\n return result\n}\n","// 選択管理(単一/複数/範囲)\n\nimport type { FlatNode } from './types'\n\n/**\n * replace: 既存選択をクリアして新しいパスのみ選択\n * toggle: 指定パスの選択を反転(Ctrl+Click)\n * range: anchorから指定パスまでの範囲を選択(Shift+Click)\n */\nexport function computeSelection(\n currentSelected: Set<string>,\n anchorPath: string | null,\n targetPath: string,\n mode: 'replace' | 'toggle' | 'range',\n flatList: FlatNode[],\n): { selectedPaths: Set<string>; anchorPath: string } {\n switch (mode) {\n case 'replace':\n return {\n selectedPaths: new Set([targetPath]),\n anchorPath: targetPath,\n }\n\n case 'toggle': {\n const next = new Set(currentSelected)\n if (next.has(targetPath)) {\n next.delete(targetPath)\n } else {\n next.add(targetPath)\n }\n return {\n selectedPaths: next,\n anchorPath: targetPath,\n }\n }\n\n case 'range': {\n if (!anchorPath) {\n return {\n selectedPaths: new Set([targetPath]),\n anchorPath: targetPath,\n }\n }\n\n const paths = flatList.map((f) => f.node.path)\n const anchorIdx = paths.indexOf(anchorPath)\n const targetIdx = paths.indexOf(targetPath)\n\n if (anchorIdx === -1 || targetIdx === -1) {\n return {\n selectedPaths: new Set([targetPath]),\n anchorPath: targetPath,\n }\n }\n\n const start = Math.min(anchorIdx, targetIdx)\n const end = Math.max(anchorIdx, targetIdx)\n const rangePaths = new Set(paths.slice(start, end + 1))\n\n return {\n selectedPaths: rangePaths,\n anchorPath, // range選択ではanchorは変えない\n }\n }\n }\n}\n","// ソート\n\nimport type { FileEntry } from './types'\n\n/**\n * デフォルトソート: フォルダ優先 → 名前の大文字小文字無視で昇順\n */\nexport function defaultSort(a: FileEntry, b: FileEntry): number {\n if (a.isDirectory !== b.isDirectory) {\n return a.isDirectory ? -1 : 1\n }\n return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })\n}\n","// フィルタ\n\nimport type { FileEntry } from './types'\n\n/**\n * デフォルトフィルタ: 全表示(フィルタなし)\n */\nexport function defaultFilter(_entry: FileEntry): boolean {\n return true\n}\n","// ファイル名検索ユーティリティ\n\nimport type { FileEntry, TreeNode } from './types'\n\n/**\n * ファジーマッチ: クエリの各文字が順番に含まれているかチェック\n * スコアも返す(連続マッチ・先頭マッチ・セパレータ後マッチが高スコア)\n */\nexport function fuzzyMatch(query: string, target: string): { match: boolean; score: number } {\n const q = query.toLowerCase()\n const t = target.toLowerCase()\n\n if (q.length === 0) return { match: true, score: 0 }\n if (q.length > t.length) return { match: false, score: 0 }\n\n // 完全一致は最高スコア\n if (t === q) return { match: true, score: 100 }\n\n // 前方一致は高スコア\n if (t.startsWith(q)) return { match: true, score: 90 }\n\n // 部分一致\n if (t.includes(q)) return { match: true, score: 80 }\n\n // ファジーマッチ\n let qi = 0\n let score = 0\n let lastMatchIndex = -2\n\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) {\n qi++\n // 連続マッチボーナス\n if (ti === lastMatchIndex + 1) {\n score += 5\n }\n // セパレータ直後のマッチボーナス(パス区切り、ハイフン、アンダースコア等)\n if (ti === 0 || '/\\\\-_.'.includes(t[ti - 1])) {\n score += 10\n }\n score += 1\n lastMatchIndex = ti\n }\n }\n\n if (qi < q.length) return { match: false, score: 0 }\n return { match: true, score }\n}\n\n/**\n * ツリーフィルタ用: クエリにマッチするノードとその祖先を残す\n * マッチしたパスのSetを返す\n */\nexport function findMatchingPaths(\n nodes: TreeNode[],\n query: string,\n): Set<string> {\n const matching = new Set<string>()\n\n function walk(node: TreeNode, ancestors: string[]): boolean {\n const nameMatch = fuzzyMatch(query, node.name).match\n let childMatch = false\n\n if (node.children) {\n for (const child of node.children) {\n if (walk(child, [...ancestors, node.path])) {\n childMatch = true\n }\n }\n }\n\n if (nameMatch || childMatch) {\n matching.add(node.path)\n for (const a of ancestors) {\n matching.add(a)\n }\n return true\n }\n return false\n }\n\n for (const node of nodes) {\n walk(node, [])\n }\n\n return matching\n}\n\n/**\n * ファジーファインド用: 全ファイルからスコア順に候補を返す\n */\nexport function fuzzyFind(\n files: FileEntry[],\n query: string,\n maxResults: number = 50,\n): FileEntry[] {\n if (!query) return []\n\n const scored: Array<{ entry: FileEntry; score: number }> = []\n\n for (const entry of files) {\n // ファイル名でマッチ\n const nameResult = fuzzyMatch(query, entry.name)\n // パスでもマッチ(スコアは低め)\n const pathResult = fuzzyMatch(query, entry.path)\n\n const bestScore = Math.max(nameResult.score, pathResult.score * 0.5)\n\n if (nameResult.match || pathResult.match) {\n scored.push({ entry, score: bestScore })\n }\n }\n\n scored.sort((a, b) => b.score - a.score)\n return scored.slice(0, maxResults).map((s) => s.entry)\n}\n","// createFileTree - ヘッドレスファイルツリーコントローラ\r\n\r\nimport type {\r\n FileEntry,\r\n FileSystemAdapter,\r\n FileTreeController,\r\n FileTreeOptions,\r\n FlatNode,\r\n TreeEvent,\r\n TreeNode,\r\n TreeState,\r\n WatchEvent,\r\n} from './types'\r\nimport { createEventProcessor } from './event-processor'\r\nimport { flattenTree } from './flatten'\r\nimport { computeSelection } from './selection'\r\nimport { defaultSort } from './sort'\r\nimport { defaultFilter } from './filter'\r\nimport { findMatchingPaths } from './search'\r\n\r\nfunction toTreeNode(entry: FileEntry, depth: number): TreeNode {\r\n return {\r\n ...entry,\r\n depth,\r\n children: entry.isDirectory ? undefined : undefined,\r\n childrenLoaded: false,\r\n }\r\n}\r\n\r\nfunction findNode(nodes: TreeNode[], path: string): TreeNode | undefined {\r\n for (const node of nodes) {\r\n if (node.path === path) return node\r\n if (node.children) {\r\n const found = findNode(node.children, path)\r\n if (found) return found\r\n }\r\n }\r\n return undefined\r\n}\r\n\r\nfunction findParentNodes(nodes: TreeNode[], targetPath: string): TreeNode | undefined {\r\n for (const node of nodes) {\r\n if (node.children) {\r\n for (const child of node.children) {\r\n if (child.path === targetPath) return node\r\n }\r\n const found = findParentNodes(node.children, targetPath)\r\n if (found) return found\r\n }\r\n }\r\n return undefined\r\n}\r\n\r\n/** パスの親ディレクトリを取得 */\r\nfunction dirname(path: string): string {\r\n const sep = path.includes('\\\\') ? '\\\\' : '/'\r\n const idx = path.lastIndexOf(sep)\r\n return idx === -1 ? '' : path.slice(0, idx)\r\n}\r\n\r\n/** パスの末尾(ファイル名)を取得 */\r\nfunction basename(path: string): string {\r\n const sep = path.includes('\\\\') ? '\\\\' : '/'\r\n const idx = path.lastIndexOf(sep)\r\n return idx === -1 ? path : path.slice(idx + 1)\r\n}\r\n\r\n/**\r\n * ヘッドレスファイルツリーコントローラを生成する。\r\n * フレームワーク非依存。React等で使う場合は `momoi-explorer/react` のTreeProviderを推奨。\r\n *\r\n * @param options - ツリーの初期化オプション\r\n * @returns FileTreeController インスタンス\r\n *\r\n * @example\r\n * ```ts\r\n * import { createFileTree } from 'momoi-explorer'\r\n *\r\n * const tree = createFileTree({\r\n * adapter: myAdapter,\r\n * rootPath: '/home/user/project',\r\n * onEvent: (e) => console.log(e),\r\n * })\r\n * await tree.loadRoot()\r\n * ```\r\n */\r\nexport function createFileTree(options: FileTreeOptions): FileTreeController {\r\n const { adapter, rootPath, onEvent } = options\r\n let sortFn = options.sort ?? defaultSort\r\n let filterFn = options.filter ?? defaultFilter\r\n\r\n let state: TreeState = {\r\n rootPath,\r\n rootNodes: [],\r\n expandedPaths: new Set(),\r\n selectedPaths: new Set(),\r\n anchorPath: null,\r\n renamingPath: null,\r\n creatingState: null,\r\n searchQuery: null,\r\n flatList: [],\r\n }\r\n\r\n const listeners = new Set<(state: TreeState) => void>()\r\n let expandingPaths = new Set<string>()\r\n\r\n function emit(event: TreeEvent): void {\r\n onEvent?.(event)\r\n }\r\n\r\n function notify(): void {\r\n const matchingPaths = state.searchQuery\r\n ? findMatchingPaths(state.rootNodes, state.searchQuery)\r\n : null\r\n state = { ...state, flatList: flattenTree(state.rootNodes, state.expandedPaths, matchingPaths) }\r\n for (const listener of listeners) {\r\n listener(state)\r\n }\r\n }\r\n\r\n async function loadChildren(node: TreeNode): Promise<void> {\r\n const entries = await adapter.readDir(node.path)\r\n const filtered = entries.filter(filterFn)\r\n filtered.sort(sortFn)\r\n // 既存の展開済み子ノードのchildrenを引き継ぐ\r\n const oldChildMap = node.children\r\n ? new Map(node.children.map((c) => [c.path, c]))\r\n : new Map<string, TreeNode>()\r\n node.children = filtered.map((e) => {\r\n const existing = oldChildMap.get(e.path)\r\n if (existing && existing.childrenLoaded) {\r\n return { ...toTreeNode(e, node.depth + 1), children: existing.children, childrenLoaded: true }\r\n }\r\n return toTreeNode(e, node.depth + 1)\r\n })\r\n node.childrenLoaded = true\r\n }\r\n\r\n /** 親ディレクトリをリフレッシュし、展開中のフォルダの子も再読み込みする */\r\n async function refreshParent(parentPath: string): Promise<void> {\r\n const parentNode = findNode(state.rootNodes, parentPath)\r\n if (parentNode) {\r\n await loadChildren(parentNode)\r\n state.expandedPaths = new Set(state.expandedPaths)\r\n state.expandedPaths.add(parentPath)\r\n } else if (parentPath === rootPath) {\r\n const entries = await adapter.readDir(rootPath)\r\n const filtered = entries.filter(filterFn)\r\n filtered.sort(sortFn)\r\n // 既存の展開済みノードのchildrenを引き継ぐ\r\n const oldNodeMap = new Map(state.rootNodes.map((n) => [n.path, n]))\r\n state.rootNodes = filtered.map((e) => {\r\n const existing = oldNodeMap.get(e.path)\r\n if (existing && existing.childrenLoaded) {\r\n return { ...toTreeNode(e, 0), children: existing.children, childrenLoaded: true }\r\n }\r\n return toTreeNode(e, 0)\r\n })\r\n }\r\n }\r\n\r\n function sortNodes(nodes: TreeNode[]): void {\r\n nodes.sort(sortFn)\r\n for (const node of nodes) {\r\n if (node.children) {\r\n sortNodes(node.children)\r\n }\r\n }\r\n }\r\n\r\n function filterNodes(nodes: TreeNode[]): TreeNode[] {\r\n return nodes.filter((node) => {\r\n if (!filterFn(node)) return false\r\n if (node.children) {\r\n node.children = filterNodes(node.children)\r\n }\r\n return true\r\n })\r\n }\r\n\r\n // ウォッチ関連\r\n let unwatchFn: (() => void) | null = null\r\n let eventProcessor: ReturnType<typeof createEventProcessor> | null = null\r\n\r\n function handleWatchEvents(events: WatchEvent[]): void {\r\n emit({ type: 'external-change', changes: events })\r\n\r\n // 変更されたパスの親ディレクトリを収集してリフレッシュ\r\n const dirsToRefresh = new Set<string>()\r\n for (const event of events) {\r\n const parent = dirname(event.path)\r\n // 展開中のディレクトリのみリフレッシュ\r\n if (parent === rootPath || state.expandedPaths.has(parent)) {\r\n dirsToRefresh.add(parent)\r\n }\r\n // ディレクトリ自体が変更された場合、展開中ならそれもリフレッシュ\r\n if (event.isDirectory && state.expandedPaths.has(event.path)) {\r\n dirsToRefresh.add(event.path)\r\n }\r\n }\r\n\r\n // 非同期でリフレッシュ(展開状態を保持)\r\n for (const dir of dirsToRefresh) {\r\n refreshParent(dir).then(() => notify()).catch(() => {})\r\n }\r\n }\r\n\r\n function startWatching(): void {\r\n if (!adapter.watch) return\r\n\r\n eventProcessor = createEventProcessor(handleWatchEvents, options.watchOptions)\r\n unwatchFn = adapter.watch(rootPath, (events) => {\r\n eventProcessor!.push(events)\r\n })\r\n }\r\n\r\n function stopWatching(): void {\r\n if (unwatchFn) {\r\n unwatchFn()\r\n unwatchFn = null\r\n }\r\n if (eventProcessor) {\r\n eventProcessor.destroy()\r\n eventProcessor = null\r\n }\r\n }\r\n\r\n const controller: FileTreeController = {\r\n getState(): TreeState {\r\n return state\r\n },\r\n\r\n subscribe(listener: (s: TreeState) => void): () => void {\r\n listeners.add(listener)\r\n return () => listeners.delete(listener)\r\n },\r\n\r\n async loadRoot(): Promise<void> {\r\n const entries = await adapter.readDir(rootPath)\r\n const filtered = entries.filter(filterFn)\r\n filtered.sort(sortFn)\r\n state.rootNodes = filtered.map((e) => toTreeNode(e, 0))\r\n notify()\r\n startWatching()\r\n },\r\n\r\n async expand(path: string): Promise<void> {\r\n // 再入ガード: 同じパスの展開処理が進行中なら無視\r\n if (expandingPaths.has(path)) return\r\n expandingPaths.add(path)\r\n\r\n try {\r\n const node = findNode(state.rootNodes, path)\r\n if (!node || !node.isDirectory) return\r\n\r\n if (!node.childrenLoaded) {\r\n await loadChildren(node)\r\n }\r\n\r\n // await後にstateが変わっている可能性があるので再確認\r\n state.expandedPaths = new Set(state.expandedPaths)\r\n state.expandedPaths.add(path)\r\n notify()\r\n emit({ type: 'expand', path })\r\n } finally {\r\n expandingPaths.delete(path)\r\n }\r\n },\r\n\r\n collapse(path: string): void {\r\n const sep = path.includes('\\\\') ? '\\\\' : '/'\r\n const prefix = path + sep\r\n state.expandedPaths = new Set(state.expandedPaths)\r\n state.expandedPaths.delete(path)\r\n // 子孫の展開状態もクリア\r\n for (const p of state.expandedPaths) {\r\n if (p.startsWith(prefix)) {\r\n state.expandedPaths.delete(p)\r\n }\r\n }\r\n notify()\r\n emit({ type: 'collapse', path })\r\n },\r\n\r\n async toggleExpand(path: string): Promise<void> {\r\n // expand進行中は無視(ダブルクリックで展開→即collapseを防止)\r\n if (expandingPaths.has(path)) return\r\n\r\n if (state.expandedPaths.has(path)) {\r\n controller.collapse(path)\r\n } else {\r\n await controller.expand(path)\r\n }\r\n },\r\n\r\n async expandTo(path: string): Promise<void> {\r\n // パスの各祖先を展開していく\r\n const parts: string[] = []\r\n let current = path\r\n while (current !== rootPath && current !== '') {\r\n const parent = dirname(current)\r\n if (parent === current) break\r\n parts.unshift(parent)\r\n current = parent\r\n }\r\n\r\n for (const ancestorPath of parts) {\r\n if (ancestorPath === rootPath) continue\r\n if (!state.expandedPaths.has(ancestorPath)) {\r\n await controller.expand(ancestorPath)\r\n }\r\n }\r\n },\r\n\r\n select(path: string, mode: 'replace' | 'toggle' | 'range' = 'replace'): void {\r\n const result = computeSelection(\r\n state.selectedPaths,\r\n state.anchorPath,\r\n path,\r\n mode,\r\n state.flatList,\r\n )\r\n state.selectedPaths = result.selectedPaths\r\n state.anchorPath = result.anchorPath\r\n notify()\r\n emit({ type: 'select', paths: Array.from(result.selectedPaths) })\r\n },\r\n\r\n selectAll(): void {\r\n state.selectedPaths = new Set(state.flatList.map((f) => f.node.path))\r\n notify()\r\n emit({ type: 'select', paths: Array.from(state.selectedPaths) })\r\n },\r\n\r\n clearSelection(): void {\r\n state.selectedPaths = new Set()\r\n state.anchorPath = null\r\n notify()\r\n emit({ type: 'select', paths: [] })\r\n },\r\n\r\n startRename(path: string): void {\r\n state.renamingPath = path\r\n notify()\r\n },\r\n\r\n async commitRename(newName: string): Promise<void> {\r\n if (!state.renamingPath || !adapter.rename) return\r\n\r\n const oldPath = state.renamingPath\r\n const parent = dirname(oldPath)\r\n const sep = oldPath.includes('\\\\') ? '\\\\' : '/'\r\n const newPath = parent + sep + newName\r\n\r\n await adapter.rename(oldPath, newPath)\r\n state.renamingPath = null\r\n\r\n // リネームされたノードの親をリフレッシュ\r\n if (parent === rootPath) {\r\n await controller.loadRoot()\r\n } else {\r\n const parentNode = findNode(state.rootNodes, parent)\r\n if (parentNode) {\r\n await loadChildren(parentNode)\r\n }\r\n }\r\n\r\n notify()\r\n emit({ type: 'rename', oldPath, newPath })\r\n },\r\n\r\n cancelRename(): void {\r\n state.renamingPath = null\r\n notify()\r\n },\r\n\r\n async startCreate(parentPath: string, isDirectory: boolean, insertAfterPath?: string): Promise<void> {\r\n // 親フォルダを展開してから作成モードに入る\r\n if (parentPath !== rootPath && !state.expandedPaths.has(parentPath)) {\r\n await controller.expand(parentPath)\r\n }\r\n state.creatingState = { parentPath, isDirectory, insertAfterPath }\r\n notify()\r\n },\r\n\r\n async commitCreate(name: string): Promise<void> {\r\n if (!state.creatingState) return\r\n\r\n const { parentPath, isDirectory } = state.creatingState\r\n state.creatingState = null\r\n\r\n if (isDirectory) {\r\n await controller.createDir(parentPath, name)\r\n } else {\r\n await controller.createFile(parentPath, name)\r\n }\r\n },\r\n\r\n cancelCreate(): void {\r\n state.creatingState = null\r\n notify()\r\n },\r\n\r\n async createFile(parentPath: string, name: string): Promise<void> {\r\n if (!adapter.createFile) return\r\n await adapter.createFile(parentPath, name)\r\n await refreshParent(parentPath)\r\n\r\n notify()\r\n emit({ type: 'create', parentPath, name, isDirectory: false })\r\n },\r\n\r\n async createDir(parentPath: string, name: string): Promise<void> {\r\n if (!adapter.createDir) return\r\n await adapter.createDir(parentPath, name)\r\n await refreshParent(parentPath)\r\n\r\n notify()\r\n emit({ type: 'create', parentPath, name, isDirectory: true })\r\n },\r\n\r\n async deleteSelected(): Promise<void> {\r\n if (!adapter.delete || state.selectedPaths.size === 0) return\r\n\r\n const paths = Array.from(state.selectedPaths)\r\n await adapter.delete(paths)\r\n\r\n state.selectedPaths = new Set()\r\n state.anchorPath = null\r\n\r\n // 影響を受ける親ディレクトリをリフレッシュ\r\n const parentDirs = new Set(paths.map(dirname))\r\n for (const dir of parentDirs) {\r\n await refreshParent(dir)\r\n }\r\n\r\n notify()\r\n emit({ type: 'delete', paths })\r\n },\r\n\r\n async refresh(path?: string): Promise<void> {\r\n if (!path || path === rootPath) {\r\n await refreshParent(rootPath)\r\n } else {\r\n const node = findNode(state.rootNodes, path)\r\n if (node && node.isDirectory) {\r\n await loadChildren(node)\r\n }\r\n }\r\n\r\n notify()\r\n emit({ type: 'refresh', path })\r\n },\r\n\r\n setSearchQuery(query: string | null): void {\r\n state.searchQuery = query && query.trim() ? query.trim() : null\r\n notify()\r\n },\r\n\r\n async collectAllFiles(): Promise<FileEntry[]> {\r\n const result: FileEntry[] = []\r\n\r\n async function walk(dirPath: string): Promise<void> {\r\n const entries = await adapter.readDir(dirPath)\r\n for (const entry of entries) {\r\n if (!filterFn(entry)) continue\r\n result.push(entry)\r\n if (entry.isDirectory) {\r\n await walk(entry.path)\r\n }\r\n }\r\n }\r\n\r\n await walk(rootPath)\r\n return result\r\n },\r\n\r\n setFilter(fn: ((entry: FileEntry) => boolean) | null): void {\r\n filterFn = fn ?? defaultFilter\r\n // 既に読み込み済みのノードを再フィルタ\r\n state.rootNodes = filterNodes(state.rootNodes)\r\n notify()\r\n },\r\n\r\n setSort(fn: ((a: FileEntry, b: FileEntry) => number) | null): void {\r\n sortFn = fn ?? defaultSort\r\n sortNodes(state.rootNodes)\r\n notify()\r\n },\r\n\r\n destroy(): void {\r\n stopWatching()\r\n listeners.clear()\r\n },\r\n }\r\n\r\n return controller\r\n}\r\n","import { createContext, useContext } from 'react'\r\nimport type { FileTreeController, TreeState } from '../core/types'\r\n\r\n/** TreeProvider が提供するコンテキスト値 */\r\nexport interface TreeContextValue {\r\n /** ツリー操作用コントローラ */\r\n controller: FileTreeController\r\n /** 現在のツリー状態 */\r\n state: TreeState\r\n}\r\n\r\n/** @internal ツリーコンテキスト。通常は直接使わず `useTreeContext` 経由で利用する */\r\nexport const TreeContext = createContext<TreeContextValue | null>(null)\r\n\r\n/**\r\n * TreeProvider のコンテキストを取得する。\r\n * TreeProvider の外で使用すると Error をスローする。\r\n * @returns ツリーのコントローラと状態\r\n */\r\nexport function useTreeContext(): TreeContextValue {\r\n const ctx = useContext(TreeContext)\r\n if (!ctx) {\r\n throw new Error('useTreeContext must be used within a <TreeProvider>')\r\n }\r\n return ctx\r\n}\r\n","import { useTreeContext } from './context'\r\nimport type { FileTreeController, TreeState } from '../core/types'\r\n\r\n/** {@link useFileTree} の戻り値。ツリー状態の全フィールドに加えコントローラを含む */\r\nexport interface UseFileTreeResult extends TreeState {\r\n /** ツリー操作用コントローラ */\r\n controller: FileTreeController\r\n}\r\n\r\n/**\r\n * ツリー全体の状態とコントローラを返すフック。\r\n * TreeProvider 内で使用すること。\r\n * @returns ツリー状態(flatList, expandedPaths 等)とコントローラ\r\n */\r\nexport function useFileTree(): UseFileTreeResult {\r\n const { controller, state } = useTreeContext()\r\n return { ...state, controller }\r\n}\r\n","import { useCallback, useState } from 'react'\r\n\r\n/** コンテキストメニューの表示状態 */\r\nexport interface ContextMenuState {\r\n /** メニューが表示されているか */\r\n isVisible: boolean\r\n /** メニューのX座標(clientX) */\r\n x: number\r\n /** メニューのY座標(clientY) */\r\n y: number\r\n /** 右クリック対象のファイルパス */\r\n targetPath: string | null\r\n}\r\n\r\n/** {@link useContextMenu} の戻り値 */\r\nexport interface UseContextMenuResult extends ContextMenuState {\r\n /** 指定位置にコンテキストメニューを表示する */\r\n show(e: React.MouseEvent, targetPath: string): void\r\n /** コンテキストメニューを閉じる */\r\n hide(): void\r\n}\r\n\r\n/**\r\n * 右クリックメニューの表示位置・表示状態を管理するフック。\r\n * @returns メニュー状態と表示/非表示の操作関数\r\n */\r\nexport function useContextMenu(): UseContextMenuResult {\r\n const [menuState, setMenuState] = useState<ContextMenuState>({\r\n isVisible: false,\r\n x: 0,\r\n y: 0,\r\n targetPath: null,\r\n })\r\n\r\n const show = useCallback((e: React.MouseEvent, targetPath: string) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n setMenuState({\r\n isVisible: true,\r\n x: e.clientX,\r\n y: e.clientY,\r\n targetPath,\r\n })\r\n }, [])\r\n\r\n const hide = useCallback(() => {\r\n setMenuState((prev) => ({ ...prev, isVisible: false, targetPath: null }))\r\n }, [])\r\n\r\n return { ...menuState, show, hide }\r\n}\r\n","import { useCallback, useEffect, useRef } from 'react'\nimport { useTreeContext } from './context'\nimport { ExplorerCommands } from '../core/keybindings'\nimport type { ExplorerCommandId } from '../core/keybindings'\n\n/**\n * InputService(momoi-keybind)を受け取り、エクスプローラーのコマンドハンドラーを登録する。\n * momoi-keybindが無い場合は使わなくてOK。\n *\n * @param inputService - momoi-keybindのInputServiceインスタンス。nullならスキップ\n * @param options - コマンド実行時の追加処理\n */\nexport function useExplorerKeybindings(\n inputService: InputServiceLike | null,\n options?: {\n onCopyPath?: (paths: string[]) => void\n },\n): void {\n const { controller, state } = useTreeContext()\n const stateRef = useRef(state)\n stateRef.current = state\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n const getCreateTarget = useCallback((): { parentPath: string; insertAfterPath?: string } => {\n const s = stateRef.current\n if (s.selectedPaths.size === 0) return { parentPath: s.rootPath }\n const firstSelected = s.flatList.find((f) => s.selectedPaths.has(f.node.path))\n if (!firstSelected) return { parentPath: s.rootPath }\n // フォルダ選択 → そのフォルダの子の先頭\n if (firstSelected.node.isDirectory) return { parentPath: firstSelected.node.path }\n // ファイル選択 → そのファイルの直後\n const sep = firstSelected.node.path.includes('\\\\') ? '\\\\' : '/'\n const idx = firstSelected.node.path.lastIndexOf(sep)\n const parentPath = idx === -1 ? s.rootPath : firstSelected.node.path.slice(0, idx)\n return { parentPath, insertAfterPath: firstSelected.node.path }\n }, [])\n\n useEffect(() => {\n if (!inputService) return\n\n const disposers: Array<() => void> = []\n\n const handlers: Record<ExplorerCommandId, () => void> = {\n [ExplorerCommands.DELETE]: () => controller.deleteSelected(),\n [ExplorerCommands.RENAME]: () => {\n const s = stateRef.current\n if (s.selectedPaths.size === 1) {\n controller.startRename(Array.from(s.selectedPaths)[0])\n }\n },\n [ExplorerCommands.NEW_FILE]: () => {\n const t = getCreateTarget()\n controller.startCreate(t.parentPath, false, t.insertAfterPath)\n },\n [ExplorerCommands.NEW_FOLDER]: () => {\n const t = getCreateTarget()\n controller.startCreate(t.parentPath, true, t.insertAfterPath)\n },\n [ExplorerCommands.REFRESH]: () => controller.refresh(),\n [ExplorerCommands.COLLAPSE_ALL]: () => {\n const s = stateRef.current\n for (const path of s.expandedPaths) {\n controller.collapse(path)\n }\n },\n [ExplorerCommands.SELECT_ALL]: () => controller.selectAll(),\n [ExplorerCommands.COPY_PATH]: () => {\n const s = stateRef.current\n const paths = Array.from(s.selectedPaths)\n optionsRef.current?.onCopyPath?.(paths)\n },\n }\n\n for (const [command, handler] of Object.entries(handlers)) {\n disposers.push(inputService.registerCommand(command, handler))\n }\n\n return () => {\n for (const dispose of disposers) {\n dispose()\n }\n }\n }, [inputService, controller, getCreateTarget])\n}\n\n/**\n * momoi-keybindのInputServiceの最小インターフェース。\n * momoi-keybindに直接依存せず、duck typingで受け入れる。\n */\nexport interface InputServiceLike {\n registerCommand(command: string, handler: (args?: unknown) => void): () => void\n setContext(key: string, value: unknown): void\n deleteContext(key: string): void\n}\n","// エクスプローラー用のコマンドIDとデフォルトキーバインド定義\n//\n// momoi-keybind の KeybindingEntry 互換の形式でエクスポートする。\n// momoi-keybind が無くても型として参照できるように、独自の型を定義。\n\n/** momoi-keybind の KeybindingEntry と互換の型 */\nexport interface ExplorerKeybindingEntry {\n key: string\n command: string\n when?: string\n args?: unknown\n}\n\n/** エクスプローラーのコマンドID */\nexport const ExplorerCommands = {\n DELETE: 'explorer.delete',\n RENAME: 'explorer.rename',\n NEW_FILE: 'explorer.newFile',\n NEW_FOLDER: 'explorer.newFolder',\n REFRESH: 'explorer.refresh',\n COLLAPSE_ALL: 'explorer.collapseAll',\n SELECT_ALL: 'explorer.selectAll',\n COPY_PATH: 'explorer.copyPath',\n} as const\n\nexport type ExplorerCommandId = (typeof ExplorerCommands)[keyof typeof ExplorerCommands]\n\n/** デフォルトのキーバインド定義。momoi-keybindのInputServiceに渡せる形式 */\nexport const defaultExplorerKeybindings: ExplorerKeybindingEntry[] = [\n { key: 'Delete', command: ExplorerCommands.DELETE, when: 'explorerFocus' },\n { key: 'F2', command: ExplorerCommands.RENAME, when: 'explorerFocus' },\n { key: 'Ctrl+N', command: ExplorerCommands.NEW_FILE, when: 'explorerFocus' },\n { key: 'Ctrl+Shift+N', command: ExplorerCommands.NEW_FOLDER, when: 'explorerFocus' },\n { key: 'Ctrl+R', command: ExplorerCommands.REFRESH, when: 'explorerFocus' },\n { key: 'Ctrl+Shift+E', command: ExplorerCommands.COLLAPSE_ALL, when: 'explorerFocus' },\n { key: 'Ctrl+A', command: ExplorerCommands.SELECT_ALL, when: 'explorerFocus' },\n { key: 'Ctrl+Shift+C', command: ExplorerCommands.COPY_PATH, when: 'explorerFocus' },\n]\n","import { useCallback, useRef } from 'react'\nimport type { InputServiceLike } from './useExplorerKeybindings'\n\n/**\n * エクスプローラーのフォーカス状態をmomoi-keybindのコンテキストに連動させるhook。\n * 返されたpropsをエクスプローラーのルート要素に渡す。\n *\n * @param inputService - momoi-keybindのInputServiceインスタンス。nullならno-op\n * @param contextKey - コンテキストキー名。デフォルト: 'explorerFocus'\n */\nexport function useExplorerFocus(\n inputService: InputServiceLike | null,\n contextKey: string = 'explorerFocus',\n): {\n onFocus: () => void\n onBlur: () => void\n tabIndex: number\n} {\n const focused = useRef(false)\n\n const onFocus = useCallback(() => {\n if (!focused.current) {\n focused.current = true\n inputService?.setContext(contextKey, true)\n }\n }, [inputService, contextKey])\n\n const onBlur = useCallback(() => {\n if (focused.current) {\n focused.current = false\n inputService?.deleteContext(contextKey)\n }\n }, [inputService, contextKey])\n\n return { onFocus, onBlur, tabIndex: 0 }\n}\n","import type React from 'react'\r\nimport { memo, useMemo } from 'react'\r\nimport { getIcon } from 'material-file-icons'\r\nimport type { TreeNode } from '../core/types'\r\nimport { InlineRename } from './InlineRename'\r\n\r\n// デフォルトの展開/折りたたみ矢印SVG\r\nfunction ChevronIcon(): React.JSX.Element {\r\n return (\r\n <svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M6 4l4 4-4 4\" stroke=\"currentColor\" strokeWidth=\"1.5\" fill=\"none\" />\r\n </svg>\r\n )\r\n}\r\n\r\n// デフォルトのフォルダアイコン\r\nfunction FolderIcon({ isExpanded }: { isExpanded: boolean }): React.JSX.Element {\r\n return (\r\n <svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\">\r\n {isExpanded ? (\r\n <path d=\"M1.5 3h5l1 1.5H14.5v9h-13z\" fill=\"#dcb67a\" opacity=\"0.9\" />\r\n ) : (\r\n <path d=\"M1.5 2.5h5l1 1.5H14.5v10h-13z\" fill=\"#dcb67a\" />\r\n )}\r\n </svg>\r\n )\r\n}\r\n\r\n/**\r\n * material-file-iconsを使ったファイルアイコン。\r\n * ファイル名からアイコンを自動判定しSVGを描画する。\r\n */\r\nfunction MaterialFileIcon({ filename }: { filename: string }): React.JSX.Element {\r\n const svg = useMemo(() => getIcon(filename).svg, [filename])\r\n return <span className=\"momoi-explorer-icon-inner\" dangerouslySetInnerHTML={{ __html: svg }} />\r\n}\r\n\r\n/** {@link TreeNodeRow} に渡すprops */\r\nexport interface TreeNodeRowProps {\r\n /** 表示対象のノード */\r\n node: TreeNode\r\n /** ネスト深度(インデント量に使用) */\r\n depth: number\r\n /** ディレクトリが展開されているか */\r\n isExpanded: boolean\r\n /** 選択されているか */\r\n isSelected: boolean\r\n /** リネーム中か */\r\n isRenaming: boolean\r\n /** 行クリック時のハンドラ */\r\n onClick(e: React.MouseEvent): void\r\n /** 行ダブルクリック時のハンドラ */\r\n onDoubleClick(): void\r\n /** 右クリック時のハンドラ */\r\n onContextMenu(e: React.MouseEvent): void\r\n /** 展開/折りたたみトグル */\r\n onToggleExpand(): void\r\n /** リネーム確定時のハンドラ */\r\n onCommitRename(newName: string): void\r\n /** リネームキャンセル時のハンドラ */\r\n onCancelRename(): void\r\n /** ノードアイコンのカスタムレンダラー */\r\n renderIcon?: (node: TreeNode, isExpanded: boolean) => React.ReactNode\r\n /** ノード右端に表示するバッジのカスタムレンダラー */\r\n renderBadge?: (node: TreeNode) => React.ReactNode\r\n}\r\n\r\n/**\r\n * ツリーの1行を表すコンポーネント。\r\n * インデント・展開矢印・アイコン・ファイル名・バッジ・インラインリネームを描画する。\r\n */\r\nexport const TreeNodeRow = memo(function TreeNodeRow({\r\n node,\r\n depth,\r\n isExpanded,\r\n isSelected,\r\n isRenaming,\r\n onClick,\r\n onDoubleClick,\r\n onContextMenu,\r\n onToggleExpand,\r\n onCommitRename,\r\n onCancelRename,\r\n renderIcon,\r\n renderBadge,\r\n}: TreeNodeRowProps): React.JSX.Element {\r\n return (\r\n <div\r\n className=\"momoi-explorer-row\"\r\n data-selected={isSelected}\r\n data-path={node.path}\r\n onClick={onClick}\r\n onDoubleClick={onDoubleClick}\r\n onContextMenu={onContextMenu}\r\n >\r\n {/* インデントガイド */}\r\n <span className=\"momoi-explorer-indent\">\r\n {Array.from({ length: depth }, (_, i) => (\r\n <span key={i} className=\"momoi-explorer-indent-guide\" />\r\n ))}\r\n </span>\r\n\r\n {/* 展開矢印 */}\r\n <span\r\n className=\"momoi-explorer-chevron\"\r\n data-expanded={isExpanded}\r\n data-is-dir={node.isDirectory}\r\n onClick={(e) => {\r\n e.stopPropagation()\r\n onToggleExpand()\r\n }}\r\n >\r\n <ChevronIcon />\r\n </span>\r\n\r\n {/* アイコン */}\r\n <span className=\"momoi-explorer-icon\">\r\n {renderIcon\r\n ? renderIcon(node, isExpanded)\r\n : node.isDirectory\r\n ? <FolderIcon isExpanded={isExpanded} />\r\n : <MaterialFileIcon filename={node.name} />\r\n }\r\n </span>\r\n\r\n {/* 名前 or リネーム入力 */}\r\n {isRenaming ? (\r\n <InlineRename\r\n currentName={node.name}\r\n onCommit={onCommitRename}\r\n onCancel={onCancelRename}\r\n />\r\n ) : (\r\n <span className=\"momoi-explorer-name\">{node.name}</span>\r\n )}\r\n\r\n {/* バッジ */}\r\n {renderBadge && (\r\n <span className=\"momoi-explorer-badge\">\r\n {renderBadge(node)}\r\n </span>\r\n )}\r\n </div>\r\n )\r\n})\r\n","import type React from 'react'\r\nimport { useEffect, useRef, useState } from 'react'\r\n\r\n/** {@link InlineRename} に渡すprops */\r\nexport interface InlineRenameProps {\r\n /** 現在のファイル/フォルダ名 */\r\n currentName: string\r\n /** 新しい名前で確定する際のコールバック */\r\n onCommit(newName: string): void\r\n /** リネームをキャンセルする際のコールバック */\r\n onCancel(): void\r\n}\r\n\r\n/**\r\n * インライン名前変更用の入力コンポーネント。\r\n * Enter で確定、Esc でキャンセル、blur 時も確定する。\r\n * マウント時に自動フォーカスし、拡張子の前までを選択状態にする。\r\n */\r\nexport function InlineRename({ currentName, onCommit, onCancel }: InlineRenameProps): React.JSX.Element {\r\n const inputRef = useRef<HTMLInputElement>(null)\r\n const [value, setValue] = useState(currentName)\r\n\r\n useEffect(() => {\r\n const input = inputRef.current\r\n if (!input) return\r\n input.focus()\r\n // 拡張子の前まで選択\r\n const dotIndex = currentName.lastIndexOf('.')\r\n if (dotIndex > 0) {\r\n input.setSelectionRange(0, dotIndex)\r\n } else {\r\n input.select()\r\n }\r\n }, [currentName])\r\n\r\n function handleKeyDown(e: React.KeyboardEvent): void {\r\n e.stopPropagation()\r\n if (e.key === 'Enter') {\r\n const trimmed = value.trim()\r\n if (trimmed && trimmed !== currentName) {\r\n onCommit(trimmed)\r\n } else {\r\n onCancel()\r\n }\r\n } else if (e.key === 'Escape') {\r\n onCancel()\r\n }\r\n }\r\n\r\n function handleBlur(): void {\r\n const trimmed = value.trim()\r\n if (trimmed && trimmed !== currentName) {\r\n onCommit(trimmed)\r\n } else {\r\n onCancel()\r\n }\r\n }\r\n\r\n return (\r\n <input\r\n ref={inputRef}\r\n className=\"momoi-explorer-rename-input\"\r\n value={value}\r\n onChange={(e) => setValue(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n onBlur={handleBlur}\r\n />\r\n )\r\n}\r\n","import type React from 'react'\r\nimport { useEffect, useRef } from 'react'\r\nimport type { MenuItemDef } from '../core/types'\r\n\r\n/** {@link ContextMenu} に渡すprops */\r\nexport interface ContextMenuProps {\r\n /** メニュー項目の定義リスト */\r\n items: MenuItemDef[]\r\n /** メニュー表示のX座標 */\r\n x: number\r\n /** メニュー表示のY座標 */\r\n y: number\r\n /** メニューを閉じる際のコールバック */\r\n onClose(): void\r\n}\r\n\r\n/**\r\n * 右クリックコンテキストメニュー。\r\n * 外側クリックまたは Esc キーで閉じる。画面端からはみ出さないよう自動調整する。\r\n */\r\nexport function ContextMenu({ items, x, y, onClose }: ContextMenuProps): React.JSX.Element {\r\n const menuRef = useRef<HTMLDivElement>(null)\r\n\r\n useEffect(() => {\r\n function handleClick(e: MouseEvent): void {\r\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\r\n onClose()\r\n }\r\n }\r\n function handleKey(e: KeyboardEvent): void {\r\n if (e.key === 'Escape') onClose()\r\n }\r\n document.addEventListener('mousedown', handleClick)\r\n document.addEventListener('keydown', handleKey)\r\n return () => {\r\n document.removeEventListener('mousedown', handleClick)\r\n document.removeEventListener('keydown', handleKey)\r\n }\r\n }, [onClose])\r\n\r\n // 画面外にはみ出さないように調整\r\n useEffect(() => {\r\n const menu = menuRef.current\r\n if (!menu) return\r\n const rect = menu.getBoundingClientRect()\r\n if (rect.right > window.innerWidth) {\r\n menu.style.left = `${window.innerWidth - rect.width - 4}px`\r\n }\r\n if (rect.bottom > window.innerHeight) {\r\n menu.style.top = `${window.innerHeight - rect.height - 4}px`\r\n }\r\n }, [x, y])\r\n\r\n return (\r\n <div\r\n ref={menuRef}\r\n className=\"momoi-explorer-context-menu\"\r\n style={{ left: x, top: y }}\r\n >\r\n {items.map((item) => {\r\n if (item.separator) {\r\n return <div key={item.id} className=\"momoi-explorer-context-menu-separator\" />\r\n }\r\n return (\r\n <div\r\n key={item.id}\r\n className=\"momoi-explorer-context-menu-item\"\r\n data-disabled={item.disabled ?? false}\r\n onClick={() => {\r\n if (!item.disabled) {\r\n item.action([])\r\n onClose()\r\n }\r\n }}\r\n >\r\n <span>{item.label}</span>\r\n {item.shortcut && (\r\n <span className=\"momoi-explorer-context-menu-shortcut\">{item.shortcut}</span>\r\n )}\r\n </div>\r\n )\r\n })}\r\n </div>\r\n )\r\n}\r\n","import type React from 'react'\r\nimport { useCallback, useRef } from 'react'\r\nimport { useTreeContext } from '../react/context'\r\n\r\n/** {@link TreeFilterBar} に渡すprops */\r\nexport interface TreeFilterBarProps {\r\n /** 入力欄のプレースホルダー。デフォルト: `\"Filter files...\"` */\r\n placeholder?: string\r\n}\r\n\r\n/**\r\n * ファジー検索によるツリーフィルタバー。\r\n * 入力に応じてツリー表示を絞り込む。Esc キーで入力をクリアする。\r\n */\r\nexport function TreeFilterBar({\r\n placeholder = 'Filter files...',\r\n}: TreeFilterBarProps): React.JSX.Element {\r\n const { controller, state } = useTreeContext()\r\n const inputRef = useRef<HTMLInputElement>(null)\r\n\r\n const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\r\n controller.setSearchQuery(e.target.value || null)\r\n }, [controller])\r\n\r\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\r\n if (e.key === 'Escape') {\r\n controller.setSearchQuery(null)\r\n if (inputRef.current) inputRef.current.value = ''\r\n }\r\n }, [controller])\r\n\r\n return (\r\n <div className=\"momoi-explorer-filter-bar\">\r\n <input\r\n ref={inputRef}\r\n className=\"momoi-explorer-filter-input\"\r\n type=\"text\"\r\n placeholder={placeholder}\r\n defaultValue={state.searchQuery ?? ''}\r\n onChange={handleChange}\r\n onKeyDown={handleKeyDown}\r\n />\r\n {state.searchQuery && (\r\n <span\r\n className=\"momoi-explorer-filter-clear\"\r\n onClick={() => {\r\n controller.setSearchQuery(null)\r\n if (inputRef.current) inputRef.current.value = ''\r\n }}\r\n >\r\n ×\r\n </span>\r\n )}\r\n </div>\r\n )\r\n}\r\n","import type React from 'react'\r\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\r\nimport { getIcon } from 'material-file-icons'\r\nimport type { FileEntry, FileTreeController } from '../core/types'\r\nimport { fuzzyFind } from '../core/search'\r\n\r\nfunction QuickOpenIcon({ filename }: { filename: string }): React.JSX.Element {\r\n const svg = useMemo(() => getIcon(filename).svg, [filename])\r\n return <span className=\"momoi-explorer-quickopen-icon\" dangerouslySetInnerHTML={{ __html: svg }} />\r\n}\r\n\r\n/** {@link QuickOpen} に渡すprops */\r\nexport interface QuickOpenProps {\r\n /** ファイル一覧の収集に使用するコントローラ。FileExplorer の `onControllerReady` で取得可能 */\r\n controller: FileTreeController\r\n /** ダイアログの表示/非表示 */\r\n isOpen: boolean\r\n /** ダイアログを閉じる際のコールバック */\r\n onClose(): void\r\n /** ファイル選択時のコールバック */\r\n onSelect(entry: FileEntry): void\r\n /** 入力欄のプレースホルダー。デフォルト: `\"Search files by name...\"` */\r\n placeholder?: string\r\n /** 検索結果の最大表示件数。デフォルト: `50` */\r\n maxResults?: number\r\n}\r\n\r\n/**\r\n * VSCode風のクイックオープンダイアログ。\r\n * ツリー内の全ファイルからファジー検索し、矢印キーで選択、Enter で確定する。\r\n * Esc またはオーバーレイクリックで閉じる。\r\n */\r\nexport function QuickOpen({\r\n controller,\r\n isOpen,\r\n onClose,\r\n onSelect,\r\n placeholder = 'Search files by name...',\r\n maxResults = 50,\r\n}: QuickOpenProps): React.JSX.Element | null {\r\n const inputRef = useRef<HTMLInputElement>(null)\r\n const [query, setQuery] = useState('')\r\n const [allFiles, setAllFiles] = useState<FileEntry[]>([])\r\n const [results, setResults] = useState<FileEntry[]>([])\r\n const [selectedIndex, setSelectedIndex] = useState(0)\r\n\r\n // ファイル一覧を収集\r\n useEffect(() => {\r\n if (!isOpen) return\r\n controller.collectAllFiles().then(setAllFiles)\r\n }, [isOpen, controller])\r\n\r\n // フォーカス\r\n useEffect(() => {\r\n if (isOpen) {\r\n setQuery('')\r\n setResults([])\r\n setSelectedIndex(0)\r\n setTimeout(() => inputRef.current?.focus(), 0)\r\n }\r\n }, [isOpen])\r\n\r\n // 検索実行\r\n useEffect(() => {\r\n if (!query) {\r\n setResults([])\r\n setSelectedIndex(0)\r\n return\r\n }\r\n const found = fuzzyFind(allFiles, query, maxResults)\r\n setResults(found)\r\n setSelectedIndex(0)\r\n }, [query, allFiles, maxResults])\r\n\r\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\r\n switch (e.key) {\r\n case 'Escape':\r\n onClose()\r\n break\r\n case 'ArrowDown':\r\n e.preventDefault()\r\n setSelectedIndex((i) => Math.min(i + 1, results.length - 1))\r\n break\r\n case 'ArrowUp':\r\n e.preventDefault()\r\n setSelectedIndex((i) => Math.max(i - 1, 0))\r\n break\r\n case 'Enter':\r\n e.preventDefault()\r\n if (results[selectedIndex]) {\r\n onSelect(results[selectedIndex])\r\n onClose()\r\n }\r\n break\r\n }\r\n }, [onClose, onSelect, results, selectedIndex])\r\n\r\n if (!isOpen) return null\r\n\r\n return (\r\n <div className=\"momoi-explorer-quickopen-overlay\" onClick={onClose}>\r\n <div\r\n className=\"momoi-explorer-quickopen\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n <input\r\n ref={inputRef}\r\n className=\"momoi-explorer-quickopen-input\"\r\n type=\"text\"\r\n placeholder={placeholder}\r\n value={query}\r\n onChange={(e) => setQuery(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n />\r\n {results.length > 0 && (\r\n <div className=\"momoi-explorer-quickopen-results\">\r\n {results.map((entry, i) => (\r\n <div\r\n key={entry.path}\r\n className=\"momoi-explorer-quickopen-item\"\r\n data-selected={i === selectedIndex}\r\n onMouseEnter={() => setSelectedIndex(i)}\r\n onClick={() => {\r\n onSelect(entry)\r\n onClose()\r\n }}\r\n >\r\n <QuickOpenIcon filename={entry.name} />\r\n <span className=\"momoi-explorer-quickopen-name\">{entry.name}</span>\r\n <span className=\"momoi-explorer-quickopen-path\">{entry.path}</span>\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n {query && results.length === 0 && (\r\n <div className=\"momoi-explorer-quickopen-empty\">No matching files</div>\r\n )}\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","TreeNodeRow","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_material_file_icons","import_jsx_runtime"]}