UNPKG

@botpress/adk-cli

Version:

Command-line interface for the Botpress Agent Development Kit (ADK)

91 lines (88 loc) 3.02 kB
// @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 };