mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 19:03:50 +00:00
91 lines
2.4 KiB
TypeScript
91 lines
2.4 KiB
TypeScript
/**
|
|
* Generic selector component for hooks.
|
|
* Displays a list of string options with keyboard navigation.
|
|
*/
|
|
|
|
import { Container, isArrowDown, isArrowUp, isEnter, isEscape, Spacer, Text } from "@mariozechner/pi-tui";
|
|
import { theme } from "../theme/theme.js";
|
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
|
|
export class HookSelectorComponent extends Container {
|
|
private options: string[];
|
|
private selectedIndex = 0;
|
|
private listContainer: Container;
|
|
private onSelectCallback: (option: string) => void;
|
|
private onCancelCallback: () => void;
|
|
|
|
constructor(title: string, options: string[], onSelect: (option: string) => void, onCancel: () => void) {
|
|
super();
|
|
|
|
this.options = options;
|
|
this.onSelectCallback = onSelect;
|
|
this.onCancelCallback = onCancel;
|
|
|
|
// Add top border
|
|
this.addChild(new DynamicBorder());
|
|
this.addChild(new Spacer(1));
|
|
|
|
// Add title
|
|
this.addChild(new Text(theme.fg("accent", title), 1, 0));
|
|
this.addChild(new Spacer(1));
|
|
|
|
// Create list container
|
|
this.listContainer = new Container();
|
|
this.addChild(this.listContainer);
|
|
|
|
this.addChild(new Spacer(1));
|
|
|
|
// Add hint
|
|
this.addChild(new Text(theme.fg("dim", "↑↓ navigate enter select esc cancel"), 1, 0));
|
|
|
|
this.addChild(new Spacer(1));
|
|
|
|
// Add bottom border
|
|
this.addChild(new DynamicBorder());
|
|
|
|
// Initial render
|
|
this.updateList();
|
|
}
|
|
|
|
private updateList(): void {
|
|
this.listContainer.clear();
|
|
|
|
for (let i = 0; i < this.options.length; i++) {
|
|
const option = this.options[i];
|
|
const isSelected = i === this.selectedIndex;
|
|
|
|
let text = "";
|
|
if (isSelected) {
|
|
text = theme.fg("accent", "→ ") + theme.fg("accent", option);
|
|
} else {
|
|
text = ` ${theme.fg("text", option)}`;
|
|
}
|
|
|
|
this.listContainer.addChild(new Text(text, 1, 0));
|
|
}
|
|
}
|
|
|
|
handleInput(keyData: string): void {
|
|
// Up arrow or k
|
|
if (isArrowUp(keyData) || keyData === "k") {
|
|
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
this.updateList();
|
|
}
|
|
// Down arrow or j
|
|
else if (isArrowDown(keyData) || keyData === "j") {
|
|
this.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);
|
|
this.updateList();
|
|
}
|
|
// Enter
|
|
else if (isEnter(keyData) || keyData === "\n") {
|
|
const selected = this.options[this.selectedIndex];
|
|
if (selected) {
|
|
this.onSelectCallback(selected);
|
|
}
|
|
}
|
|
// Escape
|
|
else if (isEscape(keyData)) {
|
|
this.onCancelCallback();
|
|
}
|
|
}
|
|
}
|