fix(cli): stabilize prompt layout to prevent jumping when typing

- Added minHeight and spacer text to shortcuts hint container
- Ensures the line occupied by the hint remains in the layout even when the hint is hidden during typing
- Updated tests and snapshots
This commit is contained in:
Taylor Mullen
2026-03-04 00:57:35 -08:00
parent af424aefa9
commit 2a12ac49e2
3 changed files with 20 additions and 37 deletions
@@ -820,18 +820,7 @@ describe('Composer', () => {
}); });
describe('Shortcuts Hint', () => { describe('Shortcuts Hint', () => {
it('restores shortcuts hint after 200ms debounce when buffer is empty', async () => { it('hides shortcuts hint when text is typed in buffer', async () => {
const { lastFrame } = await renderComposer(
createMockUIState({
buffer: { text: '' } as unknown as TextBuffer,
cleanUiDetailsVisible: false,
}),
);
expect(lastFrame({ allowEmpty: true })).toContain('ShortcutsHint');
});
it('does not show shortcuts hint immediately when buffer has text', async () => {
const uiState = createMockUIState({ const uiState = createMockUIState({
buffer: { text: 'hello' } as unknown as TextBuffer, buffer: { text: 'hello' } as unknown as TextBuffer,
cleanUiDetailsVisible: false, cleanUiDetailsVisible: false,
@@ -901,16 +890,6 @@ describe('Composer', () => {
expect(lastFrame()).not.toContain('ShortcutsHint'); expect(lastFrame()).not.toContain('ShortcutsHint');
}); });
it('hides shortcuts hint when text is typed in buffer', async () => {
const uiState = createMockUIState({
buffer: { text: 'hello' } as unknown as TextBuffer,
});
const { lastFrame } = await renderComposer(uiState);
expect(lastFrame()).not.toContain('ShortcutsHint');
});
it('hides shortcuts hint while loading in minimal mode', async () => { it('hides shortcuts hint while loading in minimal mode', async () => {
const uiState = createMockUIState({ const uiState = createMockUIState({
cleanUiDetailsVisible: false, cleanUiDetailsVisible: false,
+9 -7
View File
@@ -249,8 +249,13 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
marginTop={isNarrow ? 1 : 0} marginTop={isNarrow ? 1 : 0}
flexDirection="column" flexDirection="column"
alignItems={isNarrow ? 'flex-start' : 'flex-end'} alignItems={isNarrow ? 'flex-start' : 'flex-end'}
minHeight={1}
> >
{showUiDetails && showShortcutsHint && <ShortcutsHint />} {showUiDetails && showShortcutsHint ? (
<ShortcutsHint />
) : (
<Text> </Text>
)}
</Box> </Box>
</Box> </Box>
{showMinimalMetaRow && ( {showMinimalMetaRow && (
@@ -309,6 +314,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
marginTop={isNarrow && showMinimalBleedThroughRow ? 1 : 0} marginTop={isNarrow && showMinimalBleedThroughRow ? 1 : 0}
flexDirection={isNarrow ? 'column' : 'row'} flexDirection={isNarrow ? 'column' : 'row'}
alignItems={isNarrow ? 'flex-start' : 'flex-end'} alignItems={isNarrow ? 'flex-start' : 'flex-end'}
minHeight={1}
> >
{showMinimalContextBleedThrough && ( {showMinimalContextBleedThrough && (
<ContextUsageDisplay <ContextUsageDisplay
@@ -317,18 +323,14 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
terminalWidth={uiState.terminalWidth} terminalWidth={uiState.terminalWidth}
/> />
)} )}
{showShortcutsHint && (
<Box <Box
marginLeft={ marginLeft={
showMinimalContextBleedThrough && !isNarrow ? 1 : 0 showMinimalContextBleedThrough && !isNarrow ? 1 : 0
} }
marginTop={ marginTop={showMinimalContextBleedThrough && isNarrow ? 1 : 0}
showMinimalContextBleedThrough && isNarrow ? 1 : 0
}
> >
<ShortcutsHint /> {showShortcutsHint ? <ShortcutsHint /> : <Text> </Text>}
</Box> </Box>
)}
</Box> </Box>
)} )}
</Box> </Box>
@@ -10,13 +10,15 @@ Footer
`; `;
exports[`Composer > Snapshots > matches snapshot in minimal UI mode 1`] = ` exports[`Composer > Snapshots > matches snapshot in minimal UI mode 1`] = `
" ShortcutsHint "
ShortcutsHint
InputPrompt: Type your message or @path/to/file InputPrompt: Type your message or @path/to/file
" "
`; `;
exports[`Composer > Snapshots > matches snapshot in minimal UI mode while loading 1`] = ` exports[`Composer > Snapshots > matches snapshot in minimal UI mode while loading 1`] = `
" LoadingIndicator "
LoadingIndicator
InputPrompt: Type your message or @path/to/file InputPrompt: Type your message or @path/to/file
" "
`; `;