clack-tree-select
Version:
Beautiful, interactive, searchable tree selection prompt for Clack CLI apps
171 lines (166 loc) • 5.43 kB
text/typescript
import * as _clack_core from '@clack/core';
import { Prompt } from '@clack/core';
import { Readable, Writable } from 'node:stream';
/**
* Represents a tree item with optional children and metadata
* @template T The type of the value stored in each tree item
*/
interface TreeItem<T = any> {
/** The unique value/identifier for this tree item */
value: T;
/** Display name for the item (falls back to string representation of value) */
name?: string;
/** Whether this directory should be initially expanded */
open?: boolean;
/** Child items - can be TreeItems, strings, or raw values */
children?: TreeItem<T>[] | string[] | T[];
}
/**
* Options for configuring tree selection behavior
*/
interface TreeSelectConfig {
/** Allow multiple selections */
multiple?: boolean;
/** Require at least one selection */
required?: boolean;
/** Show help text with keyboard shortcuts */
showHelp?: boolean;
/** Enable inline search via typing letters */
searchable?: boolean;
/** Custom icons for different item types */
icons?: {
directory?: string;
file?: string;
expanded?: string;
collapsed?: string;
};
}
/**
* Complete options for the TreeSelectPrompt
* @template T The type of values in the tree
*/
interface TreeSelectOptions$1<T = any> extends TreeSelectConfig {
/** The tree structure to display */
tree: TreeItem<T>[] | string[] | T[];
/** Initial selected values */
initialValues?: T[];
/** Value where cursor should start */
cursorAt?: T;
/** Custom validation function */
validate?: (value: T[] | undefined) => string | void;
/** Optional render function consumed by Prompt */
render?: () => string;
/** Optional runtime fields forwarded to Prompt environment */
signal?: AbortSignal;
input?: NodeJS.ReadStream;
output?: NodeJS.WriteStream;
}
interface FlatTreeItem<T> {
value: T;
name: string;
level: number;
isDirectory: boolean;
isOpen: boolean;
parent?: FlatTreeItem<T>;
originalItem: TreeItem<T>;
}
/**
* Minimal TreeSelectPrompt for testing
*/
declare class TreeSelectPrompt<T> extends Prompt<T[]> {
tree: TreeItem<T>[];
flatTree: FlatTreeItem<T>[];
cursor: number;
multiple: boolean;
config: TreeSelectConfig;
searchQuery: string;
isSearching: boolean;
constructor(opts: TreeSelectOptions$1<T>);
private normalizeTree;
private normalizeTreeItem;
private rebuildFlatTree;
/** Build a flattened list of the entire tree ignoring open/closed state */
private buildFullFlatTree;
/** Return the list of items currently visible (search-filtered or by open state) */
getVisibleFlatTree(): FlatTreeItem<T>[];
/** Fuzzy match: query (spaces removed) must appear in order within name (spaces removed) */
private isFuzzyMatch;
private toggleDirectory;
private toggleSelection;
private selectChildren;
private deselectChildren;
private expandAll;
private collapseAll;
private selectAll;
private deselectAll;
private areAllDirectoriesExpanded;
private areAllItemsSelected;
private toggleExpandAll;
private toggleSelectAll;
private handleCursor;
getState(): {
value: T[] | undefined;
cursor: number;
state: _clack_core.State;
flatTree: FlatTreeItem<T>[];
searchQuery: string;
isSearching: boolean;
};
}
interface CommonOptions {
input?: Readable;
output?: Writable;
signal?: AbortSignal;
}
interface TreeSelectOptions<Value> extends CommonOptions {
message: string;
tree: TreeItem<Value>[] | Value[];
multiple?: boolean;
initialValues?: Value[];
required?: boolean;
cursorAt?: Value;
maxItems?: number;
onlyShowDirectories?: boolean;
/** Enable search functionality (default: true for better UX) */
searchable?: boolean;
/** Maximum tree depth to display (default: Infinity) */
maxDepth?: number;
/** Custom icons for different item types */
icons?: {
directory?: string;
file?: string;
expanded?: string;
collapsed?: string;
};
/** Show help text with keyboard shortcuts */
showHelp?: boolean;
}
interface FileSystemTreeOptions extends Omit<TreeSelectOptions<string>, 'tree'> {
root: string;
includeFiles?: boolean;
includeHidden?: boolean;
maxDepth?: number;
filter?: (path: string) => boolean;
}
/**
* Build a tree structure from a file system path
*/
declare function buildFileSystemTree(rootPath: string, options?: {
includeFiles?: boolean;
includeHidden?: boolean;
maxDepth?: number;
filter?: (path: string) => boolean;
currentDepth?: number;
}): TreeItem<string>[];
/**
* Create a tree-select prompt for file system navigation
*/
declare const fileSystemTreeSelect: (opts: FileSystemTreeOptions) => Promise<symbol | string[]>;
/**
* Create a beautiful tree-select prompt with enhanced UX
* @param opts Configuration options for the tree select
* @returns Promise resolving to selected values
*/
declare const treeSelect: <Value>(opts: TreeSelectOptions<Value>) => Promise<symbol | Value[]>;
export { TreeSelectPrompt, buildFileSystemTree, fileSystemTreeSelect, treeSelect };
export type { TreeSelectOptions$1 as CoreTreeSelectOptions, FileSystemTreeOptions, TreeItem, TreeSelectOptions };