Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ReText, animatedProps text] Incorrect behavior with numeric text in fitting containers. Some numbers end with an ellipsis, IOS only #6752

Open
gendalf-thug opened this issue Nov 23, 2024 · 4 comments
Labels
Missing info The user didn't precise the problem enough Missing repro This issue need minimum repro scenario Platform: iOS This issue is specific to iOS

Comments

@gendalf-thug
Copy link

Description

Bug demo in my project: https://drive.google.com/file/d/1dP7aYLf2zNKQvo8odrSgdm9GzwNU-AqO/view?usp=share_link

Steps to reproduce

  1. Setup latest blank expo project(SDK 52) with reanimated 3.16.2
  2. Write this component or use ReText from 'react-native-redash' library
import {memo} from 'react'

import {StyleSheet, TextInput} from 'react-native'
import Animated, {
  SharedValue,
  AnimatedProps,
  useAnimatedProps,
} from 'react-native-reanimated'

import {Color} from 'src/themes'
import {IS_ANDROID} from 'src/variables'

import type {TextInputProps, TextProps as RNTextProps} from 'react-native'

interface TextProps extends Omit<TextInputProps, 'value' | 'style'> {
  text: SharedValue<string> | SharedValue<number>
  style?: AnimatedProps<RNTextProps>['style']
}
Animated.addWhitelistedNativeProps({text: true})

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)

export const AnimText = memo((props: TextProps) => {
  const {style, text, ...rest} = props

  const animatedProps = useAnimatedProps(() => {
    return {
      text: String(text.value),
    } as any
  })

  return (
    <AnimatedTextInput
      underlineColorAndroid="transparent"
      editable={false}
      value={String(text.value)}
      style={[styles.baseStyle, style || undefined]}
      {...rest}
      animatedProps={animatedProps}
    />
  )
})

const styles = StyleSheet.create({
  baseStyle: {
    color: Color.textPrimary,
    padding: IS_ANDROID ? 0 : undefined,
  },
})
  1. Component
import {useEffect} from 'react'
import {View} from 'react-native'
import {useDerivedValue, useSharedValue} from 'react-native-reanimated'
import {AnimText} from 'ui/AnimText'

const formatSecondsTimerWorklet = (sec_num: number) => {
  'worklet'
  let minutes, seconds, hours

  hours = Math.floor(sec_num / 3600)
  minutes = Math.floor((sec_num - hours * 3600) / 60)
  seconds = sec_num - hours * 3600 - minutes * 60

  if (minutes < 10) {
    minutes = '0' + minutes
  }
  if (seconds < 10) {
    seconds = '0' + seconds
  }
  if (hours < 10) {
    hours = '0' + hours
  }
  return hours + ':' + minutes + ':' + seconds
}

export default function App() {
  const timer = useSharedValue(1)
  const timerText = useDerivedValue(() => {
    return formatSecondsTimerWorklet(timer.value)
  }, [])

  useEffect(() => {
    const interval = setInterval(() => {
      timer.value += 1
    }, 1000)
    return () => {
      clearInterval(interval)
    }
  }, [])

  return (
    <View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
      <AnimText style={{fontSize: 50}} text={timerText} defaultValue="00:00" />
    </View>
  )
}

Code preview
Снимок экрана 2024-11-23 в 20 26 11

Snack or a link to a repository

Reanimated version

3.16.2

React Native version

0.76.3

Platforms

iOS

JavaScript runtime

None

Workflow

Expo Go

Architecture

None

Build type

None

Device

None

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Missing repro This issue need minimum repro scenario Missing info The user didn't precise the problem enough labels Nov 23, 2024
Copy link

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

Copy link

Hey! 👋

It looks like you've omitted a few important sections from the issue template.

Please complete Snack or a link to a repository section.

@github-actions github-actions bot added the Platform: iOS This issue is specific to iOS label Nov 23, 2024
@gendalf-thug
Copy link
Author

Help? Feedback? Human’s comment?

@dhruv-00
Copy link

Facing Same issue

Here is minimal Reproducible

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  useAnimatedProps,
  runOnJS,
} from 'react-native-reanimated';

const SLIDER_WIDTH = 300;

Animated.addWhitelistedNativeProps({ text: true });

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

interface RangePickerProps {
  initialValue?: number; // in meters
  maxValue?: number; // in meters
  unit?: string;
  onValueChange?: (value: number) => void;
}

const theme = {
  colors: {
    primary: '#b58df1',
  },
};

const RangePicker: React.FC<RangePickerProps> = ({
  initialValue = 0,
  maxValue = 100,
  unit = 'm',
  onValueChange,
}) => {
  const SLIDER_PADDING = 5;
  const HANDLE_WIDTH = 40;
  const USABLE_WIDTH = SLIDER_WIDTH - HANDLE_WIDTH - SLIDER_PADDING * 2;

  // Convert initial value to slider position
  const initialOffset = (initialValue / maxValue) * USABLE_WIDTH;
  const offset = useSharedValue(initialOffset);
  const currentValue = useSharedValue(initialValue);

  const pan = Gesture.Pan().onChange((event) => {
    const newOffset = Math.max(
      0,
      Math.min(USABLE_WIDTH, offset.value + event.changeX)
    );
    offset.value = newOffset;

    // Calculate value with better precision
    const rawValue = (newOffset / USABLE_WIDTH) * maxValue;
    const newValue = Math.round(rawValue);
    currentValue.value = newValue;
    onValueChange && runOnJS(onValueChange)(newValue);
  });

  const sliderStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: offset.value }],
  }));

  const animatedProps = useAnimatedProps(() => {
    const displayValue = currentValue.value.toFixed(0);
    return {
      text: displayValue.toString(),
      defaultValue: displayValue.toString(),
    };
  });

  return (
    <View style={styles.container}>
      <View style={styles.rangePickerContainer}>
        <AnimatedTextInput
          animatedProps={animatedProps}
          style={[styles.boxWidthText, { color: theme.colors.primary }]}
          editable={false}
        />
        <Text style={[styles.boxWidthText, { color: theme.colors.primary }]}>
          {' ' + unit}
        </Text>
      </View>
      <View style={styles.sliderTrack}>
        <GestureDetector gesture={pan}>
          <Animated.View style={[styles.sliderHandle, sliderStyle]} />
        </GestureDetector>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 32,
  },
  sliderTrack: {
    width: SLIDER_WIDTH,
    height: 30,
    backgroundColor: theme.colors.primary,
    borderRadius: 25,
    justifyContent: 'center',
    padding: 5,
  },
  sliderHandle: {
    width: 25,
    aspectRatio: 1,
    backgroundColor: '#f8f9ff',
    borderRadius: 20,
    position: 'absolute',
    left: 5,
  },
  box: {
    height: 30,
    backgroundColor: '#b58df1',
    borderRadius: 10,
  },
  boxWidthText: {
    textAlign: 'center',
    fontSize: 24,
  },
  rangePickerContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
});

export default RangePicker;

The issue I'm facing is the number are divided by 1000 and I don't know why

Simulator.Screen.Recording.-.iPhone.15.-.2024-12-12.at.17.37.33.online-video-cutter.com.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Missing info The user didn't precise the problem enough Missing repro This issue need minimum repro scenario Platform: iOS This issue is specific to iOS
Projects
None yet
Development

No branches or pull requests

2 participants