All files / apps/reallocation/src/screens/ChooseObserver/hooks useSearchOverlayAnimation.ts

90% Statements 27/30
70% Branches 7/10
75% Functions 6/8
89.65% Lines 26/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83                            1x     4x 4x 4x 4x   4x         4x 3x 3x 3x     3x 2x   2x 2x         2x           2x 2x 2x         1x   1x 1x       1x 1x         1x 1x           4x              
import { useEffect, useRef, useState } from 'react';
import {
  Easing,
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';
import { InteractionManager, Keyboard, TextInput } from 'react-native';
 
type UseSearchOverlayAnimationParams = {
  isSearchOpen: boolean;
};
 
export const useSearchOverlayAnimation = ({
  isSearchOpen,
}: UseSearchOverlayAnimationParams) => {
  const searchInputRef = useRef<TextInput>(null);
  const overlayOpacity = useSharedValue(0);
  const overlayTranslateY = useSharedValue(8);
  const [isSearchInteractive, setIsSearchInteractive] = useState(false);
 
  const searchOverlayAnimatedStyle = useAnimatedStyle(() => ({
    opacity: overlayOpacity.value,
    transform: [{ translateY: overlayTranslateY.value }],
  }));
 
  useEffect(() => {
    const openDuration = 220;
    const closeDuration = 180;
    const easing = Easing.out(Easing.cubic);
    let focusTimeout: ReturnType<typeof setTimeout> | undefined;
 
    if (isSearchOpen) {
      setIsSearchInteractive(true);
 
      overlayOpacity.value = withTiming(1, { duration: openDuration, easing });
      overlayTranslateY.value = withTiming(0, {
        duration: openDuration,
        easing,
      });
 
      focusTimeout = setTimeout(() => {
        InteractionManager.runAfterInteractions(() => {
          searchInputRef.current?.focus();
        });
      }, 120);
 
      return () => {
        Eif (focusTimeout) {
          clearTimeout(focusTimeout);
        }
      };
    }
 
    Keyboard.dismiss();
 
    overlayOpacity.value = withTiming(0, { duration: closeDuration, easing });
    overlayTranslateY.value = withTiming(
      8,
      { duration: closeDuration, easing },
      finished => {
        Eif (finished) {
          runOnJS(setIsSearchInteractive)(false);
        }
      },
    );
 
    return () => {
      Iif (focusTimeout) {
        clearTimeout(focusTimeout);
      }
    };
  }, [isSearchOpen, overlayOpacity, overlayTranslateY]);
 
  return {
    searchInputRef,
    isSearchInteractive,
    shouldHideBaseContent: isSearchOpen || isSearchInteractive,
    searchOverlayAnimatedStyle,
  };
};