react-native-slot-text 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/AnimatedNumbers.js +15 -33
  2. package/Slot.js +14 -17
  3. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState, useRef, Fragment, useLayoutEffect, useCallback } from "react";
2
+ import { useState, useRef, Fragment, useLayoutEffect, useCallback, useEffect } from "react";
3
3
  import { View, Text } from "react-native";
4
4
  import { useSharedValue } from 'react-native-reanimated';
5
5
  import styles from './styles';
@@ -28,13 +28,12 @@ const AnimatedNumbers = (props) => {
28
28
  // [number, number]: animating slot
29
29
  const idRef = useRef(`slots-${Math.random().toString(36).substring(7)}`);
30
30
  // Indexes of slots that have finished animating
31
- const slotsTrashBin = useSharedValue([]);
32
31
  const queuedNumber = useSharedValue(null);
33
32
  const [slots, setSlots] = useState([]);
34
33
  const [commaPositions, setCommaPositions] = useState([]);
35
34
  const [commaWidth, setCommaWidth] = useState(0);
36
35
  const [sizesMeasured, setSizesMeasured] = useState(false);
37
- const [keys, setKeys] = useState(Array.from({ length: props.value.toString().length }).map((_, i) => i));
36
+ const [keys, setKeys] = useState(Array.from({ length: props.value.toString().length }).map((_, i) => Math.random().toString(36).substring(2, 9)));
38
37
  const [slotHeight, setSlotHeight] = useState(0);
39
38
  const [charSizes, setCharSizes] = useState(Array.from({ length: 10 }).map((_, i) => 0));
40
39
  useLayoutEffect(() => {
@@ -48,7 +47,15 @@ const AnimatedNumbers = (props) => {
48
47
  setCommaPositions(newCommaPositions);
49
48
  }
50
49
  const newSlots = getNewSlots(props.value, slots, parseFromLeft);
51
- setKeys(Array.from({ length: newSlots.length }).map((_, i) => i));
50
+ setKeys(prev => prev.length > newSlots.length
51
+ ? newSlots[0]?.[1] === null
52
+ ? prev.slice(-1 * prev.length - newSlots.length)
53
+ : prev.slice(0, newSlots.length)
54
+ : prev.length < newSlots.length
55
+ ? newSlots[0]?.[0] === null
56
+ ? Array.from({ length: newSlots.length - prev.length }).map((_, i) => Math.random().toString(36).substring(2, 9)).concat(prev)
57
+ : prev.concat(Array.from({ length: newSlots.length - prev.length }).map((_, i) => Math.random().toString(36).substring(2, 9)))
58
+ : prev);
52
59
  setSlots(newSlots);
53
60
  }
54
61
  }, [props.value]);
@@ -61,15 +68,10 @@ const AnimatedNumbers = (props) => {
61
68
  .map(c => c === -1 ? null : c === 1 ? 0 : c)
62
69
  .slice(slots[0]?.[1] === null ? numberOfSlotsRemoved : 0) // Trim from left
63
70
  .slice(0, slots[slots.length - 1]?.[1] === null ? -1 * numberOfSlotsRemoved : undefined); // Trim from right
64
- if (cleanedSlots.length < slots.length) {
65
- setKeys(prev => prev.slice(-1 * cleanedSlots.length));
66
- }
67
- else {
68
- setKeys(Array.from({ length: cleanedSlots.length }).map((_, i) => i));
69
- }
70
- setSlots(cleanedSlots);
71
- setCommaPositions(cleanedCommas);
72
- slotsTrashBin.value = [];
71
+ setTimeout(() => {
72
+ setSlots(cleanedSlots);
73
+ setCommaPositions(cleanedCommas);
74
+ }, 0);
73
75
  }, [slots, commaPositions]);
74
76
  return (_jsxs(_Fragment, { children: [_jsxs(View, { style: styles.slotsContainer, children: [props.prefix && (_jsx(Text, { style: props.fontStyle, children: props.prefix })), slots.map((slot, i) => {
75
77
  const callback = i === slots.findIndex(s => s.length > 1) ? onCompleted : undefined;
@@ -90,24 +92,4 @@ const AnimatedNumbers = (props) => {
90
92
  }
91
93
  }, children: i === 10 ? ',' : i }, `slot-${i}`) }, `measure-slot-${i}`)))] }));
92
94
  };
93
- /*
94
- Basic logic:
95
-
96
- When a new value comes in:
97
-
98
- 1. If there is an animation currently in progress then queue the new value with any prefix prepended
99
-
100
- 2. For an animation cycle, split the new number and set the new number state
101
-
102
- 3. Loop through the new number and old number and compare digits, determing which way the new numbers
103
- and old numers need to animate. There are two versions of the number, one that's visible, and one outside
104
- the visible clipping container. If a slot has the same number between the old and new nummer, it wont be animated.
105
-
106
- 4. Set the new positions wich will trigger the animations of the slots
107
-
108
- 5. At the end, clear the new number and set the old number to the new number
109
-
110
- 6. Pop any queued values and set the formated value, which will retriger the animation cycle
111
-
112
- */
113
95
  export default AnimatedNumbers;
package/Slot.js CHANGED
@@ -4,9 +4,8 @@ import { View } from 'react-native';
4
4
  import { Text } from 'react-native';
5
5
  import Animated, { useSharedValue, withTiming, withSequence, useAnimatedStyle, interpolate, runOnJS, Easing } from 'react-native-reanimated';
6
6
  import styles from './styles';
