@botpress/adk-cli
Version:
Command-line interface for the Botpress Agent Development Kit (ADK)
91 lines (88 loc) • 3.02 kB
JavaScript
// @bun
import {
keyHints
} from "./chunk-bexyahs9.js";
import {
bind,
bold,
box,
fg,
getActiveTheme,
onKey,
signal,
t,
text
} from "./chunk-m2h26j5f.js";
// src/components/radio-buttons.ts
function radioButtons(renderer, scope, props) {
const { options, initialSelected, onSubmit, onCancel } = props;
const theme = getActiveTheme();
const startIndex = (() => {
if (initialSelected) {
const i = options.findIndex((opt) => opt.id === initialSelected);
if (i >= 0)
return i;
}
const firstEnabled = options.findIndex((opt) => !opt.disabled);
return firstEnabled >= 0 ? firstEnabled : 0;
})();
const focused = signal(startIndex);
const rows = [];
options.forEach((option, index) => {
const isDisabled = option.disabled || false;
const row = text(renderer, "");
scope.add(bind(() => {
const isFocused = focused() === index;
const indicatorColor = isDisabled ? theme.text.dimmer : isFocused ? theme.accent.cyan : theme.text.dim;
const labelColor = isDisabled ? theme.text.dimmer : isFocused ? theme.accent.cyan : theme.text.primary;
const indicator = fg(indicatorColor)(isFocused ? "\u25CF " : "\u25CB ");
const label = isFocused && !isDisabled ? fg(labelColor)(bold(option.label)) : fg(labelColor)(option.label);
row.content = isDisabled ? t`${indicator}${label} ${fg(theme.text.dimmer)("(not installed)")}` : t`${indicator}${label}`;
}, [focused]));
const rowChildren = [box(renderer, {}, [row])];
if (option.description) {
const desc = text(renderer, "");
scope.add(bind(() => {
const isFocused = focused() === index;
const color = isFocused && !isDisabled ? theme.text.dim : theme.text.dimmer;
desc.content = t`${fg(color)(option.description)}`;
}, [focused]));
rowChildren.push(box(renderer, { paddingLeft: 4 }, [desc]));
}
rows.push(box(renderer, { flexDirection: "column" }, rowChildren));
});
const hints = [
{ key: "\u2191\u2193", label: "navigate" },
{ key: "Enter", label: "select" }
];
if (onCancel)
hints.push({ key: "Esc", label: "cancel" });
rows.push(box(renderer, { marginTop: 1 }, [keyHints(renderer, hints)]));
const nextEnabled = (from, dir) => {
const n = options.length;
for (let step = 1;step <= n; step++) {
const idx = ((from + dir * step) % n + n) % n;
if (!options[idx].disabled)
return idx;
}
return from;
};
scope.add(onKey(renderer, (key) => {
if (key.name === "escape" && onCancel) {
onCancel();
return;
}
if (key.name === "return" && options.length > 0 && !options[focused()].disabled) {
onSubmit(options[focused()].value);
return;
}
if (key.name === "up") {
focused.set(nextEnabled(focused(), -1));
}
if (key.name === "down") {
focused.set(nextEnabled(focused(), 1));
}
}));
return box(renderer, { flexDirection: "column", marginTop: 1 }, rows);
}
export { radioButtons };