diff --git a/src/screens/ComposeScreen.tsx b/src/screens/ComposeScreen.tsx index 0c4b0445..ae5d7e92 100644 --- a/src/screens/ComposeScreen.tsx +++ b/src/screens/ComposeScreen.tsx @@ -114,10 +114,11 @@ function RecipientChip({ recipient, onRemove }: { recipient: Recipient; onRemove } function SuggestionList({ - suggestions, onPick, + suggestions, onPick, onPressIn, }: { suggestions: Array<{ contact: ContactCard; name: string; email: string }>; onPick: (s: { name: string; email: string }) => void; + onPressIn?: () => void; }) { const c = useColors(); const styles = React.useMemo(() => makeStyles(c), [c]); @@ -128,6 +129,7 @@ function SuggestionList({ return ( onPick(s)} style={({ pressed }) => [styles.suggestionRow, pressed && styles.suggestionRowPressed]} > @@ -345,6 +347,7 @@ export default function ComposeScreen({ route, navigation }: Props) { }); const editorRef = React.useRef(null); + const isPickingSuggestion = React.useRef(false); // Track inline-image placeholders that haven't yet been rewritten to cid: // until send time. Maps cid → blobId/type/name/size. const inlineRegistryRef = React.useRef>(new Map()); @@ -377,6 +380,7 @@ export default function ComposeScreen({ route, navigation }: Props) { }, [suggestionQuery, individuals, alreadySelected]); const pickSuggestion = (s: { name: string; email: string }) => { + isPickingSuggestion.current = true; const recipient: Recipient = { name: s.name, email: s.email }; if (activeField === 'cc') { setCcRecipients((prev) => [...prev, recipient]); @@ -1001,7 +1005,7 @@ export default function ComposeScreen({ route, navigation }: Props) { @@ -1018,7 +1022,7 @@ export default function ComposeScreen({ route, navigation }: Props) { - + {t('email_composer.to', 'To')} {toRecipients.map((r, i) => ( @@ -1036,8 +1040,13 @@ export default function ComposeScreen({ route, navigation }: Props) { onChangeText={setToInput} onFocus={() => setActiveField('to')} onBlur={() => { - addTyped(); - setTimeout(() => setActiveField((f) => (f === 'to' ? null : f)), 200); + setTimeout(() => { + if (!isPickingSuggestion.current) { + addTyped(); + } + setActiveField((f) => (f === 'to' ? null : f)); + isPickingSuggestion.current = false; + }, 200); }} onSubmitEditing={addTyped} keyboardType="email-address" @@ -1046,7 +1055,13 @@ export default function ComposeScreen({ route, navigation }: Props) { /> {activeField === 'to' && suggestions.length > 0 && ( - + { + isPickingSuggestion.current = true; + }} + /> )} {!ccVisible && ( setCcVisible(true)} style={styles.ccToggle}> @@ -1056,7 +1071,7 @@ export default function ComposeScreen({ route, navigation }: Props) { {ccVisible && ( - + {t('email_composer.cc', 'Cc')} {ccRecipients.map((r, i) => ( @@ -1074,8 +1089,13 @@ export default function ComposeScreen({ route, navigation }: Props) { onChangeText={setCcInput} onFocus={() => setActiveField('cc')} onBlur={() => { - addTyped(); - setTimeout(() => setActiveField((f) => (f === 'cc' ? null : f)), 200); + setTimeout(() => { + if (!isPickingSuggestion.current) { + addTyped(); + } + setActiveField((f) => (f === 'cc' ? null : f)); + isPickingSuggestion.current = false; + }, 200); }} onSubmitEditing={addTyped} keyboardType="email-address" @@ -1084,7 +1104,13 @@ export default function ComposeScreen({ route, navigation }: Props) { /> {activeField === 'cc' && suggestions.length > 0 && ( - + { + isPickingSuggestion.current = true; + }} + /> )} )} @@ -1365,6 +1391,7 @@ function makeStyles(c: ThemePalette) { borderBottomWidth: 1, borderBottomColor: c.borderLight, gap: spacing.md, + position: 'relative', }, fieldLabel: { ...typography.body, @@ -1407,12 +1434,16 @@ function makeStyles(c: ThemePalette) { paddingVertical: 6, }, suggestionBox: { - marginTop: spacing.xs, - marginLeft: 60, + position: 'absolute', + top: '100%', + left: spacing.lg + 56 + spacing.md, + right: spacing.lg, borderWidth: 1, borderColor: c.borderLight, borderRadius: radius.sm, backgroundColor: c.card, + zIndex: 20, + elevation: 5, overflow: 'hidden', }, suggestionRow: {