rn-marquee-text 1.0.4 → 2.0.0
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 +168 -112
- package/dist/AutoScroll.d.ts +28 -0
- package/dist/AutoScroll.js +145 -0
- package/dist/MarqueeText.d.ts +9 -5
- package/dist/MarqueeText.js +56 -54
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
# React Native Marquee Text
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
<p align="center">
|
|
6
|
-
<img src="https://via.placeholder.com/300x80?text=Marquee+Demo" alt="Marquee Demo" />
|
|
7
|
-
</p>
|
|
3
|
+
A highly customizable package for implementing smooth auto-scrolling and marquee text components in React Native applications. This package works seamlessly in both React Native and Expo environments.
|
|
8
4
|
|
|
9
5
|
## Features
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
6
|
+
- 🚀 Smooth scrolling animations powered by React Native Reanimated
|
|
7
|
+
- 💯 Works perfectly in both React Native and Expo environments
|
|
8
|
+
- 🔄 Multiple animation modes (continuous loop and bounce)
|
|
9
|
+
- ⚙️ Customizable speed, delay, and styling options
|
|
10
|
+
- 📱 No external dependencies other than React Native Reanimated
|
|
11
|
+
- ⚡ Optimized performance with native animations
|
|
12
|
+
- 📏 Auto-detects when scrolling is needed (text larger than container)
|
|
13
|
+
- ↔️ Supports both horizontal and vertical scrolling
|
|
14
|
+
- 📰 Includes a dedicated MarqueeText component for text tickers
|
|
18
15
|
|
|
19
16
|
## Installation
|
|
20
17
|
|
|
@@ -26,136 +23,195 @@ npm install rn-marquee-text react-native-reanimated
|
|
|
26
23
|
yarn add rn-marquee-text react-native-reanimated
|
|
27
24
|
```
|
|
28
25
|
|
|
29
|
-
###
|
|
26
|
+
### Expo Projects
|
|
27
|
+
For Expo projects, make sure you have Reanimated installed:
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
```bash
|
|
30
|
+
expo install react-native-reanimated
|
|
31
|
+
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Then, add the Babel plugin to your babel.config.js:
|
|
34
34
|
|
|
35
35
|
```javascript
|
|
36
|
-
module.exports =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
presets: ['babel-preset-expo'], // or 'module:metro-react-native-babel-preset' for React Native
|
|
40
|
-
plugins: ['react-native-reanimated/plugin'],
|
|
41
|
-
};
|
|
36
|
+
module.exports = {
|
|
37
|
+
presets: ['babel-preset-expo'],
|
|
38
|
+
plugins: ['react-native-reanimated/plugin'],
|
|
42
39
|
};
|
|
43
40
|
```
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
## Components
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```javascript
|
|
50
|
-
import React from 'react';
|
|
51
|
-
import { View, StyleSheet } from 'react-native';
|
|
52
|
-
import MarqueeText from 'rn-marquee-text';
|
|
44
|
+
### 1. AutoScroll
|
|
45
|
+
A versatile component for scrolling any content (text or components) that overflows its container.
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{/* Basic Usage */}
|
|
58
|
-
<MarqueeText
|
|
59
|
-
text="This is a basic marquee that scrolls horizontally when text is longer than the container."
|
|
60
|
-
/>
|
|
61
|
-
|
|
62
|
-
{/* Custom Speed and Color */}
|
|
63
|
-
<MarqueeText
|
|
64
|
-
text="This marquee scrolls faster and has custom colors!"
|
|
65
|
-
speed={60}
|
|
66
|
-
textColor="#007AFF"
|
|
67
|
-
/>
|
|
68
|
-
|
|
69
|
-
{/* Bounce Mode */}
|
|
70
|
-
<MarqueeText
|
|
71
|
-
text="This text bounces back and forth instead of looping continuously!"
|
|
72
|
-
bounce={true}
|
|
73
|
-
textColor="#FF3B30"
|
|
74
|
-
/>
|
|
75
|
-
</View>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
47
|
+
#### Basic Usage
|
|
48
|
+
```jsx
|
|
49
|
+
import AutoScroll, { AnimationMode } from 'rn-marquee-text';
|
|
78
50
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
51
|
+
const Example = () => (
|
|
52
|
+
<AutoScroll
|
|
53
|
+
style={{ height: 100, width: '100%' }}
|
|
54
|
+
mode={AnimationMode.LOOP}
|
|
55
|
+
speed={40}
|
|
56
|
+
>
|
|
57
|
+
This is a long text that will automatically scroll when it's larger than
|
|
58
|
+
the container. The component automatically detects if scrolling is needed.
|
|
59
|
+
</AutoScroll>
|
|
60
|
+
);
|
|
89
61
|
```
|
|
90
62
|
|
|
91
|
-
|
|
92
|
-
|
|
63
|
+
#### Props
|
|
93
64
|
| Prop | Type | Default | Description |
|
|
94
65
|
|------|------|---------|-------------|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
|
|
66
|
+
| children | ReactNode | (required) | Content to be scrolled |
|
|
67
|
+
| mode | AnimationMode or string | 'loop' | Animation mode: 'loop' or 'bounce' |
|
|
68
|
+
| speed | number | 30 | Speed of scrolling in pixels per second |
|
|
69
|
+
| delay | number | 1500 | Delay in milliseconds before starting the animation |
|
|
70
|
+
| endPauseDuration | number | 1000 | Duration to pause at the ends (only for bounce mode) |
|
|
71
|
+
| style | ViewStyle | {} | Style for the container |
|
|
72
|
+
| textStyle | TextStyle | {} | Style for the text (when children is a string) |
|
|
73
|
+
| enabled | boolean | true | Whether to enable the animation |
|
|
74
|
+
| direction | string | 'vertical' | Direction of scroll: 'horizontal' or 'vertical' |
|
|
75
|
+
|
|
76
|
+
### 2. MarqueeText
|
|
77
|
+
A specialized component for creating ticker/marquee text effects, perfect for news tickers, announcements, or notifications.
|
|
78
|
+
|
|
79
|
+
#### Basic Usage
|
|
80
|
+
```jsx
|
|
81
|
+
import { MarqueeText } from 'rn-marquee-text';
|
|
82
|
+
|
|
83
|
+
const Example = () => (
|
|
84
|
+
<View style={{ width: '100%', borderRadius: 8, overflow: 'hidden' }}>
|
|
85
|
+
<MarqueeText
|
|
86
|
+
text="Breaking News: This is a full-width marquee text component that scrolls horizontally"
|
|
87
|
+
speed={100}
|
|
88
|
+
backgroundColor="#7b341e"
|
|
89
|
+
textColor="#fffaf0"
|
|
90
|
+
fontSize={18}
|
|
91
|
+
/>
|
|
92
|
+
</View>
|
|
93
|
+
);
|
|
111
94
|
```
|
|
112
95
|
|
|
113
|
-
|
|
96
|
+
#### Props
|
|
97
|
+
| Prop | Type | Default | Description |
|
|
98
|
+
|------|------|---------|-------------|
|
|
99
|
+
| text | string | (required) | Text content to scroll |
|
|
100
|
+
| speed | number | 80 | Speed of scrolling in pixels per second |
|
|
101
|
+
| backgroundColor | string | '#000' | Background color of the marquee container |
|
|
102
|
+
| textColor | string | '#fff' | Text color |
|
|
103
|
+
| fontSize | number | 16 | Font size of the text |
|
|
104
|
+
| paddingVertical | number | 8 | Vertical padding inside the marquee |
|
|
105
|
+
| paddingHorizontal | number | 12 | Horizontal padding inside the marquee |
|
|
106
|
+
| delay | number | 1000 | Delay in milliseconds before starting animation |
|
|
107
|
+
| bounceMode | boolean | false | Whether to use bounce animation |
|
|
108
|
+
| endPauseDuration | number | 2000 | Pause duration at each end (only when bounceMode is true) |
|
|
114
109
|
|
|
115
110
|
## Advanced Examples
|
|
116
111
|
|
|
117
|
-
###
|
|
112
|
+
### AutoScroll with Custom Content
|
|
113
|
+
```jsx
|
|
114
|
+
import React from 'react';
|
|
115
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
116
|
+
import AutoScroll from 'rn-marquee-text';
|
|
117
|
+
|
|
118
|
+
const CardScroller = () => {
|
|
119
|
+
return (
|
|
120
|
+
<AutoScroll style={styles.scrollContainer} direction="horizontal">
|
|
121
|
+
<View style={styles.contentContainer}>
|
|
122
|
+
{[1, 2, 3, 4, 5].map((item) => (
|
|
123
|
+
<View key={item} style={styles.card}>
|
|
124
|
+
<Text style={styles.cardText}>Card {item}</Text>
|
|
125
|
+
</View>
|
|
126
|
+
))}
|
|
127
|
+
</View>
|
|
128
|
+
</AutoScroll>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
118
131
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
style={{
|
|
127
|
-
backgroundColor: '#F5F5F5',
|
|
128
|
-
borderRadius: 8,
|
|
132
|
+
const styles = StyleSheet.create({
|
|
133
|
+
scrollContainer: {
|
|
134
|
+
height: 120,
|
|
135
|
+
width: '100%',
|
|
136
|
+
},
|
|
137
|
+
contentContainer: {
|
|
138
|
+
flexDirection: 'row',
|
|
129
139
|
padding: 10,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
},
|
|
141
|
+
card: {
|
|
142
|
+
width: 100,
|
|
143
|
+
height: 100,
|
|
144
|
+
backgroundColor: '#f0f0f0',
|
|
145
|
+
borderRadius: 8,
|
|
146
|
+
marginRight: 10,
|
|
147
|
+
justifyContent: 'center',
|
|
148
|
+
alignItems: 'center',
|
|
149
|
+
},
|
|
150
|
+
cardText: {
|
|
151
|
+
fontSize: 16,
|
|
152
|
+
fontWeight: 'bold',
|
|
153
|
+
},
|
|
154
|
+
});
|
|
133
155
|
```
|
|
134
156
|
|
|
135
|
-
###
|
|
157
|
+
### News Ticker with MarqueeText
|
|
158
|
+
```jsx
|
|
159
|
+
import React from 'react';
|
|
160
|
+
import { View, StyleSheet } from 'react-native';
|
|
161
|
+
import { MarqueeText } from 'rn-marquee-text';
|
|
136
162
|
|
|
137
|
-
|
|
163
|
+
const NewsTicker = () => {
|
|
164
|
+
return (
|
|
165
|
+
<View style={styles.tickerContainer}>
|
|
166
|
+
<MarqueeText
|
|
167
|
+
text="BREAKING NEWS: Latest updates on global events. Markets reach all-time high. New technological breakthroughs announced."
|
|
168
|
+
speed={70}
|
|
169
|
+
backgroundColor="#1a365d"
|
|
170
|
+
textColor="#ffffff"
|
|
171
|
+
fontSize={16}
|
|
172
|
+
bounceMode={false}
|
|
173
|
+
/>
|
|
174
|
+
</View>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
138
177
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
178
|
+
const styles = StyleSheet.create({
|
|
179
|
+
tickerContainer: {
|
|
180
|
+
width: '100%',
|
|
181
|
+
borderRadius: 4,
|
|
182
|
+
overflow: 'hidden',
|
|
183
|
+
marginVertical: 10,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
147
186
|
```
|
|
148
187
|
|
|
149
|
-
## Performance
|
|
188
|
+
## Tips for Optimal Performance
|
|
189
|
+
- Adjust speed based on content length: Longer content might benefit from faster speeds.
|
|
190
|
+
- Use appropriate delays: Give your users time to notice the content before it starts scrolling.
|
|
191
|
+
- Consider bounce mode for important information: The back-and-forth animation can draw more attention.
|
|
192
|
+
- Limit the number of simultaneous scrolling components: Too many can impact performance.
|
|
193
|
+
- Test on lower-end devices: Ensure smooth animations across various device capabilities.
|
|
150
194
|
|
|
151
|
-
|
|
152
|
-
- For large text, consider increasing the `delay` to give the component time to measure properly
|
|
153
|
-
- If animations appear jerky, try wrapping your component in a `React.memo()` to prevent unnecessary re-renders
|
|
195
|
+
## Troubleshooting
|
|
154
196
|
|
|
155
|
-
|
|
197
|
+
### Text Not Scrolling
|
|
198
|
+
- Make sure the text is actually larger than its container
|
|
199
|
+
- Check that enabled prop is not set to false
|
|
200
|
+
- Try increasing the container's overflow: 'hidden' style
|
|
201
|
+
|
|
202
|
+
### Animation Feels Choppy
|
|
203
|
+
- Use the useNativeDriver: true option if available
|
|
204
|
+
- Reduce the number of simultaneously animating components
|
|
205
|
+
- Simplify your component tree structure
|
|
156
206
|
|
|
207
|
+
## License
|
|
157
208
|
MIT
|
|
158
209
|
|
|
159
210
|
## Contributing
|
|
211
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
160
212
|
|
|
161
|
-
|
|
213
|
+
1. Fork the project
|
|
214
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
215
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
216
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
217
|
+
5. Open a Pull Request
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TextStyle, ViewStyle } from 'react-native';
|
|
3
|
+
/**
|
|
4
|
+
* AutoScroll component that measures its content and container
|
|
5
|
+
* dimensions and automatically sets up a scrolling animation if
|
|
6
|
+
* the content is larger than the container.
|
|
7
|
+
*
|
|
8
|
+
* @prop {React.ReactNode} children - The content to be scrolled
|
|
9
|
+
* @prop {AnimationMode} mode - The animation mode (LOOP or BOUNCE)
|
|
10
|
+
* @prop {number} speed - The speed of the animation in px/s
|
|
11
|
+
* @prop {number} delay - The delay before the animation starts in ms
|
|
12
|
+
* @prop {number} endPauseDuration - The pause duration at the end of a bounce animation in ms
|
|
13
|
+
* @prop {ViewStyle} style - Additional styles for the container
|
|
14
|
+
* @prop {TextStyle} textStyle - Additional styles for the text content
|
|
15
|
+
* @prop {boolean} enabled - Whether the scrolling animation is enabled
|
|
16
|
+
* @prop {'horizontal'|'vertical'} direction - The direction of the scrolling animation
|
|
17
|
+
*/
|
|
18
|
+
export declare const AutoScroll: ({ children, mode, speed, delay, endPauseDuration, style, textStyle, enabled, direction, }: {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
mode?: "loop" | "bounce";
|
|
21
|
+
speed?: number;
|
|
22
|
+
delay?: number;
|
|
23
|
+
endPauseDuration?: number;
|
|
24
|
+
style?: ViewStyle;
|
|
25
|
+
textStyle?: TextStyle;
|
|
26
|
+
enabled?: boolean;
|
|
27
|
+
direction?: "horizontal" | "vertical";
|
|
28
|
+
}) => React.JSX.Element;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import Animated, { useSharedValue, useAnimatedStyle, withTiming, withRepeat, withDelay, withSequence, cancelAnimation, Easing, } from 'react-native-reanimated';
|
|
4
|
+
import { AnimationMode } from './constants';
|
|
5
|
+
/**
|
|
6
|
+
* AutoScroll component that measures its content and container
|
|
7
|
+
* dimensions and automatically sets up a scrolling animation if
|
|
8
|
+
* the content is larger than the container.
|
|
9
|
+
*
|
|
10
|
+
* @prop {React.ReactNode} children - The content to be scrolled
|
|
11
|
+
* @prop {AnimationMode} mode - The animation mode (LOOP or BOUNCE)
|
|
12
|
+
* @prop {number} speed - The speed of the animation in px/s
|
|
13
|
+
* @prop {number} delay - The delay before the animation starts in ms
|
|
14
|
+
* @prop {number} endPauseDuration - The pause duration at the end of a bounce animation in ms
|
|
15
|
+
* @prop {ViewStyle} style - Additional styles for the container
|
|
16
|
+
* @prop {TextStyle} textStyle - Additional styles for the text content
|
|
17
|
+
* @prop {boolean} enabled - Whether the scrolling animation is enabled
|
|
18
|
+
* @prop {'horizontal'|'vertical'} direction - The direction of the scrolling animation
|
|
19
|
+
*/
|
|
20
|
+
export var AutoScroll = function (_a) {
|
|
21
|
+
var children = _a.children, _b = _a.mode, mode = _b === void 0 ? '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, _f = _a.style, style = _f === void 0 ? {} : _f, _g = _a.textStyle, textStyle = _g === void 0 ? {} : _g, _h = _a.enabled, enabled = _h === void 0 ? true : _h, _j = _a.direction, direction = _j === void 0 ? 'vertical' : _j;
|
|
22
|
+
// References for measurement
|
|
23
|
+
var containerRef = useRef(null);
|
|
24
|
+
var contentRef = useRef(null);
|
|
25
|
+
// Dimensions state
|
|
26
|
+
var _k = useState(0), containerSize = _k[0], setContainerSize = _k[1];
|
|
27
|
+
var _l = useState(0), contentSize = _l[0], setContentSize = _l[1];
|
|
28
|
+
var _m = useState(false), needsScrolling = _m[0], setNeedsScrolling = _m[1];
|
|
29
|
+
var _o = useState(false), isReady = _o[0], setIsReady = _o[1];
|
|
30
|
+
// Animation values
|
|
31
|
+
var scrollPosition = useSharedValue(0);
|
|
32
|
+
var isHorizontal = direction === 'horizontal';
|
|
33
|
+
// Log props for debugging
|
|
34
|
+
useEffect(function () {
|
|
35
|
+
console.log('AutoScroll Props:', {
|
|
36
|
+
mode: mode,
|
|
37
|
+
speed: speed,
|
|
38
|
+
delay: delay,
|
|
39
|
+
direction: direction,
|
|
40
|
+
enabled: enabled
|
|
41
|
+
});
|
|
42
|
+
}, [mode, speed, delay, direction, enabled]);
|
|
43
|
+
// Measure container and content dimensions
|
|
44
|
+
useEffect(function () {
|
|
45
|
+
var measureDimensions = function () {
|
|
46
|
+
if (containerRef.current && contentRef.current) {
|
|
47
|
+
var measureContainer_1 = function () {
|
|
48
|
+
var _a;
|
|
49
|
+
(_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.measure(function (x, y, width, height) {
|
|
50
|
+
var size = isHorizontal ? width : height;
|
|
51
|
+
setContainerSize(size);
|
|
52
|
+
console.log('Container size:', size);
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
var measureContent_1 = function () {
|
|
56
|
+
var _a;
|
|
57
|
+
(_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.measure(function (x, y, width, height) {
|
|
58
|
+
var size = isHorizontal ? width : height;
|
|
59
|
+
setContentSize(size);
|
|
60
|
+
console.log('Content size:', size);
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
// Allow layout to complete before measuring
|
|
64
|
+
setTimeout(function () {
|
|
65
|
+
measureContainer_1();
|
|
66
|
+
measureContent_1();
|
|
67
|
+
}, 300);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
measureDimensions();
|
|
71
|
+
}, [children, isHorizontal]);
|
|
72
|
+
// Check if scrolling is needed
|
|
73
|
+
useEffect(function () {
|
|
74
|
+
if (containerSize > 0 && contentSize > 0) {
|
|
75
|
+
var needsScroll = contentSize > containerSize;
|
|
76
|
+
setNeedsScrolling(needsScroll);
|
|
77
|
+
setIsReady(true);
|
|
78
|
+
console.log('Needs scrolling:', needsScroll);
|
|
79
|
+
}
|
|
80
|
+
}, [containerSize, contentSize]);
|
|
81
|
+
// Control animation based on dimensions and mode
|
|
82
|
+
useEffect(function () {
|
|
83
|
+
if (!isReady || !needsScrolling || !enabled)
|
|
84
|
+
return;
|
|
85
|
+
// Calculate animation duration based on speed
|
|
86
|
+
var distance = contentSize - containerSize;
|
|
87
|
+
var duration = (distance / speed) * 1000;
|
|
88
|
+
console.log('Animation setup:', { distance: distance, duration: duration });
|
|
89
|
+
// Reset position
|
|
90
|
+
scrollPosition.value = 0;
|
|
91
|
+
if (mode === AnimationMode.LOOP || mode === 'loop') {
|
|
92
|
+
// Continuous loop animation
|
|
93
|
+
scrollPosition.value = withDelay(delay, withRepeat(withTiming(-distance, { duration: duration, easing: Easing.linear }), -1, false));
|
|
94
|
+
}
|
|
95
|
+
else if (mode === AnimationMode.BOUNCE || mode === 'bounce') {
|
|
96
|
+
// Bounce animation (back and forth)
|
|
97
|
+
scrollPosition.value = withDelay(delay, withRepeat(withSequence(withTiming(-distance, { duration: duration, easing: Easing.linear }), withTiming(-distance, { duration: endPauseDuration, easing: Easing.linear }), withTiming(0, { duration: duration, easing: Easing.linear }), withTiming(0, { duration: endPauseDuration, easing: Easing.linear })), -1, false));
|
|
98
|
+
}
|
|
99
|
+
return function () {
|
|
100
|
+
cancelAnimation(scrollPosition);
|
|
101
|
+
};
|
|
102
|
+
}, [isReady, needsScrolling, enabled, scrollPosition, contentSize, containerSize, mode, speed, delay, endPauseDuration]);
|
|
103
|
+
// Create animated style
|
|
104
|
+
var animatedStyle = useAnimatedStyle(function () {
|
|
105
|
+
return {
|
|
106
|
+
transform: [
|
|
107
|
+
isHorizontal
|
|
108
|
+
? { translateX: scrollPosition.value }
|
|
109
|
+
: { translateY: scrollPosition.value },
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
// Check if children is text content
|
|
114
|
+
var isTextContent = typeof children === 'string';
|
|
115
|
+
return (<View ref={containerRef} style={[
|
|
116
|
+
styles.container,
|
|
117
|
+
isHorizontal ? styles.horizontalContainer : styles.verticalContainer,
|
|
118
|
+
style,
|
|
119
|
+
]}>
|
|
120
|
+
{needsScrolling ? (<Animated.View ref={contentRef} style={[styles.content, animatedStyle]}>
|
|
121
|
+
{isTextContent ? (<Text style={[styles.text, textStyle]}>{children}</Text>) : (children)}
|
|
122
|
+
</Animated.View>) : (<View ref={contentRef} style={styles.content}>
|
|
123
|
+
{isTextContent ? (<Text style={[styles.text, textStyle]}>{children}</Text>) : (children)}
|
|
124
|
+
</View>)}
|
|
125
|
+
</View>);
|
|
126
|
+
};
|
|
127
|
+
var styles = StyleSheet.create({
|
|
128
|
+
container: {
|
|
129
|
+
overflow: 'hidden',
|
|
130
|
+
},
|
|
131
|
+
horizontalContainer: {
|
|
132
|
+
flexDirection: 'row',
|
|
133
|
+
},
|
|
134
|
+
verticalContainer: {
|
|
135
|
+
flexDirection: 'column',
|
|
136
|
+
},
|
|
137
|
+
content: {
|
|
138
|
+
flexGrow: 0,
|
|
139
|
+
flexShrink: 0,
|
|
140
|
+
},
|
|
141
|
+
text: {
|
|
142
|
+
flexGrow: 0,
|
|
143
|
+
flexShrink: 0,
|
|
144
|
+
},
|
|
145
|
+
});
|
package/dist/MarqueeText.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
import { ViewStyle } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
|
|
4
|
-
declare const MarqueeText: ({ text, speed, containerStyle, textStyle }: {
|
|
2
|
+
declare const MarqueeText: ({ text, speed, backgroundColor, textColor, fontSize, paddingVertical, paddingHorizontal, delay, bounceMode, endPauseDuration, }: {
|
|
5
3
|
text: string;
|
|
6
4
|
speed?: number;
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
backgroundColor?: string;
|
|
6
|
+
textColor?: string;
|
|
7
|
+
fontSize?: number;
|
|
8
|
+
paddingVertical?: number;
|
|
9
|
+
paddingHorizontal?: number;
|
|
10
|
+
delay?: number;
|
|
11
|
+
bounceMode?: boolean;
|
|
12
|
+
endPauseDuration?: number;
|
|
9
13
|
}) => React.JSX.Element;
|
|
10
14
|
export default MarqueeText;
|
package/dist/MarqueeText.js
CHANGED
|
@@ -1,62 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
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';
|
|
3
5
|
var MarqueeText = function (_a) {
|
|
4
|
-
var text = _a.text, _b = _a.speed, speed = _b === void 0 ?
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var
|
|
9
|
-
var _f = useState(0), textWidth = _f[0], setTextWidth = _f[1];
|
|
10
|
-
// Start animation when we have both widths
|
|
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
11
|
useEffect(function () {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
|
|
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));
|
|
16
30
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Animated.timing(scrollX, {
|
|
25
|
-
toValue: -textWidth, // Move text completely off screen to the left
|
|
26
|
-
duration: (textWidth + containerWidth) / speed * 1000, // Time based on distance and speed
|
|
27
|
-
useNativeDriver: true, // This is crucial for performance
|
|
28
|
-
}).start(function (_a) {
|
|
29
|
-
var finished = _a.finished;
|
|
30
|
-
// When animation completes, restart it
|
|
31
|
-
if (finished) {
|
|
32
|
-
startAnimation();
|
|
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));
|
|
33
38
|
}
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
+
};
|
|
46
|
+
});
|
|
47
|
+
return (<View style={{
|
|
48
|
+
backgroundColor: backgroundColor,
|
|
49
|
+
paddingVertical: paddingVertical,
|
|
50
|
+
paddingHorizontal: paddingHorizontal,
|
|
51
|
+
overflow: 'hidden',
|
|
38
52
|
}}>
|
|
39
|
-
<Animated.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
</Animated.
|
|
53
|
+
<Animated.Text style={[
|
|
54
|
+
{
|
|
55
|
+
color: textColor,
|
|
56
|
+
fontSize: fontSize,
|
|
57
|
+
},
|
|
58
|
+
animatedStyle,
|
|
59
|
+
]} numberOfLines={1}>
|
|
60
|
+
{text}
|
|
61
|
+
</Animated.Text>
|
|
48
62
|
</View>);
|
|
49
63
|
};
|
|
50
|
-
var styles = StyleSheet.create({
|
|
51
|
-
container: {
|
|
52
|
-
overflow: 'hidden',
|
|
53
|
-
backgroundColor: 'black',
|
|
54
|
-
height: 40,
|
|
55
|
-
justifyContent: 'center',
|
|
56
|
-
},
|
|
57
|
-
text: {
|
|
58
|
-
color: 'white',
|
|
59
|
-
fontSize: 16,
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
64
|
export default MarqueeText;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rn-marquee-text",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A customizable marquee (scrolling) text component for React Native",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
|
-
"url": "git+https://github.com/pareshchavda/rn-marquee-text.git"
|
|
32
|
+
"url": "git+https://github.com/pareshchavda/rn-marquee-text-public.git"
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
|
-
"url": "https://github.com/pareshchavda/rn-marquee-text/issues"
|
|
35
|
+
"url": "https://github.com/pareshchavda/rn-marquee-text-public/issues"
|
|
36
36
|
},
|
|
37
|
-
"homepage": "https://github.com/pareshchavda/rn-marquee-text#readme",
|
|
37
|
+
"homepage": "https://github.com/pareshchavda/rn-marquee-text-public#readme",
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"prop-types": ">=15.0.0",
|
|
40
40
|
"react": "*",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"typescript": "^5.0.0"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"react-native-gesture-handler": "^2.25.0"
|
|
53
|
+
"react-native-gesture-handler": "^2.25.0",
|
|
54
|
+
"rn-marquee-text": "^1.0.4"
|
|
54
55
|
}
|
|
55
56
|
}
|