import { useCallback } from 'react';
import {
findNodeHandle,
TextInput,
type BlurEvent,
type FocusEvent,
} from 'react-native';
import GorhomBottomSheetPackage from '../../../optional/gorhom-bottom-sheet';
/**
* Return type for the bottom-sheet-aware handlers hook
*/
interface UseBottomSheetAwareHandlersReturn {
/** Focus handler that notifies the bottom sheet about the keyboard target */
onFocus: (e: FocusEvent) => void;
/** Blur handler that conditionally clears the keyboard target in the bottom sheet */
onBlur: (e: BlurEvent) => void;
}
/**
* Hook that provides onFocus/onBlur handlers for managing bottom sheet
* keyboard state when an input is rendered inside a BottomSheet context.
*
* Uses `useBottomSheetInternal(true)` (unsafe mode) so it returns `null`
* instead of throwing when called outside a BottomSheet. When inside a
* BottomSheet it returns handlers that wire into the keyboard state
* management logic required by `@gorhom/bottom-sheet`.
*
* Pass the returned handlers to your `` or `` component:
*
* ```tsx
* const { onFocus, onBlur } = useBottomSheetAwareHandlers();
*
* ```
*
* @returns onFocus and onBlur handlers for bottom sheet keyboard management
*/
export function useBottomSheetAwareHandlers(): UseBottomSheetAwareHandlersReturn {
const useBottomSheetInternal =
GorhomBottomSheetPackage?.useBottomSheetInternal;
const bottomSheetContext = useBottomSheetInternal?.(true) ?? null;
const isActive = bottomSheetContext !== null;
/**
* Handles focus event: notifies the bottom sheet about the keyboard target.
*/
const onFocus = useCallback(
(e: FocusEvent) => {
if (isActive && bottomSheetContext) {
bottomSheetContext.animatedKeyboardState.set(
(state: Record) => ({
...state,
target: e.nativeEvent.target,
})
);
}
},
[isActive, bottomSheetContext]
);
/**
* Handles blur event: conditionally clears the keyboard target in the
* bottom sheet state.
*/
const onBlur = useCallback(
(e: BlurEvent) => {
if (isActive && bottomSheetContext) {
const keyboardState = bottomSheetContext.animatedKeyboardState.get();
// Legacy typings don't accept host instances in `findNodeHandle`.
const currentFocusedInput = findNodeHandle(
TextInput.State.currentlyFocusedInput() as unknown as Parameters<
typeof findNodeHandle
>[0]
);
const shouldRemoveCurrentTarget =
keyboardState.target === e.nativeEvent.target;
const shouldIgnoreBlurEvent =
currentFocusedInput &&
bottomSheetContext.textInputNodesRef.current.has(currentFocusedInput);
if (shouldRemoveCurrentTarget && !shouldIgnoreBlurEvent) {
bottomSheetContext.animatedKeyboardState.set(
(state: Record) => ({
...state,
target: undefined,
})
);
}
}
},
[isActive, bottomSheetContext]
);
return { onFocus, onBlur };
}