Fix dialog focus

This commit is contained in:
2026-03-23 03:51:51 +00:00
parent a28d43a68b
commit 7fd89c5663
18 changed files with 403 additions and 177 deletions

View File

@@ -2,10 +2,11 @@
* Dialog components for modals, confirmations, and input dialogs.
*/
import React, { useRef, useState } from 'react';
import { Box, Text, useInput, measureElement } from 'ink';
import React, { useId, useRef, useState } from 'react';
import { Box, Text, measureElement } from 'ink';
import TextInput from './TextInput.js';
import { colors } from '../theme.js';
import { useInputLayer, useLayeredInput } from '../hooks/useInputLayer.js';
/**
* Base dialog wrapper props.
@@ -118,15 +119,17 @@ export function InputDialog({
onCancel,
isActive = true,
}: InputDialogProps): React.ReactElement {
const layerId = useId();
const [value, setValue] = useState(initialValue);
useInput((input, key) => {
if (!isActive) return;
// Auto-capture input when this dialog is mounted.
useInputLayer(layerId);
useLayeredInput(layerId, (_input, key) => {
if (key.escape) {
onCancel();
}
}, { isActive });
});
const handleSubmit = (val: string) => {
onSubmit(val);
@@ -183,11 +186,13 @@ export function ConfirmDialog({
confirmLabel = 'Yes',
cancelLabel = 'No',
}: ConfirmDialogProps): React.ReactElement {
const layerId = useId();
const [selected, setSelected] = useState<'confirm' | 'cancel'>('confirm');
useInput((input, key) => {
if (!isActive) return;
// Auto-capture input when this dialog is mounted.
useInputLayer(layerId);
useLayeredInput(layerId, (input, key) => {
if (key.leftArrow || key.rightArrow || key.tab) {
setSelected(prev => prev === 'confirm' ? 'cancel' : 'confirm');
} else if (key.return) {
@@ -201,7 +206,7 @@ export function ConfirmDialog({
} else if (input === 'y' || input === 'Y') {
onConfirm();
}
}, { isActive });
});
return (
<DialogWrapper title={title} borderColor={colors.warning}>
@@ -255,13 +260,16 @@ export function MessageDialog({
type = 'info',
isActive = true,
}: MessageDialogProps): React.ReactElement {
useInput((input, key) => {
if (!isActive) return;
const layerId = useId();
// Auto-capture input when this dialog is mounted.
useInputLayer(layerId);
useLayeredInput(layerId, (_input, key) => {
if (key.return || key.escape) {
onClose();
}
}, { isActive });
});
const borderColor = type === 'error' ? colors.error :
type === 'success' ? colors.success :