rn-marquee-text 2.0.2 → 2.0.4

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/README.md CHANGED
@@ -1,233 +1,175 @@
1
- # React Native Marquee Text
1
+ Here's a more professional and well-structured version of your README file with improved formatting, organization, and a "Copy All" button:
2
2
 
3
+ ```markdown
4
+ # React Native Marquee Text 🚀
3
5
 
4
- A highly customizable package for smooth, auto-scrolling marquee text components in React Native apps. Works seamlessly in both React Native CLI and Expo environments.
6
+ [![npm version](https://img.shields.io/npm/v/rn-marquee-text.svg?style=flat-square)](https://www.npmjs.com/package/rn-marquee-text)
7
+ [![license](https://img.shields.io/npm/l/rn-marquee-text.svg?style=flat-square)](https://github.com/yourusername/rn-marquee-text/blob/main/LICENSE)
8
+ [![downloads](https://img.shields.io/npm/dm/rn-marquee-text.svg?style=flat-square)](https://www.npmjs.com/package/rn-marquee-text)
9
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
5
10
 
6
- ![npm version](https://img.shields.io/npm/v/rn-marquee-text.svg)
7
- ![license](https://img.shields.io/npm/l/rn-marquee-text.svg)
8
- ![downloads](https://img.shields.io/npm/dm/rn-marquee-text.svg)
11
+ A high-performance, feature-rich marquee component for React Native with smooth animations and flexible configuration.
9
12
 
10
- ## 🚀 Features
13
+ ![Horizontal and Vertical Marquee Demo](demo-combined.gif)
11
14
 
12
- - Smooth scrolling powered by React Native Reanimated
13
- - 🧩 Fully compatible with React Native & Expo
14
- - 🔁 Supports loop and bounce animation modes
15
- - 🎛️ Customizable speed, delay, and styles
16
- - 📱 No dependencies except Reanimated
17
- - 📏 Auto-detects overflow for auto-scrolling
18
- - ↔️ Supports horizontal and vertical scrolling
19
- - 📰 Built-in MarqueeText for ticker-style effects
15
+ ## Table of Contents
16
+ - [Features](#features-)
17
+ - [Installation](#installation-)
18
+ - [Usage](#usage-)
19
+ - [API Reference](#api-reference-)
20
+ - [Examples](#examples-)
21
+ - [Troubleshooting](#troubleshooting-)
22
+ - [Contributing](#contributing-)
23
+ - [License](#license-)
20
24
 
21
- ## 📦 Installation
25
+ ## Features
22
26
 
23
- ```bash
24
- # React Native CLI
25
- npm install rn-marquee-text react-native-reanimated
26
-
27
- # OR using yarn
28
- yarn add rn-marquee-text react-native-reanimated
29
- ```
27
+ - **Multi-directional scrolling**: Horizontal and vertical marquee effects
28
+ - **Animation modes**: Loop and bounce animations
29
+ - **Performance optimized**: Built with React Native Reanimated 2
30
+ - **Customizable**: Control speed, delay, spacing, and more
31
+ - **Interactive**: Gesture support for pausing/resuming
32
+ - **Flexible content**: Supports both text and custom components
33
+ - **TypeScript ready**: Complete type definitions included
30
34
 
31
- ### Expo Users
35
+ ## Installation 📦
32
36
 
33
37
  ```bash
