import type { InputRenderable, SelectOption } from "@opentui/core" import type { RefObject } from "react" import { SectionDivider } from "./section-divider" import type { UiTheme } from "../theme" import type { BranchDialogMode, FocusTarget } from "../types" import { getVisibleRange } from "../list-range" import { fitLine } from "../utils" import { ViewFrame, resolveViewContentWidth, resolveVisibleRows } from "./view-frame" type BranchDialogProps = { open: boolean mode: BranchDialogMode focus: FocusTarget terminalWidth: number terminalHeight: number currentBranch: string branchOptions: SelectOption[] branchIndex: number selectedBranchForAction: string | null branchActionOptions: SelectOption[] branchActionIndex: number branchStrategyOptions: SelectOption[] branchStrategyIndex: number branchName: string branchNameRef: RefObject onBranchNameInput: (value: string) => void onBranchClick: (index: number) => void onBranchActionClick: (index: number) => void onBranchStrategyClick: (index: number) => void onBranchScroll: (direction: "up" | "down") => void onBranchActionScroll: (direction: "up" | "down") => void onBranchStrategyScroll: (direction: "up" | "down") => void theme: UiTheme } export function BranchDialog({ open, mode, focus, terminalWidth, terminalHeight, currentBranch, branchOptions, branchIndex, selectedBranchForAction, branchActionOptions, branchActionIndex, branchStrategyOptions, branchStrategyIndex, branchName, branchNameRef, onBranchNameInput, onBranchClick, onBranchActionClick, onBranchStrategyClick, onBranchScroll, onBranchActionScroll, onBranchStrategyScroll, theme, }: BranchDialogProps) { if (!open) return null const visibleOptionRows = resolveVisibleRows(terminalHeight, 16) const createOption = branchOptions[0] const checkoutOptions = branchOptions.slice(1) const checkoutSelectedIndex = Math.max(branchIndex - 1, 0) const visibleCheckoutRows = Math.max(1, visibleOptionRows - 2) const checkoutRange = getVisibleRange( checkoutOptions.length, checkoutSelectedIndex, visibleCheckoutRows, ) const strategyRange = getVisibleRange( branchStrategyOptions.length, branchStrategyIndex, visibleOptionRows, ) const actionRange = getVisibleRange( branchActionOptions.length, branchActionIndex, visibleOptionRows, ) const rowWidth = Math.max(resolveViewContentWidth(terminalWidth) - 2, 12) const labelWidth = Math.max(rowWidth - 2, 1) return ( change branch branch: {currentBranch} {mode === "select" ? ( <> { const direction = event.scroll?.direction if (direction !== "up" && direction !== "down") return event.preventDefault() event.stopPropagation() onBranchScroll(direction) }} > {createOption ? ( { event.preventDefault() event.stopPropagation() onBranchClick(0) }} > {branchIndex === 0 ? "▶ " : " "} {fitLine(createOption.name ?? String(createOption.value ?? ""), labelWidth)} ) : null} {checkoutOptions.length > 0 ? ( {fitLine("branches", labelWidth)} ) : null} {checkoutOptions .slice(checkoutRange.start, checkoutRange.end) .map((option, visibleIndex) => { const absoluteIndex = checkoutRange.start + visibleIndex + 1 const selected = absoluteIndex === branchIndex const optionName = option.name ?? String(option.value ?? "") const isCurrentBranch = (option.description ?? "").length > 0 const marker = isCurrentBranch ? "● " : " " const label = `${marker}${optionName}` return ( { event.preventDefault() event.stopPropagation() onBranchClick(absoluteIndex) }} > {selected ? "▶ " : " "} {fitLine(label, labelWidth)} ) })} ) : mode === "action" ? ( <> branch: {selectedBranchForAction ?? "-"} { const direction = event.scroll?.direction if (direction !== "up" && direction !== "down") return event.preventDefault() event.stopPropagation() onBranchActionScroll(direction) }} > {branchActionOptions .slice(actionRange.start, actionRange.end) .map((option, visibleIndex) => { const absoluteIndex = actionRange.start + visibleIndex const selected = absoluteIndex === branchActionIndex const optionName = option.name ?? String(option.value ?? "") const optionDescription = option.description ?? "" const label = optionDescription ? `${optionName} - ${optionDescription}` : optionName return ( { event.preventDefault() event.stopPropagation() onBranchActionClick(absoluteIndex) }} > {selected ? "▶ " : " "} {fitLine(label, labelWidth)} ) })} ) : mode === "confirm" ? ( <> { const direction = event.scroll?.direction if (direction !== "up" && direction !== "down") return event.preventDefault() event.stopPropagation() onBranchStrategyScroll(direction) }} > {branchStrategyOptions .slice(strategyRange.start, strategyRange.end) .map((option, visibleIndex) => { const absoluteIndex = strategyRange.start + visibleIndex const selected = absoluteIndex === branchStrategyIndex const optionName = option.name ?? String(option.value ?? "") const optionDescription = option.description ?? "" const label = optionDescription ? `${optionName} - ${optionDescription}` : optionName return ( { event.preventDefault() event.stopPropagation() onBranchStrategyClick(absoluteIndex) }} > {selected ? "▶ " : " "} {fitLine(label, labelWidth)} ) })} ) : ( <> )} ) }