react-native-slot-text 2.1.0 → 2.2.1
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.
- package/AnimatedNumbers.js +16 -34
- package/Slot.js +6 -2
- package/package.json +1 -1
package/AnimatedNumbers.js
CHANGED
@@ -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) =>
|
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(
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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;
|
@@ -78,6 +80,7 @@ const AnimatedNumbers = (props) => {
|
|
78
80
|
setSlotHeight(e.nativeEvent.layout.height);
|
79
81
|
if (i === 10) {
|
80
82
|
setCommaWidth(e.nativeEvent.layout.width);
|
83
|
+
setSizesMeasured(true);
|
81
84
|
}
|
82
85
|
else {
|
83
86
|
const charSize = e.nativeEvent.layout.width;
|
@@ -86,28 +89,7 @@ const AnimatedNumbers = (props) => {
|
|
86
89
|
newSizes[i] = charSize;
|
87
90
|
return newSizes;
|
88
91
|
});
|
89
|
-
setSizesMeasured(true);
|
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
@@ -43,11 +43,15 @@ const Slot = (props) => {
|
|
43
43
|
margin.value = withTiming((props.charSizes[incomingValue] - props.charSizes[currentValue]), { duration: props.animationDuration / 2 });
|
44
44
|
if (incomingValue > currentValue) {
|
45
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 }, () => {
|
46
|
+
incomingY.value = withSequence(withTiming(-1 * props.height, { duration: 0, easing: Easing.ease }), withTiming(0, { duration: props.animationDuration }, () => {
|
47
|
+
props.onCompleted && runOnJS(props.onCompleted)();
|
48
|
+
}));
|
47
49
|
}
|
48
50
|
else if (incomingValue < currentValue) {
|
49
51
|
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 }, () => {
|
52
|
+
incomingY.value = withSequence(withTiming(1 * props.height, { duration: 0, easing: Easing.ease }), withTiming(0, { duration: props.animationDuration }, () => {
|
53
|
+
props.onCompleted && runOnJS(props.onCompleted)();
|
54
|
+
}));
|
51
55
|
}
|
52
56
|
}
|
53
57
|
}, [props.slot]);
|