CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-navigation--stack

Stack navigator component for iOS and Android with animated transitions and gestures

Pending
Overview
Eval results
Files

animation-utilities.mddocs/

Animation Utilities

Utility hooks and context providers for accessing animation values and gesture handlers within screen components, enabling custom animations and gesture-aware components.

Capabilities

useCardAnimation

Hook that provides access to card animation interpolation properties within stack screen components.

/**
 * Hook to access card animation values within stack screens
 * @returns Card animation interpolation properties
 * @throws Error if called outside of a stack screen context
 */
function useCardAnimation(): StackCardInterpolationProps;

Usage Examples:

import React from 'react';
import { Animated, View } from 'react-native';
import { useCardAnimation } from '@react-navigation/stack';

function AnimatedScreen() {
  const { current, closing, swiping } = useCardAnimation();

  // Create custom animations based on card animation progress
  const customOpacity = current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0.3, 1],
  });

  const customScale = current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0.9, 1],
  });

  const customRotation = current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: ['-5deg', '0deg'],
  });

  return (
    <Animated.View
      style={{
        flex: 1,
        opacity: customOpacity,
        transform: [
          { scale: customScale },
          { rotate: customRotation },
        ],
      }}
    >
      <View style={{ padding: 20 }}>
        <Text>Custom Animated Content</Text>
        
        {/* Animate based on swipe gesture */}
        <Animated.View
          style={{
            opacity: swiping.interpolate({
              inputRange: [0, 1],
              outputRange: [1, 0.5],
            }),
          }}
        >
          <Text>This fades during swipe gestures</Text>
        </Animated.View>

        {/* Animate based on closing state */}
        <Animated.View
          style={{
            transform: [{
              translateY: closing.interpolate({
                inputRange: [0, 1],
                outputRange: [0, -20],
              }),
            }],
          }}
        >
          <Text>This moves up when closing</Text>
        </Animated.View>
      </View>
    </Animated.View>
  );
}

useGestureHandlerRef

Hook that provides access to the gesture handler reference for coordinating custom gestures with navigation gestures.

/**
 * Hook to access gesture handler ref within stack screens
 * @returns Gesture handler reference for coordination with navigation gestures
 * @throws Error if called outside of a stack screen context
 */
function useGestureHandlerRef(): React.Ref<PanGestureHandler>;

Usage Examples:

import React from 'react';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import { useGestureHandlerRef } from '@react-navigation/stack';

function GestureAwareScreen() {
  const navigationGestureRef = useGestureHandlerRef();
  const customGestureRef = useRef();

  const handleGestureEvent = (event) => {
    // Custom gesture handling that works with navigation gestures
    console.log('Custom gesture:', event.nativeEvent);
  };

  const handleStateChange = (event) => {
    if (event.nativeEvent.state === State.END) {
      console.log('Custom gesture ended');
    }
  };

  return (
    <PanGestureHandler
      ref={customGestureRef}
      onGestureEvent={handleGestureEvent}
      onHandlerStateChange={handleStateChange}
      simultaneousHandlers={navigationGestureRef} // Allow simultaneous gestures
    >
      <View style={{ flex: 1 }}>
        <Text>Swipe me while navigation gestures still work!</Text>
      </View>
    </PanGestureHandler>
  );
}

CardAnimationContext

React context that provides card animation interpolation properties to child components.

/**
 * Context providing card animation interpolation props to child components
 * Value is undefined when not within a stack screen
 */
const CardAnimationContext: React.Context<StackCardInterpolationProps | undefined>;

Usage Examples:

import React, { useContext } from 'react';
import { CardAnimationContext } from '@react-navigation/stack';

function CustomAnimatedComponent() {
  const animationProps = useContext(CardAnimationContext);

  if (!animationProps) {
    // Not within a stack screen, render without animation
    return <StaticComponent />;
  }

  const { current, next, closing } = animationProps;

  const animatedOpacity = current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1],
  });

  return (
    <Animated.View style={{ opacity: animatedOpacity }}>
      <Text>Animated based on card transition</Text>
    </Animated.View>
  );
}

// Provider usage (automatically provided by stack navigator)
function CustomScreen() {
  return (
    <View>
      <CustomAnimatedComponent />
    </View>
  );
}

GestureHandlerRefContext

