Private/UI/Show-PSMBMenu.ps1

function Show-PSMBMenu {
    <#
    .SYNOPSIS
        Renders a menu and reads user selection.
    .DESCRIPTION
        On PS 7+ with an interactive console, uses arrow-key navigation with
        premium box rendering. Falls back to classic Read-Host numbered input
        on non-interactive hosts.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Title,

        [Parameter(Mandatory)]
        [string[]]$Options,

        [Parameter()]
        [switch]$IncludeBack,

        [Parameter()]
        [switch]$IncludeQuit
    )

    if (Test-PSMBArrowKeySupport) {
        return Show-PSMBMenuArrowSingle -Title $Title -Options $Options -IncludeBack:$IncludeBack -IncludeQuit:$IncludeQuit
    }

    # Classic Read-Host fallback
    while ($true) {
        Write-Host ''
        Write-Host (' {0}' -f $Title) -ForegroundColor Yellow
        Write-Host (' {0}' -f ('-' * $Title.Length)) -ForegroundColor DarkYellow
        Write-Host ''

        for ($i = 0; $i -lt $Options.Count; $i++) {
            $num = $i + 1
            Write-Host (' {0}. {1}' -f $num, $Options[$i]) -ForegroundColor White
        }

        Write-Host ''

        if ($IncludeBack) {
            Write-Host ' 0. Back' -ForegroundColor DarkGray
        }

        if ($IncludeQuit) {
            Write-Host ' Q. Quit' -ForegroundColor DarkGray
        }

        Write-Host ''
        $input_value = Read-Host -Prompt ' Select an option'
        $input_value = $input_value.Trim()

        if ($IncludeQuit -and ($input_value -eq 'Q' -or $input_value -eq 'q')) {
            return 'Quit'
        }

        if ($IncludeBack -and $input_value -eq '0') {
            return 'Back'
        }

        $num = 0
        if ([int]::TryParse($input_value, [ref]$num)) {
            if ($num -ge 1 -and $num -le $Options.Count) {
                return ($num - 1)
            }
        }

        Write-Host ' Invalid selection. Please try again.' -ForegroundColor Red
    }
}