fix(app): show keybind tooltips on prompt input controls (#37824)

This commit is contained in:
Rahul A Mistry
2026-07-20 10:22:38 +10:00
committed by GitHub
parent 67caf894e0
commit 7985c2066a
3 changed files with 54 additions and 39 deletions
@@ -60,6 +60,8 @@ export function PromptInputV2Composer(props: PromptInputV2ComposerProps) {
controller={props.controller} controller={props.controller}
borderUnderlay={props.borderUnderlay} borderUnderlay={props.borderUnderlay}
class={props.class} class={props.class}
attachKeybind={command.keybindParts("file.attach")}
attachShortcut={command.keybind("file.attach")}
modelControl={ modelControl={
<PromptInputV2ModelControl <PromptInputV2ModelControl
loading={props.controller.model.loading} loading={props.controller.model.loading}
@@ -451,12 +453,14 @@ export function usePromptInputV2Controller(props: PromptInputV2ControllerProps):
options: () => props.controls.agents.options.map((name) => ({ id: name, label: name })), options: () => props.controls.agents.options.map((name) => ({ id: name, label: name })),
current: () => props.controls.agents.current, current: () => props.controls.agents.current,
onSelect: props.controls.agents.select, onSelect: props.controls.agents.select,
keybind: () => command.keybindParts("agent.cycle"),
} }
: undefined, : undefined,
variant: { variant: {
options: () => variants().map((value) => ({ id: value, label: value })), options: () => variants().map((value) => ({ id: value, label: value })),
current: () => props.controls.model.selection.variant.current() ?? "default", current: () => props.controls.model.selection.variant.current() ?? "default",
onSelect: (value) => props.controls.model.selection.variant.set(value === "default" ? undefined : value), onSelect: (value) => props.controls.model.selection.variant.set(value === "default" ? undefined : value),
keybind: () => command.keybindParts("model.variant.cycle"),
}, },
submit: { submit: {
stopping, stopping,
@@ -39,6 +39,8 @@ export type PromptInputV2Props = {
borderUnderlay?: boolean borderUnderlay?: boolean
class?: string class?: string
modelControl?: JSX.Element modelControl?: JSX.Element
attachKeybind?: string[]
attachShortcut?: string
} }
export function PromptInputV2(props: PromptInputV2Props) { export function PromptInputV2(props: PromptInputV2Props) {
@@ -197,9 +199,9 @@ export function PromptInputV2(props: PromptInputV2Props) {
<PromptInputV2AddMenu <PromptInputV2AddMenu
disabled={state.mode === "shell"} disabled={state.mode === "shell"}
title="Add images and files" title="Add images and files"
keybind={["Mod", "U"]} keybind={props.attachKeybind ?? ["Mod", "U"]}
attachLabel="Images and files" attachLabel="Images and files"
attachShortcut="Mod+U" attachShortcut={props.attachShortcut ?? "Mod+U"}
commandsLabel="Commands" commandsLabel="Commands"
contextLabel="Context" contextLabel="Context"
shellLabel="Shell command" shellLabel="Shell command"
@@ -233,7 +235,11 @@ export function PromptInputV2(props: PromptInputV2Props) {
<Show when={view.variant}> <Show when={view.variant}>
{(control) => ( {(control) => (
<Show when={control().options().length > 1}> <Show when={control().options().length > 1}>
<PromptInputV2ConfiguredSelect title="Choose model variant" control={control()} /> <PromptInputV2ConfiguredSelect
title="Choose model variant"
keybind={["Shift", "Mod", "D"]}
control={control()}
/>
</Show> </Show>
)} )}
</Show> </Show>
@@ -512,7 +518,7 @@ function PromptInputV2ConfiguredSelect(props: {
return ( return (
<PromptInputV2Select <PromptInputV2Select
title={props.title} title={props.title}
keybind={props.keybind} keybind={props.control.keybind?.() ?? props.keybind}
options={props.control.options()} options={props.control.options()}
current={current()} current={current()}
currentIcon={ currentIcon={
@@ -536,36 +542,45 @@ export function PromptInputV2Select(props: {
onSelect: (id: string) => void onSelect: (id: string) => void
}) { }) {
return ( return (
<MenuV2 gutter={6} modal={false} placement="top-start" onOpenChange={props.onOpenChange}> <TooltipV2
<MenuV2.Trigger placement="top"
as={ButtonV2} value={
variant="ghost-muted" <>
size="normal" {props.title}
class={`max-w-[220px] justify-start ![font-weight:440] ${props.class ?? ""}`} <KeybindV2 keys={props.keybind ?? []} variant="neutral" />
title={keybindTitle(props.title, props.keybind)} </>
> }
{props.currentIcon} >
<span class="truncate capitalize leading-5"> <MenuV2 gutter={6} modal={false} placement="top-start" onOpenChange={props.onOpenChange}>
{props.options.find((option) => option.id === props.current)?.label ?? props.current} <MenuV2.Trigger
</span> as={ButtonV2}
<span class="-ml-0.5 -mr-1 flex shrink-0"> variant="ghost-muted"
<IconV2 name="chevron-down" /> size="normal"
</span> class={`max-w-[220px] justify-start ![font-weight:440] ${props.class ?? ""}`}
</MenuV2.Trigger> >
<MenuV2.Portal> {props.currentIcon}
<MenuV2.Content> <span class="truncate capitalize leading-5">
<MenuV2.RadioGroup value={props.current} onChange={props.onSelect}> {props.options.find((option) => option.id === props.current)?.label ?? props.current}
<For each={props.options}> </span>
{(option) => ( <span class="-ml-0.5 -mr-1 flex shrink-0">
<MenuV2.RadioItem value={option.id} class="capitalize" closeOnSelect> <IconV2 name="chevron-down" />
{option.label} </span>
</MenuV2.RadioItem> </MenuV2.Trigger>
)} <MenuV2.Portal>
</For> <MenuV2.Content>
</MenuV2.RadioGroup> <MenuV2.RadioGroup value={props.current} onChange={props.onSelect}>
</MenuV2.Content> <For each={props.options}>
</MenuV2.Portal> {(option) => (
</MenuV2> <MenuV2.RadioItem value={option.id} class="capitalize" closeOnSelect>
{option.label}
</MenuV2.RadioItem>
)}
</For>
</MenuV2.RadioGroup>
</MenuV2.Content>
</MenuV2.Portal>
</MenuV2>
</TooltipV2>
) )
} }
@@ -688,8 +703,3 @@ function PromptInputV2SuggestionIcon(props: { item: PromptInputV2Suggestion }) {
/> />
) )
} }
function keybindTitle(label: string, keybind?: string[]) {
if (!keybind?.length) return label
return `${label} (${keybind.join("+")})`
}
@@ -23,6 +23,7 @@ export type PromptInputV2SelectControl = {
options: Accessor<PromptInputV2Option[]> options: Accessor<PromptInputV2Option[]>
current: Accessor<string> current: Accessor<string>
onSelect: (id: string) => void onSelect: (id: string) => void
keybind?: Accessor<string[]>
} }
export type PromptInputV2ViewConfig = { export type PromptInputV2ViewConfig = {