34
- expo install react-native-reanimated
35
- ```
36
-
37
- Then update your `babel.config.js`:
38
+ # Using npm
39
+ npm install rn-marquee-text react-native-reanimated react-native-gesture-handler
38
40
 
39
- ```js
40
- module.exports = {
41
- presets: ['babel-preset-expo'],
42
- plugins: ['react-native-reanimated/plugin'],
43
- };
41
+ # Using yarn
42
+ yarn add rn-marquee-text react-native-reanimated react-native-gesture-handler
44
43
  ```
45
44
 
46
- ## 🧱 Components
45
+ ### Peer Dependencies
46
+ Ensure you've properly installed and configured:
47
+ - [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation)
48
+ - [React Native Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler/docs/)
47
49
 
48
- ### 1️⃣ AutoScroll — Scroll any overflowed content
50
+ ## Usage 🚀
49
51
 
50
- #### Basic Usage
51
-
52
- ```tsx
53
- import AutoScroll, { AnimationMode } from 'rn-marquee-text';
54
-
55
- const Example = () => (
56
- <AutoScroll
57
- style={{ height: 100, width: '100%' }}
58
- mode={AnimationMode.LOOP}
59
- speed={40}
60
- >
61
- This is a long text that will scroll if it overflows its container.
62
- </AutoScroll>
63
- );
64
- ```
65
-
66
- #### Props
52
+ ### Basic Implementation
53
+ ```jsx
54
+ import React from 'react';
55
+ import { StyleSheet, View } from 'react-native';
56
+ import MarqueeText from 'rn-marquee-text';
67
57
 
68
- | Prop | Type | Default | Description |
69
- |------|------|---------|-------------|
70
- | children | ReactNode | (required) | Content to scroll |
71
- | mode | 'loop' \| 'bounce' | 'loop' | Animation type |
72
- | speed | number | 30 | Speed in px/sec |
73
- | delay | number | 1500 | Delay before animation starts |
74
- | endPauseDuration | number | 1000 | Pause time at edges (for bounce mode) |
75
- | style | ViewStyle | {} | Container styling |
76
- | textStyle | TextStyle | {} | Text styling (when children is string) |
77
- | enabled | boolean | true | Enable or disable animation |
78
- | direction | 'horizontal' \| 'vertical' | 'vertical' | Scroll direction |
79
-
80
- ### 2️⃣ MarqueeText — For ticker-style text
81
-
82
- #### Basic Usage
83
-
84
- ```tsx
85
- import { MarqueeText } from 'rn-marquee-text';
86
- import { View, Text } from 'react-native';
87
-
88
- const Example = () => (
89
- <View style={{ width: '100%', borderRadius: 8, overflow: 'hidden' }}>
58
+ const App = () => (
59
+ <View style={styles.container}>
90
60
  <MarqueeText
91
- speed={100}
92
- backgroundColor="#1a365d"
93
- textColor="#f0f4f8"
94
- fontSize={14}
95
- direction="horizontal"
61
+ style={styles.marquee}
62
+ speed={40}
63
+ textStyle={styles.text}
96
64
  >
97
- <Text>
98
- Breaking News: This is a marquee text scrolling horizontally!
99
- </Text>
65
+ Your scrolling text goes here
100
66
  </MarqueeText>
101
67
  </View>
102
68
  );
103
- ```
104
-
105
- #### Props
106
-
107
- | Prop | Type | Default | Description |
108
- |------|------|---------|-------------|
109
- | text | string | (required) | Text to display (alternative to children) |
110
- | speed | number | 80 | Speed in px/sec |
111
- | backgroundColor | string | #000 | Marquee background color |
112
- | textColor | string | #fff | Text color |
113
- | fontSize | number | 16 | Font size |
114
- | paddingVertical | number | 8 | Vertical padding |
115
- | paddingHorizontal | number | 12 | Horizontal padding |
116
- | delay | number | 1000 | Delay before animation starts |
117
- | bounceMode | boolean | false | Whether to bounce at edges |
118
- | endPauseDuration | number | 2000 | Pause at each end (only in bounce mode) |
119
-
120
- ## 💡 Advanced Examples
121
-
122
- ### 🔁 AutoScroll with Custom Content
123
-
124
- ```tsx
125
- import React from 'react';
126
- import { View, Text, StyleSheet } from 'react-native';
127
- import AutoScroll from 'rn-marquee-text';
128
-
129
- const CardScroller = () => (
130
- <AutoScroll style={styles.scrollContainer} direction="horizontal">
131
- <View style={styles.contentContainer}>
132
- {[1, 2, 3, 4, 5].map((item) => (
133
- <View key={item} style={styles.card}>
134
- <Text style={styles.cardText}>Card {item}</Text>
135
- </View>
136
- ))}
137
- </View>
138
- </AutoScroll>
139
- );
140
69
 
141
70
  const styles = StyleSheet.create({
142
- scrollContainer: {
143
- height: 120,
144
- width: '100%',
145
- },
146
- contentContainer: {
147
- flexDirection: 'row',
148
- padding: 10,
149
- },
150
- card: {
151
- width: 100,
152
- height: 100,
153
- backgroundColor: '#f0f0f0',
154
- borderRadius: 8,
155
- marginRight: 10,
156
- justifyContent: 'center',
157
- alignItems: 'center',
158
- },
159
- cardText: {
160
- fontSize: 16,
161
- fontWeight: 'bold',
162
- },
71
+ container: { flex: 1, justifyContent: 'center', padding: 20 },
72
+ marquee: { height: 50, backgroundColor: '#f5f5f5', borderRadius: 8 },
73
+ text: { fontSize: 16, color: '#333' }
163
74
  });
164
- ```
165
-
166
- ### 📰 News Ticker with MarqueeText
167
-
168
- ```tsx
169
- import React from 'react';
170
- import { View, Text, StyleSheet } from 'react-native';
171
- import { MarqueeText } from 'rn-marquee-text';
172
-
173
- const NewsTicker = () => (
174
- <View style={styles.tickerContainer}>
175
- <MarqueeText speed={70} bounceMode={false}>
176
- <Text style={styles.cardText}>
177
- BREAKING NEWS: Latest updates on global events. Markets reach all-time high.
178
- </Text>
179
- </MarqueeText>
180
- </View>
181
- );
182
75
 
183
- const styles = StyleSheet.create({
184
- tickerContainer: {
185
- width: '100%',
186
- borderRadius: 4,
187
- overflow: 'hidden',
188
- marginVertical: 10,
189
- },
190
- cardText: {
191
- fontSize: 14,
192
- paddingHorizontal: 10,
193
- },
194
- });
76
+ export default App;
195
77
  ```
