import React from 'react'; import { type ExitState, useExitOnCtrlCDWithKeybindings } from '../hooks/useExitOnCtrlCD.js'; import { Box, Text } from '../index.js'; import { useKeybinding } from '../keybindings/useKeybinding.js'; import type { Theme } from './theme-types.js'; import { ConfigurableShortcutHint } from './ConfigurableShortcutHint.js'; import { Byline } from './Byline.js'; import { KeyboardShortcutHint } from './KeyboardShortcutHint.js'; import { Pane } from './Pane.js'; type DialogProps = { title: React.ReactNode; subtitle?: React.ReactNode; children: React.ReactNode; onCancel: () => void; color?: keyof Theme; hideInputGuide?: boolean; hideBorder?: boolean; /** Custom input guide content. Receives exitState for Ctrl+C/D pending display. */ inputGuide?: (exitState: ExitState) => React.ReactNode; /** * Controls whether Dialog's built-in confirm:no (Esc/n) and app:exit/interrupt * (Ctrl-C/D) keybindings are active. Set to `false` while an embedded text * field is being edited so those keys reach the field instead of being * consumed by Dialog. TextInput has its own ctrl+c/d handlers (cancel on * press, delete-forward on ctrl+d with text). Defaults to `true`. */ isCancelActive?: boolean; }; export function Dialog({ title, subtitle, children, onCancel, color = 'permission', hideInputGuide, hideBorder, inputGuide, isCancelActive = true, }: DialogProps): React.ReactNode { const exitState = useExitOnCtrlCDWithKeybindings(undefined, undefined, isCancelActive); // Use configurable keybinding for ESC to cancel. // isCancelActive lets consumers (e.g. ElicitationDialog) disable this while // an embedded TextInput is focused, so that keys like 'n' reach the field // instead of being consumed here. useKeybinding('confirm:no', onCancel, { context: 'Confirmation', isActive: isCancelActive, }); const defaultInputGuide = exitState.pending ? ( Press {exitState.keyName} again to exit ) : ( ); const content = ( <> {title} {subtitle && {subtitle}} {children} {!hideInputGuide && ( {inputGuide ? inputGuide(exitState) : defaultInputGuide} )} ); if (hideBorder) { return content; } return {content}; }