fix(tui): pin dialog select footer to bottom (#29878)

This commit is contained in:
Shoubhit Dash
2026-05-29 16:43:50 +05:30
committed by GitHub
parent 5764f19937
commit 7da2620078

View File

@@ -354,7 +354,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
const right = createMemo(() => visibleActions().filter((item) => item.side === "right")) const right = createMemo(() => visibleActions().filter((item) => item.side === "right"))
return ( return (
<box gap={1} paddingBottom={1}> <box gap={1} paddingBottom={1} flexGrow={1}>
<box paddingLeft={4} paddingRight={4}> <box paddingLeft={4} paddingRight={4}>
<box flexDirection="row" justifyContent="space-between"> <box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}> <text fg={theme.text} attributes={TextAttributes.BOLD}>
@@ -391,106 +391,108 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
</box> </box>
</Show> </Show>
</box> </box>
<Show <box flexGrow={1} flexShrink={1}>
when={grouped().length > 0} <Show
fallback={ when={grouped().length > 0}
<box paddingLeft={4} paddingRight={4} paddingTop={1}> fallback={
<text fg={theme.textMuted}>No results found</text> <box paddingLeft={4} paddingRight={4} paddingTop={1}>
</box> <text fg={theme.textMuted}>No results found</text>
} </box>
> }
<scrollbox
paddingLeft={1}
paddingRight={1}
scrollbarOptions={{ visible: false }}
scrollAcceleration={scrollAcceleration()}
ref={(r: ScrollBoxRenderable) => (scroll = r)}
maxHeight={height()}
> >
<For each={grouped()}> <scrollbox
{([category, options], index) => ( paddingLeft={1}
<> paddingRight={1}
<Show when={category}> scrollbarOptions={{ visible: false }}
<box paddingTop={index() > 0 ? 1 : 0} paddingLeft={3}> scrollAcceleration={scrollAcceleration()}
<Show ref={(r: ScrollBoxRenderable) => (scroll = r)}
when={options[0]?.categoryView} maxHeight={height()}
fallback={ >
<text fg={theme.accent} attributes={TextAttributes.BOLD}> <For each={grouped()}>
{category} {([category, options], index) => (
</text> <>
} <Show when={category}>
> <box paddingTop={index() > 0 ? 1 : 0} paddingLeft={3}>
{options[0]?.categoryView} <Show
</Show> when={options[0]?.categoryView}
</box> fallback={
</Show> <text fg={theme.accent} attributes={TextAttributes.BOLD}>
<For each={options}> {category}
{(option) => { </text>
const active = createMemo(() => isDeepEqual(option.value, selected()?.value)) }
const current = createMemo(() => isDeepEqual(option.value, props.current))
return (
<box
id={JSON.stringify(option.value)}
flexDirection="column"
position="relative"
onMouseMove={() => {
setStore("input", "mouse")
}}
onMouseUp={() => {
option.onSelect?.(dialog)
props.onSelect?.(option)
}}
onMouseOver={() => {
if (store.input !== "mouse") return
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
onMouseDown={() => {
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
> >
{options[0]?.categoryView}
</Show>
</box>
</Show>
<For each={options}>
{(option) => {
const active = createMemo(() => isDeepEqual(option.value, selected()?.value))
const current = createMemo(() => isDeepEqual(option.value, props.current))
return (
<box <box
flexDirection="row" id={JSON.stringify(option.value)}
paddingLeft={current() || option.gutter ? 1 : 3} flexDirection="column"
paddingRight={3} position="relative"
gap={1} onMouseMove={() => {
backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)} setStore("input", "mouse")
}}
onMouseUp={() => {
option.onSelect?.(dialog)
props.onSelect?.(option)
}}
onMouseOver={() => {
if (store.input !== "mouse") return
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
onMouseDown={() => {
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
> >
<Show when={!current() && option.margin}> <box
<box position="absolute" left={1} flexShrink={0}> flexDirection="row"
{option.margin} paddingLeft={current() || option.gutter ? 1 : 3}
</box> paddingRight={3}
</Show> gap={1}
<Option backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)}
title={option.title} >
footer={flatten() ? (option.category ?? option.footer) : option.footer} <Show when={!current() && option.margin}>
description={option.description !== category ? option.description : undefined} <box position="absolute" left={1} flexShrink={0}>
active={active()} {option.margin}
current={current()} </box>
gutter={option.gutter} </Show>
/> <Option
title={option.title}
footer={flatten() ? (option.category ?? option.footer) : option.footer}
description={option.description !== category ? option.description : undefined}
active={active()}
current={current()}
gutter={option.gutter}
/>
</box>
<For each={option.details}>
{(detail) => (
<box paddingLeft={3} paddingRight={3}>
<text fg={theme.textMuted} wrapMode="none">
{Locale.truncateMiddle(detail, Math.max(1, Math.min(76, dimensions().width - 12)))}
</text>
</box>
)}
</For>
</box> </box>
<For each={option.details}> )
{(detail) => ( }}
<box paddingLeft={3} paddingRight={3}> </For>
<text fg={theme.textMuted} wrapMode="none"> </>
{Locale.truncateMiddle(detail, Math.max(1, Math.min(76, dimensions().width - 12)))} )}
</text> </For>
</box> </scrollbox>
)} </Show>
</For> </box>
</box>
)
}}
</For>
</>
)}
</For>
</scrollbox>
</Show>
<Show when={visibleActions().length} fallback={<box flexShrink={0} />}> <Show when={visibleActions().length} fallback={<box flexShrink={0} />}>
<box <box
paddingRight={2} paddingRight={2}