196
78
 
197
- ## 🛠️ Tips for Optimal Performance
79
+ ## API Reference 📚
198
80
 
199
- - Match speed with content length for readability
200
- - Use delays to give users time to read before scrolling
201
- - Bounce mode is more attention-grabbing (e.g., for alerts)
202
- - Limit concurrent scroll components to avoid frame drops
203
- - Test on low-end devices for smooth performance
81
+ ### Props
82
+ | Prop | Type | Default | Description |
83
+ |------|------|---------|-------------|
84
+ | `children` | React.ReactNode | Required | Content to scroll (string or components) |
85
+ | `mode` | 'loop' \| 'bounce' | 'loop' | Animation behavior |
86
+ | `speed` | number | 30 | Pixels per second |
87
+ | `direction` | 'horizontal' \| 'vertical' | 'horizontal' | Scroll direction |
88
+ | `enabled` | boolean | true | Animation active state |
89
+ | `delay` | number | 1500 | Initial delay (ms) |
90
+ | `endPauseDuration` | number | 1000 | Pause at end (bounce mode) |
91
+
92
+ ### Methods (via ref)
93
+ ```jsx
94
+ const marqueeRef = useRef();
95
+
96
+ // Start animation
97
+ marqueeRef.current?.start();
98
+
99
+ // Stop animation
100
+ marqueeRef.current?.stop();
101
+
102
+ // Check if active
103
+ const isActive = marqueeRef.current?.isActive;
104
+ ```
204
105
 
205
- ## 🧩 Troubleshooting
106
+ ## Examples 🎨
107
+
108
+ ### Vertical Bounce Marquee
109
+ ```jsx
110
+ <MarqueeText
111
+ direction="vertical"
112
+ mode="bounce"
113
+ speed={20}
114
+ endPauseDuration={2000}
115
+ style={styles.verticalMarquee}
116
+ >
117
+ Line 1{'\n'}Line 2{'\n'}Line 3
118
+ </MarqueeText>
119
+ ```
206
120
 
