UNPKG

react-native-marquee-text-loop

Version:
139 lines (132 loc) 5.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MarqueeText = void 0; var React = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } // Clone of the marquee text const ScrollingTextClone = ({ index, children, anim, textLayout }) => { // Animated styles to position the cloned text const styles = (0, _reactNativeReanimated.useAnimatedStyle)(() => { return { position: 'absolute', left: (index - 1) * (textLayout.value.width + 10), // Spacing after each clone text transform: [{ translateX: -(anim.value % (textLayout.value.width + 10) // Scroll the text horizontally ) }] }; }, [index, textLayout]); // Return the cloned text element with animated styles return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { style: styles, children: children }); }; // Marquee text component const MarqueeText = exports.MarqueeText = /*#__PURE__*/React.memo(({ speed = 1, text = '', textStyles = {} }) => { // Store measurements of the parent layout and text const parentLayout = (0, _reactNativeReanimated.useSharedValue)({ width: 0, height: 0, x: 0, y: 0 }); const textLayout = (0, _reactNativeReanimated.useSharedValue)({ width: 0, height: 0, x: 0, y: 0 }); // number clones of the text are needed for scrolling const [numberOfClones, setNumberOfClones] = React.useState(0); // animated value for the scrolling animation const scrollAnimationValue = (0, _reactNativeReanimated.useSharedValue)(0); const frameRateMs = 30; // frame rate // update the animation on each animation (0, _reactNativeReanimated.useFrameCallback)(frameInfo => { if (frameInfo.timeSincePreviousFrame === null) { return; } const frameDelta = frameInfo.timeSincePreviousFrame / frameRateMs; scrollAnimationValue.value += speed * frameDelta; // Update the scroll animation }, true); // update the number of clones based on text size (0, _reactNativeReanimated.useAnimatedReaction)(() => { // If the text or parent container size is zero - zero clones if (textLayout.value.width === 0 || parentLayout.value.width === 0 || textLayout.value.height === 0 || parentLayout.value.height === 0) { return 0; } // Calculate the number of clones needed based on the parent layout return Math.round(parentLayout.value.width / textLayout.value.width) + 1 // Adding extra clones to ensure the loop continues ; }, v => { if (v === 0) { return; // No clones if the measurement values are zero } (0, _reactNativeReanimated.runOnJS)(setNumberOfClones)(v + 2); // Set the clone count in JS thread (runOnJS avoids Reanimated thread issues) }, []); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, { onLayout: ev => { parentLayout.value = ev.nativeEvent.layout; // dimensions of the parent container }, pointerEvents: "box-none", children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.View, { style: styles.row, pointerEvents: "box-none", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.ScrollView, { horizontal: true, style: styles.scrollContainer, pointerEvents: "box-none", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { onLayout: ev => { textLayout.value = ev.nativeEvent.layout; // width of the text }, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: textStyles, children: text }) }) }), numberOfClones > 0 && // Render the clones [...Array(numberOfClones).keys()].map(index => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(ScrollingTextClone, { index: index, anim: scrollAnimationValue, textLayout: textLayout, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: textStyles, children: text }) }, `clone-${index}`); })] }) }); }); const styles = _reactNative.StyleSheet.create({ scrollContainer: { opacity: 0, zIndex: -9999 }, // invisible scrollView row: { flexDirection: 'row', overflow: 'hidden' } //cloned texts in a horizontal row }); //# sourceMappingURL=index.js.map