react-native-ui-lib icon indicating copy to clipboard operation
react-native-ui-lib copied to clipboard

Expo SDK 54 - Progress Bar Error

Open jdelaney3097 opened this issue 3 months ago • 2 comments

Description

After upgrading to Expo SDK 54 and react native 19, Progress bar is giving an error : [TypeError: Cannot read property 'props' of undefined]

Related to

  • [ x ] Components
  • [ ] Demo
  • [ ] Docs
  • [ ] Typings

Steps to reproduce

  1. Use expo SDK 54 and react native 19
  2. Import progress bar and try to use it

Expected behavior

Progress bar loads and user is able to use the component

Actual behavior

App gives an error

More Info

Code snippet

import { ProgressBar } from "react-native-ui-lib";
<ProgressBar progress={progressBarValue} />

Screenshots/Video

Image Image

Environment

  • React Native version: 19.1.0
  • React Native UI Lib version: ^7.46.3

Affected platforms

  • [ x ] Android
  • [ x ] iOS
  • [ ] Web

jdelaney3097 avatar Sep 19 '25 01:09 jdelaney3097

How did you get it working with SDK 54? I am getting #3805

ferretwithaberet avatar Sep 19 '25 06:09 ferretwithaberet

Same issue in last expo version But you can make the progress bar by yourself

import { View } from '@/components/ui/view';
import { useColor } from '@/hooks/useColor';
import { HEIGHT } from '@/theme/globals';
import React, { useEffect } from 'react';
import { ViewStyle } from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';

interface ProgressProps {
  value: number; // 0-100
  style?: ViewStyle;
  height?: number;
  onValueChange?: (value: number) => void;
  onSeekStart?: () => void;
  onSeekEnd?: () => void;
  interactive?: boolean;
}

export function Progress({
  value,
  style,
  height = HEIGHT,
  onValueChange,
  onSeekStart,
  onSeekEnd,
  interactive = false,
}: ProgressProps) {
  const primaryColor = useColor('primary');
  const mutedColor = useColor('muted');

  const clampedValue = Math.max(0, Math.min(100, value));
  const progressWidth = useSharedValue(clampedValue);
  const containerWidth = useSharedValue(200); // Default width, will be updated
  const isDragging = useSharedValue(false);

  // Update animation when value prop changes (only if not dragging)
  useEffect(() => {
    if (!isDragging.value) {
      progressWidth.value = withTiming(clampedValue, { duration: 300 });
    }
  }, [clampedValue]);

  const updateValue = (newValue: number) => {
    const clamped = Math.max(0, Math.min(100, newValue));
    onValueChange?.(clamped);
  };

  const handleSeekStart = () => {
    isDragging.value = true;
    onSeekStart?.();
  };

  const handleSeekEnd = () => {
    isDragging.value = false;
    onSeekEnd?.();
  };

  // Create pan gesture using the new Gesture API
  const panGesture = Gesture.Pan()
    .onStart(() => {
      if (!interactive) return;
      runOnJS(handleSeekStart)();
    })
    .onUpdate((event) => {
      if (!interactive) return;

      // Calculate new progress based on gesture position
      const newProgress = (event.x / containerWidth.value) * 100;
      const clampedProgress = Math.max(0, Math.min(100, newProgress));

      progressWidth.value = clampedProgress;
      runOnJS(updateValue)(clampedProgress);
    })
    .onEnd(() => {
      if (!interactive) return;
      runOnJS(handleSeekEnd)();
    });

  // Create tap gesture for direct seeking
  const tapGesture = Gesture.Tap().onStart((event) => {
    if (!interactive) return;

    runOnJS(handleSeekStart)();

    // Calculate progress based on tap position
    const newProgress = (event.x / containerWidth.value) * 100;
    const clampedProgress = Math.max(0, Math.min(100, newProgress));

    progressWidth.value = withTiming(clampedProgress, { duration: 200 });
    runOnJS(updateValue)(clampedProgress);

    setTimeout(() => {
      runOnJS(handleSeekEnd)();
    }, 200);
  });

  // Combine gestures
  const combinedGesture = Gesture.Race(panGesture, tapGesture);

  const animatedProgressStyle = useAnimatedStyle(() => {
    return {
      width: `${progressWidth.value}%`,
    };
  });

  const containerStyle: ViewStyle[] = [
    {
      height: height,
      width: '100%' as const,
      backgroundColor: mutedColor,
      borderRadius: height / 2,
      overflow: 'hidden' as const,
    },
    ...(style ? [style] : []),
  ];

  const onLayout = (event: any) => {
    containerWidth.value = event.nativeEvent.layout.width;
  };

  if (interactive) {
    return (
      <GestureDetector gesture={combinedGesture}>
        <Animated.View style={containerStyle} onLayout={onLayout}>
          <Animated.View
            style={[
              {
                height: '100%' as const,
                backgroundColor: primaryColor,
                borderRadius: height / 2,
              },
              animatedProgressStyle,
            ]}
          />
        </Animated.View>
      </GestureDetector>
    );
  }

  return (
    <View style={containerStyle} onLayout={onLayout}>
      <Animated.View
        style={[
          {
            height: '100%' as const,
            backgroundColor: primaryColor,
            borderRadius: height / 2,
          },
          animatedProgressStyle,
        ]}
      />
    </View>
  );
}


Note: I refer other UI Lib

Vn-ChemGio avatar Nov 27 '25 11:11 Vn-ChemGio