207
- ### Text Not Scrolling?
121
+ ### Controlled Marquee with Buttons
122
+ ```jsx
123
+ const [paused, setPaused] = useState(false);
208
124
 
209
- - Ensure content overflows the container
210
- - Confirm `enabled` is set to `true`
211
- - Use `overflow: 'hidden'` on container
125
+ <>
126
+ <MarqueeText
127
+ ref={marqueeRef}
128
+ enabled={!paused}
129
+ style={styles.marquee}
130
+ >
131
+ Controllable marquee text
132
+ </MarqueeText>
133
+
134
+ <Button
135
+ title={paused ? "Resume" : "Pause"}
136
+ onPress={() => setPaused(!paused)}
137
+ />
138
+ </>
139
+ ```
212
140
 
213
- ### 🐢 Choppy Animations?
141
+ ## Troubleshooting 🛠️
214
142
 
215
- - Leverage `useNativeDriver` if supported
216
- - Minimize simultaneous animations
217
- - Simplify nested component structure
143
+ **Animation not working?**
144
+ - Verify Reanimated installation
145
+ - Check babel.config.js for Reanimated plugin
218
146
 
219
- ## 📄 License
147
+ **Text not visible?**
148
+ - Ensure container has proper dimensions
149
+ - Verify text color contrasts with background
220
150
 
221
- MIT
151
+ **Performance issues?**
152
+ - Reduce animation speed
153
+ - Simplify marquee content
154
+ - Use `frameRate` prop to limit FPS
222
155
 
223
- ## 🤝 Contributing
156
+ ## Contributing 🤝
157
+ Contributions are welcome! Please:
158
+ 1. Open an issue to discuss changes
159
+ 2. Ensure tests are updated
160
+ 3. Maintain consistent code style
224
161
 
