rn-marquee-text 2.1.1-beta.1 → 2.1.2-beta.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/dist/MarqueeText.d.ts +0 -86
- package/dist/MarqueeText.js +33 -51
- package/package.json +1 -1
package/dist/MarqueeText.d.ts
CHANGED
|
@@ -1,119 +1,33 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { ViewStyle, TextStyle } from "react-native";
|
|
3
|
-
/**
|
|
4
|
-
* Animation modes for the marquee text
|
|
5
|
-
*/
|
|
6
3
|
declare enum AnimationMode {
|
|
7
4
|
LOOP = "loop",
|
|
8
5
|
BOUNCE = "bounce"
|
|
9
6
|
}
|
|
10
|
-
/**
|
|
11
|
-
* Direction of the marquee animation
|
|
12
|
-
*/
|
|
13
7
|
type MarqueeDirection = "horizontal" | "vertical";
|
|
14
|
-
/**
|
|
15
|
-
* Props for the MarqueeText component
|
|
16
|
-
*/
|
|
17
8
|
interface MarqueeTextProps {
|
|
18
|
-
/**
|
|
19
|
-
* Content to be scrolled (string or React nodes)
|
|
20
|
-
*/
|
|
21
9
|
children: React.ReactNode;
|
|
22
|
-
/**
|
|
23
|
-
* The animation mode: 'loop' for continuous scrolling or 'bounce' for back-and-forth
|
|
24
|
-
* @default AnimationMode.LOOP
|
|
25
|
-
*/
|
|
26
10
|
mode?: AnimationMode;
|
|
27
|
-
/**
|
|
28
|
-
* Speed of the scrolling animation in pixels per second
|
|
29
|
-
* @default 30
|
|
30
|
-
*/
|
|
31
11
|
speed?: number;
|
|
32
|
-
/**
|
|
33
|
-
* Delay in milliseconds before starting the animation
|
|
34
|
-
* @default 1500
|
|
35
|
-
*/
|
|
36
12
|
delay?: number;
|
|
37
|
-
/**
|
|
38
|
-
* Duration in milliseconds to pause at the end of the content (only for bounce mode)
|
|
39
|
-
* @default 1000
|
|
40
|
-
*/
|
|
41
13
|
endPauseDuration?: number;
|
|
42
|
-
/**
|
|
43
|
-
* Container style
|
|
44
|
-
*/
|
|
45
14
|
style?: ViewStyle;
|
|
46
|
-
/**
|
|
47
|
-
* Text style (when children is a string)
|
|
48
|
-
*/
|
|
49
15
|
textStyle?: TextStyle;
|
|
50
|
-
/**
|
|
51
|
-
* Whether to enable the animation
|
|
52
|
-
* @default true
|
|
53
|
-
*/
|
|
54
16
|
enabled?: boolean;
|
|
55
|
-
/**
|
|
56
|
-
* Direction of scrolling ('horizontal' or 'vertical')
|
|
57
|
-
* @default 'horizontal'
|
|
58
|
-
*/
|
|
59
17
|
direction?: MarqueeDirection;
|
|
60
|
-
/**
|
|
61
|
-
* Spacing between cloned elements
|
|
62
|
-
* @default 20
|
|
63
|
-
*/
|
|
64
18
|
spacing?: number;
|
|
65
|
-
/**
|
|
66
|
-
* Allow user interaction with gesture handling
|
|
67
|
-
* @default true
|
|
68
|
-
*/
|
|
69
19
|
withGesture?: boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Custom frame rate for animation
|
|
72
|
-
*/
|
|
73
20
|
frameRate?: number;
|
|
74
|
-
/**
|
|
75
|
-
* Reverse the animation direction
|
|
76
|
-
* @default false
|
|
77
|
-
*/
|
|
78
21
|
reverse?: boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Background color for the container
|
|
81
|
-
* @default 'transparent'
|
|
82
|
-
*/
|
|
83
22
|
backgroundColor?: string;
|
|
84
|
-
/**
|
|
85
|
-
* Callback when animation starts
|
|
86
|
-
*/
|
|
87
23
|
onAnimationStart?: () => void;
|
|
88
|
-
/**
|
|
89
|
-
* Callback when animation stops
|
|
90
|
-
*/
|
|
91
24
|
onAnimationStop?: () => void;
|
|
92
25
|
}
|
|
93
|
-
/**
|
|
94
|
-
* Reference handle for the MarqueeText component
|
|
95
|
-
*/
|
|
96
26
|
export interface MarqueeTextRef {
|
|
97
|
-
/**
|
|
98
|
-
* Start the marquee animation
|
|
99
|
-
*/
|
|
100
27
|
start: () => void;
|
|
101
|
-
/**
|
|
102
|
-
* Stop the marquee animation
|
|
103
|
-
*/
|
|
104
28
|
stop: () => void;
|
|
105
|
-
/**
|
|
106
|
-
* Whether the animation is currently active
|
|
107
|
-
*/
|
|
108
29
|
isActive: boolean;
|
|
109
30
|
}
|
|
110
|
-
/**
|
|
111
|
-
* MarqueeText component for scrolling text or content
|
|
112
|
-
*
|
|
113
|
-
* This component creates a scrolling effect for text or other content.
|
|
114
|
-
* It supports both horizontal and vertical scrolling, different animation
|
|
115
|
-
* modes, and user interaction via gestures.
|
|
116
|
-
*/
|
|
117
31
|
declare const MarqueeText: React.ForwardRefExoticComponent<MarqueeTextProps & React.RefAttributes<MarqueeTextRef>>;
|
|
118
32
|
export { AnimationMode };
|
|
119
33
|
export type { MarqueeDirection, MarqueeTextProps };
|
package/dist/MarqueeText.js
CHANGED
|
@@ -2,17 +2,11 @@ import * as React from "react";
|
|
|
2
2
|
import { StyleSheet, View, Text, } from "react-native";
|
|
3
3
|
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
4
4
|
import Animated, { runOnJS, useAnimatedReaction, useAnimatedStyle, useSharedValue, useFrameCallback, withDecay, } from "react-native-reanimated";
|
|
5
|
-
/**
|
|
6
|
-
* Animation modes for the marquee text
|
|
7
|
-
*/
|
|
8
5
|
var AnimationMode;
|
|
9
6
|
(function (AnimationMode) {
|
|
10
7
|
AnimationMode["LOOP"] = "loop";
|
|
11
8
|
AnimationMode["BOUNCE"] = "bounce";
|
|
12
9
|
})(AnimationMode || (AnimationMode = {}));
|
|
13
|
-
/**
|
|
14
|
-
* Component to render a child item in the marquee
|
|
15
|
-
*/
|
|
16
10
|
var AnimatedChild = React.memo(function (_a) {
|
|
17
11
|
var index = _a.index, children = _a.children, anim = _a.anim, contentMeasurement = _a.contentMeasurement, spacing = _a.spacing, direction = _a.direction;
|
|
18
12
|
var style = useAnimatedStyle(function () {
|
|
@@ -36,21 +30,9 @@ var AnimatedChild = React.memo(function (_a) {
|
|
|
36
30
|
}, [index, spacing, contentMeasurement, direction]);
|
|
37
31
|
return <Animated.View style={style}>{children}</Animated.View>;
|
|
38
32
|
});
|
|
39
|
-
/**
|
|
40
|
-
* MarqueeText component for scrolling text or content
|
|
41
|
-
*
|
|
42
|
-
* This component creates a scrolling effect for text or other content.
|
|
43
|
-
* It supports both horizontal and vertical scrolling, different animation
|
|
44
|
-
* modes, and user interaction via gestures.
|
|
45
|
-
*/
|
|
46
33
|
var MarqueeText = React.forwardRef(function (_a, ref) {
|
|
47
34
|
var children = _a.children, _b = _a.mode, mode = _b === void 0 ? AnimationMode.LOOP : _b, _c = _a.speed, speed = _c === void 0 ? 30 : _c, _d = _a.delay, delay = _d === void 0 ? 1500 : _d, _e = _a.endPauseDuration, endPauseDuration = _e === void 0 ? 1000 : _e, style = _a.style, textStyle = _a.textStyle, _f = _a.enabled, enabled = _f === void 0 ? true : _f, _g = _a.direction, direction = _g === void 0 ? "horizontal" : _g, _h = _a.spacing, spacing = _h === void 0 ? 20 : _h, _j = _a.withGesture, withGesture = _j === void 0 ? true : _j, frameRate = _a.frameRate, _k = _a.reverse, reverse = _k === void 0 ? false : _k, _l = _a.backgroundColor, backgroundColor = _l === void 0 ? "transparent" : _l, onAnimationStart = _a.onAnimationStart, onAnimationStop = _a.onAnimationStop;
|
|
48
|
-
var _m = React.useState({
|
|
49
|
-
width: 0,
|
|
50
|
-
height: 0,
|
|
51
|
-
}), contentSize = _m[0], setContentSize = _m[1];
|
|
52
35
|
var isVertical = direction === "vertical";
|
|
53
|
-
var isBounceMode = mode === AnimationMode.BOUNCE;
|
|
54
36
|
var containerMeasurement = useSharedValue({
|
|
55
37
|
width: 0,
|
|
56
38
|
height: 0,
|
|
@@ -63,13 +45,12 @@ var MarqueeText = React.forwardRef(function (_a, ref) {
|
|
|
63
45
|
x: 0,
|
|
64
46
|
y: 0,
|
|
65
47
|
});
|
|
66
|
-
var
|
|
48
|
+
var _m = React.useState(0), cloneTimes = _m[0], setCloneTimes = _m[1];
|
|
67
49
|
var anim = useSharedValue(0);
|
|
68
50
|
var isMounted = React.useRef(true);
|
|
69
51
|
var isActive = useSharedValue(false);
|
|
70
|
-
var frameRateMs = frameRate ? 1000 / frameRate : 1000 / 60;
|
|
71
|
-
var pixelsPerMs = speed /
|
|
72
|
-
// Animation frame callback
|
|
52
|
+
var frameRateMs = frameRate ? 1000 / frameRate : 1000 / 60;
|
|
53
|
+
var pixelsPerMs = speed / 10;
|
|
73
54
|
var frameCallback = useFrameCallback(function (frameInfo) {
|
|
74
55
|
if (!enabled || frameInfo.timeSincePreviousFrame === null)
|
|
75
56
|
return;
|
|
@@ -78,7 +59,6 @@ var MarqueeText = React.forwardRef(function (_a, ref) {
|
|
|
78
59
|
: frameInfo.timeSincePreviousFrame;
|
|
79
60
|
anim.value += (reverse ? -1 : 1) * pixelsPerMs * deltaTime;
|
|
80
61
|
}, false);
|
|
81
|
-
// Calculate how many clones we need to fill the screen
|
|
82
62
|
useAnimatedReaction(function () {
|
|
83
63
|
var contentDim = isVertical
|
|
84
64
|
? contentMeasurement.value.height
|
|
@@ -88,14 +68,12 @@ var MarqueeText = React.forwardRef(function (_a, ref) {
|
|
|
88
68
|
: containerMeasurement.value.width;
|
|
89
69
|
if (contentDim <= 0 || containerDim <= 0)
|
|
90
70
|
return 0;
|
|
91
|
-
// Need enough clones to fill the container plus buffer for continuous scrolling
|
|
92
71
|
return Math.ceil(containerDim / contentDim) + 2;
|
|
93
72
|
}, function (times) {
|
|
94
73
|
if (times > 0 && isMounted.current) {
|
|
95
74
|
runOnJS(setCloneTimes)(times);
|
|
96
75
|
}
|
|
97
76
|
}, [direction]);
|
|
98
|
-
// Control functions
|
|
99
77
|
var start = React.useCallback(function () {
|
|
100
78
|
if (!enabled)
|
|
101
79
|
return;
|
|
@@ -108,7 +86,6 @@ var MarqueeText = React.forwardRef(function (_a, ref) {
|
|
|
108
86
|
isActive.value = false;
|
|
109
87
|
onAnimationStop === null || onAnimationStop === void 0 ? void 0 : onAnimationStop();
|
|
110
88
|
}, [frameCallback, onAnimationStop]);
|
|
111
|
-
// Expose controls via ref
|
|
112
89
|
React.useImperativeHandle(ref, function () { return ({
|
|
113
90
|
start: start,
|
|
114
91
|
stop: stop,
|
|
@@ -116,80 +93,71 @@ var MarqueeText = React.forwardRef(function (_a, ref) {
|
|
|
116
93
|
return isActive.value;
|
|
117
94
|
},
|
|
118
95
|
}); });
|
|
119
|
-
// Setup gesture handling
|
|
120
96
|
var pan = React.useMemo(function () {
|
|
121
97
|
return Gesture.Pan()
|
|
122
98
|
.enabled(withGesture && enabled)
|
|
123
|
-
.onBegin(function () {
|
|
124
|
-
// Stop auto-animation when user interacts
|
|
125
|
-
runOnJS(stop)();
|
|
126
|
-
})
|
|
99
|
+
.onBegin(function () { return runOnJS(stop)(); })
|
|
127
100
|
.onChange(function (e) {
|
|
128
|
-
// Move according to user's gesture
|
|
129
101
|
anim.value += -(isVertical ? e.changeY : e.changeX);
|
|
130
102
|
})
|
|
131
103
|
.onFinalize(function (e) {
|
|
132
|
-
// Apply momentum scrolling when user releases
|
|
133
104
|
anim.value = withDecay({
|
|
134
105
|
velocity: -(isVertical ? e.velocityY : e.velocityX),
|
|
135
106
|
}, function (finished) {
|
|
136
|
-
// Restart auto-animation when decay finishes
|
|
137
107
|
if (finished)
|
|
138
108
|
runOnJS(start)();
|
|
139
109
|
});
|
|
140
110
|
});
|
|
141
111
|
}, [withGesture, isVertical, anim, start, stop, enabled]);
|
|
142
|
-
// Cleanup on unmount
|
|
143
112
|
React.useEffect(function () {
|
|
144
113
|
return function () {
|
|
145
114
|
isMounted.current = false;
|
|
146
115
|
stop();
|
|
147
116
|
};
|
|
148
117
|
}, [stop]);
|
|
149
|
-
// Start/stop based on enabled prop changes
|
|
150
118
|
React.useEffect(function () {
|
|
151
119
|
if (enabled) {
|
|
152
|
-
var timer_1 = setTimeout(function () {
|
|
153
|
-
start();
|
|
154
|
-
}, delay);
|
|
120
|
+
var timer_1 = setTimeout(function () { return start(); }, delay);
|
|
155
121
|
return function () { return clearTimeout(timer_1); };
|
|
156
122
|
}
|
|
157
123
|
else {
|
|
158
124
|
stop();
|
|
159
125
|
}
|
|
160
126
|
}, [enabled, start, stop, delay]);
|
|
161
|
-
// Render the content
|
|
162
127
|
var renderContent = function () {
|
|
163
128
|
if (typeof children === "string") {
|
|
164
|
-
return <Text style={textStyle}
|
|
129
|
+
return (<Text style={[styles.defaultText, textStyle]} numberOfLines={1} ellipsizeMode="tail">
|
|
130
|
+
{children}
|
|
131
|
+
</Text>);
|
|
165
132
|
}
|
|
166
|
-
return
|
|
133
|
+
return (<View style={styles.childContainer}>
|
|
134
|
+
{children}
|
|
135
|
+
</View>);
|
|
167
136
|
};
|
|
168
137
|
return (<Animated.View style={[
|
|
169
138
|
styles.container,
|
|
170
139
|
{ backgroundColor: backgroundColor },
|
|
171
140
|
style,
|
|
172
141
|
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
width: !isVertical
|
|
177
|
-
? contentMeasurement.value.width
|
|
178
|
-
: undefined,
|
|
142
|
+
minHeight: isVertical ? 20 : undefined,
|
|
143
|
+
minWidth: !isVertical ? 20 : undefined,
|
|
144
|
+
height: isVertical ? 'auto' : undefined,
|
|
145
|
+
width: !isVertical ? 'auto' : undefined,
|
|
179
146
|
},
|
|
180
147
|
]} onLayout={function (ev) {
|
|
181
148
|
containerMeasurement.value = ev.nativeEvent.layout;
|
|
182
149
|
}} pointerEvents="box-none">
|
|
183
150
|
<GestureDetector gesture={pan}>
|
|
184
|
-
<Animated.View style={
|
|
185
|
-
|
|
151
|
+
<Animated.View style={[
|
|
152
|
+
isVertical ? styles.column : styles.row,
|
|
153
|
+
styles.contentWrapper,
|
|
154
|
+
]} pointerEvents="box-none">
|
|
186
155
|
<View style={styles.hidden} onLayout={function (ev) {
|
|
187
156
|
contentMeasurement.value = ev.nativeEvent.layout;
|
|
188
157
|
}}>
|
|
189
158
|
{renderContent()}
|
|
190
159
|
</View>
|
|
191
160
|
|
|
192
|
-
{/* Visible cloned elements */}
|
|
193
161
|
{cloneTimes > 0 &&
|
|
194
162
|
Array.from({ length: cloneTimes }).map(function (_, index) { return (<AnimatedChild key={"clone-".concat(index)} index={index} anim={anim} contentMeasurement={contentMeasurement} spacing={spacing} direction={direction}>
|
|
195
163
|
{renderContent()}
|
|
@@ -210,10 +178,24 @@ var styles = StyleSheet.create({
|
|
|
210
178
|
row: {
|
|
211
179
|
flexDirection: "row",
|
|
212
180
|
position: "relative",
|
|
181
|
+
alignItems: 'center',
|
|
213
182
|
},
|
|
214
183
|
column: {
|
|
215
184
|
flexDirection: "column",
|
|
216
185
|
position: "relative",
|
|
186
|
+
justifyContent: 'center',
|
|
187
|
+
},
|
|
188
|
+
contentWrapper: {
|
|
189
|
+
flexShrink: 1,
|
|
190
|
+
},
|
|
191
|
+
defaultText: {
|
|
192
|
+
fontSize: 16,
|
|
193
|
+
color: 'black',
|
|
194
|
+
includeFontPadding: false,
|
|
195
|
+
textAlignVertical: 'center',
|
|
196
|
+
},
|
|
197
|
+
childContainer: {
|
|
198
|
+
flexShrink: 1,
|
|
217
199
|
},
|
|
218
200
|
});
|
|
219
201
|
export { AnimationMode };
|