diff --git a/packages/app/src/components/ui/combobox.tsx b/packages/app/src/components/ui/combobox.tsx index 8c05f61ab..fcf4b301c 100644 --- a/packages/app/src/components/ui/combobox.tsx +++ b/packages/app/src/components/ui/combobox.tsx @@ -17,7 +17,6 @@ import { ScrollView, Platform, StatusBar, - Keyboard, useWindowDimensions, type LayoutChangeEvent, type PressableStateCallbackType, @@ -60,6 +59,7 @@ import { type SheetHeader, } from "@/components/adaptive-modal-sheet"; import { FloatingSurface } from "@/components/ui/floating"; +import { useDismissKeyboardOnOpen } from "@/components/ui/keyboard-dismiss"; const IS_WEB = isWeb; @@ -738,9 +738,6 @@ function applySetOpen( onOpenChange: ((open: boolean) => void) | undefined, nextOpen: boolean, ) { - if (nextOpen) { - Keyboard.dismiss(); - } if (!isControlled) { setInternalOpen(nextOpen); } @@ -1026,7 +1023,7 @@ function MobileComboboxBody(props: MobileBodyProps): ReactElement { backgroundComponent={ComboboxSheetBackground} handleIndicatorStyle={props.handleIndicatorStyle} keyboardBehavior="extend" - keyboardBlurBehavior="restore" + keyboardBlurBehavior="none" > {props.header ? ( @@ -1486,6 +1483,7 @@ export function Combobox({ ); useWebKeyboardListener(isOpen, handleDesktopKey); + useDismissKeyboardOnOpen(isOpen, isMobile); const handleIndicatorStyle = useMemo( () => ({ backgroundColor: theme.colors.palette.zinc[600] }), diff --git a/packages/app/src/components/ui/dropdown-menu.tsx b/packages/app/src/components/ui/dropdown-menu.tsx index e49a48167..6dd62ea0e 100644 --- a/packages/app/src/components/ui/dropdown-menu.tsx +++ b/packages/app/src/components/ui/dropdown-menu.tsx @@ -18,7 +18,6 @@ import { Text, View, Dimensions, - Keyboard, Platform, StatusBar, type PressableProps, @@ -33,6 +32,7 @@ import { FloatingScrollView, FloatingSurface } from "@/components/ui/floating"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { useWebScrollbarStyle } from "@/hooks/use-web-scrollbar-style"; import { isWeb } from "@/constants/platform"; +import { useDismissKeyboardOnOpen } from "@/components/ui/keyboard-dismiss"; // Action status for menu items with loading/success feedback export type ActionStatus = "idle" | "pending" | "success"; @@ -91,9 +91,6 @@ function useControllableOpenState({ const value = isControlled ? open : internalOpen; const setValue = useCallback( (next: boolean) => { - if (next) { - Keyboard.dismiss(); - } if (!isControlled) setInternalOpen(next); onOpenChange?.(next); }, @@ -248,6 +245,7 @@ export function DropdownMenu({ defaultOpen, onOpenChange, }); + useDismissKeyboardOnOpen(isOpen); const flushPendingSelect = useCallback(() => { const pendingSelect = pendingSelectRef.current; diff --git a/packages/app/src/components/ui/keyboard-dismiss.ts b/packages/app/src/components/ui/keyboard-dismiss.ts new file mode 100644 index 000000000..94f6dac7b --- /dev/null +++ b/packages/app/src/components/ui/keyboard-dismiss.ts @@ -0,0 +1,17 @@ +import { useEffect } from "react"; +import { Keyboard } from "react-native"; + +export function useDismissKeyboardOnOpen(isOpen: boolean, enabled = true) { + useEffect(() => { + if (!enabled || !isOpen) return; + + Keyboard.dismiss(); + const frame = requestAnimationFrame(() => Keyboard.dismiss()); + const timer = setTimeout(() => Keyboard.dismiss(), 150); + + return () => { + cancelAnimationFrame(frame); + clearTimeout(timer); + }; + }, [enabled, isOpen]); +}