225
- Pull requests welcome!
162
+ ## License 📄
163
+ MIT © [Your Name](https://github.com/yourusername)
226
164
 
227
- Steps:
165
+ <button onclick="copyToClipboard()">Copy All README Content</button>
228
166
 
229
- 1. Fork the repo
230
- 2. Create a branch: `git checkout -b feature/amazing-feature`
231
- 3. Commit your changes: `git commit -m 'Add some amazing feature'`
232
- 4. Push the branch: `git push origin feature/amazing-feature`
233
- 5. Open a Pull Request
167
+ <script>
168
+ function copyToClipboard() {
169
+ const content = document.querySelector('article').innerText;
170
+ navigator.clipboard.writeText(content)
171
+ .then(() => alert('README copied to clipboard!'))
172
+ .catch(err => console.error('Failed to copy:', err));
173
+ }
174
+ </script>
175
+ ```
@@ -1,14 +1,119 @@
1
- import React from 'react';
2
- declare const MarqueeText: ({ text, speed, backgroundColor, textColor, fontSize, paddingVertical, paddingHorizontal, delay, bounceMode, endPauseDuration, }: {
3
- text: string;
1
+ import * as React from 'react';
2
+ import { ViewStyle, TextStyle } from 'react-native';
3
+ /**
4
+ * Animation modes for the marquee text
5
+ */
6
+ declare enum AnimationMode {
7
+ LOOP = "loop",
8
+ BOUNCE = "bounce"
9
+ }
10
+ /**
11
+ * Direction of the marquee animation
12
+ */
13
+ type MarqueeDirection = 'horizontal' | 'vertical';
14
+ /**
15
+ * Props for the MarqueeText component
16
+ */
17
+ interface MarqueeTextProps {
18
+ /**
19
+ * Content to be scrolled (string or React nodes)
20
+ */
21
+ children: React.ReactNode;
22
+ /**
23
+ * The animation mode: 'loop' for continuous scrolling or 'bounce' for back-and-forth
24
+ * @default AnimationMode.LOOP
25
+ */
26
+ mode?: AnimationMode;
27
+ /**
28
+ * Speed of the scrolling animation in pixels per second
29
+ * @default 30
30
+ */
4
31
  speed?: number;
5
- backgroundColor?: string;
6
- textColor?: string;
7
- fontSize?: number;
8
- paddingVertical?: number;
9
- paddingHorizontal?: number;
32
+ /**
33
+ * Delay in milliseconds before starting the animation
34
+ * @default 1500
35
+ */
10
36
  delay?: number;
11
- bounceMode?: boolean;
37
+ /**
38
+ * Duration in milliseconds to pause at the end of the content (only for bounce mode)
39
+ * @default 1000
40
+ */
12
41
  endPauseDuration?: number;
13
- }) => React.JSX.Element;
14
- export default MarqueeText;
42
+ /**
43
+ * Container style
44
+ */
45
+ style?: ViewStyle;
46
+ /**
47
+ * Text style (when children is a string)
48
+ */
49
+ textStyle?: TextStyle;
50
+ /**
51
+ * Whether to enable the animation
52
+ * @default true
53
+ */
54
+ enabled?: boolean;
55
+ /**
56
+ * Direction of scrolling ('horizontal' or 'vertical')
57
+ * @default 'horizontal'
58
+ */
59
+ direction?: MarqueeDirection;
60
+ /**
61
+ * Spacing between cloned elements
62
+ * @default 20
63
+ */
64
+ spacing?: number;
65
+ /**
66
+ * Allow user interaction with gesture handling
67
+ * @default true
68
+ */
69
+ withGesture?: boolean;
70
+ /**
71
+ * Custom frame rate for animation
72
+ */
73
+ frameRate?: number;
74
+ /**
75
+ * Reverse the animation direction
76
+ * @default false
77
+ */
78
+ reverse?: boolean;
79
+ /**
80
+ * Background color for the container
81
+ * @default 'transparent'
82
+ */
83
+ backgroundColor?: string;
84
+ /**
85
+ * Callback when animation starts
86
+ */
87
+ onAnimationStart?: () => void;
88
+ /**
89
+ * Callback when animation stops
90
+ */
91
+ onAnimationStop?: () => void;
92
+ }
93
+ /**
94
+ * Reference handle for the MarqueeText component
95
+ */
96
+ export interface MarqueeTextRef {
97
+ /**
98
+ * Start the marquee animation
99
+ */
100
+ start: () => void;
101
+ /**
102
+ * Stop the marquee animation
103
+ */
104
+ stop: () => void;
105
+ /**
106
+ * Whether the animation is currently active
107
+ */
108
+ isActive: boolean;
109
+ }
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
+ declare const MarqueeText: React.ForwardRefExoticComponent<MarqueeTextProps & React.RefAttributes<MarqueeTextRef>>;
118
+ export { MarqueeText, AnimationMode };
119
+ export type { MarqueeDirection, MarqueeTextProps };
@@ -1,64 +1,208 @@
1
- // MarqueeText.js - Complete rewrite with guaranteed scrolling
2
- import React, { useEffect } from 'react';
3
- import { View } from 'react-native';
4
- import Animated, { useSharedValue, useAnimatedStyle, withRepeat, withTiming, withDelay, Easing, withSequence, } from 'react-native-reanimated';
5
- var MarqueeText = function (_a) {
6
- var text = _a.text, _b = _a.speed, speed = _b === void 0 ? 60 : _b, _c = _a.backgroundColor, backgroundColor = _c === void 0 ? '#000' : _c, _d = _a.textColor, textColor = _d === void 0 ? '#fff' : _d, _e = _a.fontSize, fontSize = _e === void 0 ? 16 : _e, _f = _a.paddingVertical, paddingVertical = _f === void 0 ? 8 : _f, _g = _a.paddingHorizontal, paddingHorizontal = _g === void 0 ? 12 : _g, _h = _a.delay, delay = _h === void 0 ? 1000 : _h, _j = _a.bounceMode, bounceMode = _j === void 0 ? false : _j, _k = _a.endPauseDuration, endPauseDuration = _k === void 0 ? 2000 : _k;
7
- // Force a larger content width to ensure scrolling always happens
8
- // In real usage, we would measure dynamically, but this ensures it works
9
- var contentWidth = text.length * (fontSize * 0.6);
10
- var scrollX = useSharedValue(0);
11
- useEffect(function () {
12
- // Give layout time to complete
13
- var timeoutId = setTimeout(function () {
14
- if (bounceMode) {
15
- // Bounce animation (back and forth with pauses)
16
- scrollX.value = withDelay(delay, withRepeat(withSequence(withTiming(-contentWidth, {
17
- duration: contentWidth * (1000 / speed),
18
- easing: Easing.linear
19
- }), withTiming(-contentWidth, {
20
- duration: endPauseDuration,
21
- easing: Easing.linear
22
- }), withTiming(0, {
23
- duration: contentWidth * (1000 / speed),
24
- easing: Easing.linear
25
- }), withTiming(0, {
26
- duration: endPauseDuration,
27
- easing: Easing.linear
28
- })), -1, // Infinite repeats
29
- false));
30
- }
31
- else {
32
- // Standard loop animation
33
- scrollX.value = withDelay(delay, withRepeat(withTiming(-contentWidth, {
34
- duration: contentWidth * (1000 / speed),
35
- easing: Easing.linear
36
- }), -1, // Infinite repeats
37
- false));
38
- }
39
- }, 500);
40
- return function () { return clearTimeout(timeoutId); };
41
- }, [speed, delay, contentWidth, bounceMode, endPauseDuration]);
42
- var animatedStyle = useAnimatedStyle(function () {
43
- return {
44
- transform: [{ translateX: scrollX.value }],
45
- };
1
+ import * as React from 'react';
2
+ import { StyleSheet, View, Text } from 'react-native';
3
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
+ import Animated, { runOnJS, useAnimatedReaction, useAnimatedStyle, useSharedValue, useFrameCallback, withDecay, } from 'react-native-reanimated';
5
+ import { useFocusEffect } from '@react-navigation/native';
6
+ /**
7
+ * Animation modes for the marquee text
8
+ */
9
+ var AnimationMode;
10
+ (function (AnimationMode) {
11
+ AnimationMode["LOOP"] = "loop";
12
+ AnimationMode["BOUNCE"] = "bounce";
13
+ })(AnimationMode || (AnimationMode = {}));
14
+ /**
15
+ * Component to render a child item in the marquee
16
+ */
17
+ var AnimatedChild = React.memo(function (_a) {
18
+ var index = _a.index, children = _a.children, anim = _a.anim, contentMeasurement = _a.contentMeasurement, spacing = _a.spacing, direction = _a.direction;
19
+ var style = useAnimatedStyle(function () {
20
+ var _a;
21
+ var isVertical = direction === 'vertical';
22
+ var dimension = isVertical ? contentMeasurement.value.height : contentMeasurement.value.width;
23
+ if (dimension <= 0)
24
+ return {};
25
+ var position = (index - 1) * (dimension + spacing);
26
+ var translation = -(anim.value % (dimension + spacing));
27
+ return _a = {
28
+ position: 'absolute'
29
+ },
30
+ _a[isVertical ? 'top' : 'left'] = position,
31
+ _a.transform = isVertical
32
+ ? [{ translateY: translation }]
33
+ : [{ translateX: translation }],
34
+ _a;
35
+ }, [index, spacing, contentMeasurement, direction]);
36
+ return <Animated.View style={style}>{children}</Animated.View>;
37
+ });
38
+ /**
39
+ * MarqueeText component for scrolling text or content
40
+ *
41
+ * This component creates a scrolling effect for text or other content.
42
+ * It supports both horizontal and vertical scrolling, different animation
43
+ * modes, and user interaction via gestures.
44
+ */
45
+ var MarqueeText = React.forwardRef(function (_a, ref) {
46
+ 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;
47
+ var isVertical = direction === 'vertical';
48
+ var isBounceMode = mode === AnimationMode.BOUNCE;
49
+ var containerMeasurement = useSharedValue({
50
+ width: 0,
51
+ height: 0,
52
+ x: 0,
53
+ y: 0,
54
+ });
55
+ var contentMeasurement = useSharedValue({
56
+ width: 0,
57
+ height: 0,
58
+ x: 0,
59
+ y: 0,
46
60
  });
47
- return (<View style={{
48
- backgroundColor: backgroundColor,
49
- paddingVertical: paddingVertical,
50
- paddingHorizontal: paddingHorizontal,
51
- overflow: 'hidden',
61
+ var _m = React.useState(0), cloneTimes = _m[0], setCloneTimes = _m[1];
62
+ var anim = useSharedValue(0);
63
+ var isMounted = React.useRef(true);
64
+ var isActive = useSharedValue(false);
65
+ var frameRateMs = frameRate ? 1000 / frameRate : 1000 / 60; // Default to 60fps
66
+ var pixelsPerMs = speed / 1000;
67
+ // Animation frame callback
68
+ var frameCallback = useFrameCallback(function (frameInfo) {
69
+ if (!enabled || frameInfo.timeSincePreviousFrame === null)
70
+ return;
71
+ var deltaTime = frameRateMs
72
+ ? frameInfo.timeSincePreviousFrame / frameRateMs
73
+ : frameInfo.timeSincePreviousFrame;
74
+ anim.value += (reverse ? -1 : 1) * pixelsPerMs * deltaTime;
75
+ }, false);
76
+ // Calculate how many clones we need to fill the screen
77
+ useAnimatedReaction(function () {
78
+ var contentDim = isVertical ? contentMeasurement.value.height : contentMeasurement.value.width;
79
+ var containerDim = isVertical ? containerMeasurement.value.height : containerMeasurement.value.width;
80
+ if (contentDim <= 0 || containerDim <= 0)
81
+ return 0;
82
+ // Need enough clones to fill the container plus buffer for continuous scrolling
83
+ return Math.ceil(containerDim / contentDim) + 2;
84
+ }, function (times) {
85
+ if (times > 0 && isMounted.current) {
86
+ runOnJS(setCloneTimes)(times);
87
+ }
88
+ }, [direction]);
89
+ // Control functions
90
+ var start = React.useCallback(function () {
91
+ if (!enabled)
92
+ return;
93
+ frameCallback.setActive(true);
94
+ isActive.value = true;
95
+ onAnimationStart === null || onAnimationStart === void 0 ? void 0 : onAnimationStart();
96
+ }, [frameCallback, enabled, onAnimationStart]);
97
+ var stop = React.useCallback(function () {
98
+ frameCallback.setActive(false);
99
+ isActive.value = false;
100
+ onAnimationStop === null || onAnimationStop === void 0 ? void 0 : onAnimationStop();
101
+ }, [frameCallback, onAnimationStop]);
102
+ // Expose controls via ref
103
+ React.useImperativeHandle(ref, function () { return ({
104
+ start: start,
105
+ stop: stop,
106
+ get isActive() { return isActive.value; }
107
+ }); });
108
+ // Setup gesture handling
109
+ var pan = React.useMemo(function () {
110
+ return Gesture.Pan()
111
+ .enabled(withGesture && enabled)
112
+ .onBegin(function () {
113
+ // Stop auto-animation when user interacts
114
+ runOnJS(stop)();
115
+ })
116
+ .onChange(function (e) {
117
+ // Move according to user's gesture
118
+ anim.value += -(isVertical ? e.changeY : e.changeX);
119
+ })
120
+ .onFinalize(function (e) {
121
+ // Apply momentum scrolling when user releases
122
+ anim.value = withDecay({
123
+ velocity: -(isVertical ? e.velocityY : e.velocityX),
124
+ }, function (finished) {
125
+ // Restart auto-animation when decay finishes
126
+ if (finished)
127
+ runOnJS(start)();
128
+ });
129
+ });
130
+ }, [withGesture, isVertical, anim, start, stop, enabled]);
131
+ // Handle focus/unmount
132
+ useFocusEffect(React.useCallback(function () {
133
+ // Start animation when screen comes into focus
134
+ if (enabled) {
135
+ start();
136
+ }
137
+ return function () {
138
+ // Stop animation when screen loses focus
139
+ stop();
140
+ anim.value = 0;
141
+ };
142
+ }, [start, stop, anim, enabled]));
143
+ // Cleanup on unmount
144
+ React.useEffect(function () {
145
+ return function () {
146
+ isMounted.current = false;
147
+ };
148
+ }, []);
149
+ // Start/stop based on enabled prop changes
150
+ React.useEffect(function () {
151
+ if (enabled) {
152
+ start();
153
+ }
154
+ else {
155
+ stop();
156
+ }
157
+ }, [enabled, start, stop]);
158
+ // Render the content
159
+ var renderContent = function () {
160
+ if (typeof children === 'string') {
161
+ return <Text style={textStyle}>{children}</Text>;
162
+ }
163
+ return children;
164
+ };
165
+ return (<Animated.View style={[
166
+ styles.container,
167
+ { backgroundColor: backgroundColor },
168
+ style
169
+ ]} onLayout={function (ev) {
170
+ containerMeasurement.value = ev.nativeEvent.layout;
171
+ }} pointerEvents="box-none">
172
+ <GestureDetector gesture={pan}>
173
+ <Animated.View style={isVertical ? styles.column : styles.row} pointerEvents="box-none">
174
+ {/* Hidden element for measuring original content size */}
175
+ <View style={styles.hidden} onLayout={function (ev) {
176
+ contentMeasurement.value = ev.nativeEvent.layout;
52
177
  }}>
53
- <Animated.Text style={[
54
- {
55
- color: textColor,
56
- fontSize: fontSize,
57
- },
58
- animatedStyle,
59
- ]} numberOfLines={1}>
60
- {text}
61
- </Animated.Text>
62
- </View>);
63
- };
64
- export default MarqueeText;
178
+ {renderContent()}
179
+ </View>
180
+
181
+ {/* Visible cloned elements */}
182
+ {cloneTimes > 0 &&
183
+ Array.from({ length: cloneTimes }).map(function (_, index) { return (<AnimatedChild key={"clone-".concat(index)} index={index} anim={anim} contentMeasurement={contentMeasurement} spacing={spacing} direction={direction}>
184
+ {renderContent()}
185
+ </AnimatedChild>); })}
186
+ </Animated.View>
187
+ </GestureDetector>
188
+ </Animated.View>);
189
+ });
190
+ var styles = StyleSheet.create({
191
+ container: {
192
+ overflow: 'hidden',
193
+ },
194
+ hidden: {
195
+ opacity: 0,
196
+ position: 'absolute',
197
+ zIndex: -1,
198
+ },
199
+ row: {
200
+ flexDirection: 'row',
201
+ position: 'relative',
202
+ },
203
+ column: {
204
+ flexDirection: 'column',
205
+ position: 'relative',
206
+ },
207
+ });
208
+ export { MarqueeText, AnimationMode };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { AutoScroll } from './AutoScroll';
2
+ import { MarqueeText } from './MarqueeText';
2
3
  import { AnimationMode } from './constants';
3
- export { AutoScroll, AnimationMode };
4
+ export { AutoScroll, AnimationMode, MarqueeText };
4
5
  export default AutoScroll;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { AutoScroll } from './AutoScroll';
2
+ import { MarqueeText } from './MarqueeText';
2
3
  import { AnimationMode } from './constants';
3
- export { AutoScroll, AnimationMode };
4
+ export { AutoScroll, AnimationMode, MarqueeText };
4
5
  export default AutoScroll;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-marquee-text",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "A customizable marquee (scrolling) text component for React Native",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -50,6 +50,7 @@
50
50
  "typescript": "^5.0.0"
51
51
  },
52
52
  "dependencies": {
53
+ "@react-navigation/native": "^7.1.9",
53
54
  "react-native-gesture-handler": "^2.25.0",
54
55
  "rn-marquee-text": "^1.0.4"
55
56
  }