7
+ const easing = Easing.bezier(0.22, 0.48, 0.25, 1.02);
7
8
  const Slot = (props) => {
8
- const [value1, setValue1] = useState();
9
- const [value2, setValue2] = useState();
10
9
  const margin = useSharedValue(0);
11
10
  const y = useSharedValue(0);
12
11
  const incomingY = useSharedValue(0);
@@ -26,7 +25,7 @@ const Slot = (props) => {
26
25
  }
27
26
  // Removing slot
28
27
  else if (incomingValue === null) {
29
- y.value = withTiming(-1 * props.height, { duration: props.animationDuration, easing: Easing.ease }, () => {
28
+ y.value = withTiming(-1 * props.height, { duration: props.animationDuration, easing }, () => {
30
29
  props.onCompleted && runOnJS(props.onCompleted)();
31
30
  });
32
31
  margin.value = withTiming(-1 * props.charSizes[currentValue], { duration: props.animationDuration / 2 });
@@ -34,7 +33,7 @@ const Slot = (props) => {
34
33
  // Adding slot
35
34
  else if (currentValue === null) {
36
35
  margin.value = withTiming(props.charSizes[incomingValue], { duration: props.animationDuration / 2 });
37
- incomingY.value = withSequence(withTiming(-1 * props.height, { duration: 0 }), withTiming(0, { duration: props.animationDuration, easing: Easing.ease }, () => {
36
+ incomingY.value = withSequence(withTiming(-1 * props.height, { duration: 0 }), withTiming(0, { duration: props.animationDuration, easing }, () => {
38
37
  props.onCompleted && runOnJS(props.onCompleted)();
39
38
  }));
40
39
  }
@@ -42,21 +41,19 @@ const Slot = (props) => {
42
41
  else {
43
42
  margin.value = withTiming((props.charSizes[incomingValue] - props.charSizes[currentValue]), { duration: props.animationDuration / 2 });
44
43
  if (incomingValue > currentValue) {
45
- y.value = withTiming(props.height, { duration: props.animationDuration, easing: Easing.ease });
46
- incomingY.value = withSequence(withTiming(-1 * props.height, { duration: 0, easing: Easing.ease }), withTiming(0, { duration: props.animationDuration }, () => { props.onCompleted && runOnJS(props.onCompleted)(); }));
44
+ y.value = withTiming(props.height, { duration: props.animationDuration, easing });
45
+ incomingY.value = withSequence(withTiming(-1 * props.height, { duration: 0, easing }), withTiming(0, { duration: props.animationDuration }, () => {
46
+ props.onCompleted && runOnJS(props.onCompleted)();
47
+ }));
47
48
  }
48
49
  else if (incomingValue < currentValue) {
49
- y.value = withTiming(-1 * props.height, { duration: props.animationDuration, easing: Easing.ease });
50
- incomingY.value = withSequence(withTiming(1 * props.height, { duration: 0, easing: Easing.ease }), withTiming(0, { duration: props.animationDuration }, () => { props.onCompleted && runOnJS(props.onCompleted)(); }));
50
+ y.value = withTiming(-1 * props.height, { duration: props.animationDuration, easing });
51
+ incomingY.value = withSequence(withTiming(1 * props.height, { duration: 0, easing }), withTiming(0, { duration: props.animationDuration }, () => {
52
+ props.onCompleted && runOnJS(props.onCompleted)();
53
+ }));
51
54
  }
52
55
  }
53
56
  }, [props.slot]);
54
- useLayoutEffect(() => {
55
- if (props.slot) {
56
- setValue1(props.slot[0]);
57
- setValue2(props.slot[1]);
58
- }
59
- }, [props.slot]);
60
57
  useLayoutEffect(() => {
61
58
  if (props.commaPositions?.[props.index] === 1) {
62
59
  commaScale.value = withTiming(1, { duration: props.animationDuration });
@@ -106,8 +103,8 @@ const Slot = (props) => {
106
103
  const currentTextStyle = useAnimatedStyle(() => ({
107
104
  transform: [{ rotateX: `${interpolate(y.value, [-1 * props.height / 2, 0, props.height / 2], [90, 0, -90])}deg` }]
108
105
  }));
109
- return (_jsxs(View, { style: styles.slotContainer, children: [_jsx(Animated.View, { style: currentStyle, children: Number.isFinite(value1) &&
110
- _jsx(Animated.Text, { style: [props.fontStyle, currentTextStyle], children: value1 }) }), _jsx(Animated.View, { style: incomingStyle, children: Number.isFinite(value2) &&
111
- _jsx(Animated.Text, { style: [props.fontStyle, incomingTextStyle], children: value2 }) }), _jsx(Text, { style: styles.hiddenSlot, children: "1" }), _jsx(Animated.View, { style: commaStyle, children: _jsx(Text, { style: props.fontStyle, children: "," }) })] }));
106
+ return (_jsxs(View, { style: styles.slotContainer, children: [_jsx(Animated.View, { style: currentStyle, children: Number.isFinite(props.slot[0]) &&
107
+ _jsx(Animated.Text, { style: [props.fontStyle, currentTextStyle], children: props.slot[0] }) }), _jsx(Animated.View, { style: incomingStyle, children: Number.isFinite(props.slot[1]) &&
108
+ _jsx(Animated.Text, { style: [props.fontStyle, incomingTextStyle], children: props.slot[1] }) }), _jsx(Text, { style: styles.hiddenSlot, children: "1" }), _jsx(Animated.View, { style: commaStyle, children: _jsx(Text, { style: props.fontStyle, children: "," }) })] }));
112
109
  };
113
110
  export default Slot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-slot-text",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "author": "sc-mitton <scm.mitton@gmail.com> (https://github.com/sc-mitton)",
5
5
  "main": "index.js",
6
6
  "module": "index.ts",