React context that provides the gesture handler reference for coordinating custom gestures.

/**
 * Context providing gesture handler ref to child components
 * Value is null when not within a stack screen
 */
const GestureHandlerRefContext: React.Context<React.Ref<PanGestureHandler> | null>;

Usage Examples:

import React, { useContext } from 'react';
import { PanGestureHandler } from 'react-native-gesture-handler';
import { GestureHandlerRefContext } from '@react-navigation/stack';

function NestedGestureComponent() {
  const navigationGestureRef = useContext(GestureHandlerRefContext);

  return (
    <PanGestureHandler
      simultaneousHandlers={navigationGestureRef}
      onGestureEvent={(event) => {
        // Handle custom gesture while preserving navigation gestures
        console.log('Nested gesture:', event.nativeEvent);
      }}
    >
      <View style={{ padding: 20, backgroundColor: 'lightblue' }}>
        <Text>This area has custom gestures that work with navigation</Text>
      </View>
    </PanGestureHandler>
  );
}

Advanced Animation Patterns

Coordinated Animations

Combine multiple animation utilities for complex effects:

import { useCardAnimation, useGestureHandlerRef } from '@react-navigation/stack';

function AdvancedAnimatedScreen() {
  const { current, next, closing, swiping } = useCardAnimation();
  const gestureRef = useGestureHandlerRef();

  // Parallax effect with background
  const backgroundTranslateX = current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [100, 0],
  });

  // Content animation with gesture awareness
  const contentOpacity = Animated.multiply(
    current.progress,
    swiping.interpolate({
      inputRange: [0, 1],
      outputRange: [1, 0.7],
    })
  );

  return (
    <View style={{ flex: 1 }}>
      {/* Animated background */}
      <Animated.View
        style={{
          position: 'absolute',
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          backgroundColor: 'lightblue',
          transform: [{ translateX: backgroundTranslateX }],
        }}
      />
      
      {/* Animated content */}
      <Animated.View
        style={{
          flex: 1,
          opacity: contentOpacity,
        }}
      >
        <Text>Advanced coordinated animation</Text>
      </Animated.View>
    </View>
  );
}

Conditional Animations

Use animation context for conditional rendering and animations:

function ConditionalAnimationScreen() {
  const animationProps = useCardAnimation();
  const isAnimating = animationProps ? animationProps.current.progress._value < 1 : false;

  return (
    <View style={{ flex: 1 }}>
      {isAnimating ? (
        <LoadingComponent />
      ) : (
        <MainContent />
      )}
      
      {animationProps && (
        <Animated.View
          style={{
            position: 'absolute',
            bottom: 20,
            right: 20,
            opacity: animationProps.current.progress.interpolate({
              inputRange: [0.8, 1],
              outputRange: [0, 1],
              extrapolate: 'clamp',
            }),
          }}
        >
          <FloatingActionButton />
        </Animated.View>
      )}
    </View>
  );
}

Animation Properties Reference

StackCardInterpolationProps

Complete properties available through animation utilities:

interface StackCardInterpolationProps {
  current: {
    progress: Animated.AnimatedInterpolation<number>;
  };
  next?: {
    progress: Animated.AnimatedInterpolation<number>;
  };
  index: number;
  closing: Animated.AnimatedInterpolation<0 | 1>;
  swiping: Animated.AnimatedInterpolation<0 | 1>;
  inverted: Animated.AnimatedInterpolation<-1 | 1>;
  layouts: {
    screen: Layout;
  };
  insets: {
    top: number;
    right: number;
    bottom: number;
    left: number;
  };
}

interface Layout {
  width: number;
  height: number;
}

These properties enable:

  • current.progress: Animation progress of the current screen (0 to 1)
  • next.progress: Animation progress of the next screen in stack (if exists)
  • closing: Whether the screen is closing (1) or opening (0)
  • swiping: Whether user is actively swiping (1) or not (0)
  • inverted: Animation direction multiplier (-1 for RTL, 1 for LTR)
  • layouts.screen: Screen dimensions for responsive animations
  • insets: Safe area insets for proper positioning

Install with Tessl CLI

npx tessl i tessl/npm-react-navigation--stack

docs

animation-utilities.md

card-animations.md

header-animations.md

index.md

stack-navigation.md

transition-presets.md

transition-specs.md

tile.json