UNPKG

@animatereactnative/marquee

Version:
168 lines (166 loc) 6.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Marquee = void 0; var React = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); 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; } const AnimatedChild = ({ index, children, anim, textMeasurement, spacing, direction }) => { const stylez = (0, _reactNativeReanimated.useAnimatedStyle)(() => { if (direction === 'vertical') { return { position: 'absolute', top: (index - 1) * (textMeasurement.value.height + spacing), transform: [{ translateY: -(anim.value % (textMeasurement.value.height + spacing)) }] }; } return { position: 'absolute', left: (index - 1) * (textMeasurement.value.width + spacing), transform: [{ translateX: -(anim.value % (textMeasurement.value.width + spacing)) }] }; }, [index, spacing, textMeasurement]); return /*#__PURE__*/React.createElement(_reactNativeReanimated.default.View, { style: stylez }, children); }; /** * Used to animate the given children in a horizontal manner. */ const Marquee = exports.Marquee = /*#__PURE__*/React.memo(/*#__PURE__*/React.forwardRef(({ speed = 1, children, spacing = 0, style, reverse, frameRate, direction = 'horizontal', position, withGesture = true }, ref) => { const parentMeasurement = (0, _reactNativeReanimated.useSharedValue)({ width: 0, height: 0, x: 0, y: 0 }); const textMeasurement = (0, _reactNativeReanimated.useSharedValue)({ width: 0, height: 0, x: 0, y: 0 }); const [cloneTimes, setCloneTimes] = React.useState(0); const anim = (0, _reactNativeReanimated.useSharedValue)(0); const frameRateMs = frameRate ? 1000 / frameRate : null; const frameCallback = (0, _reactNativeReanimated.useFrameCallback)(frameInfo => { if (frameInfo.timeSincePreviousFrame === null) return; const frameDelta = frameRateMs ? frameInfo.timeSincePreviousFrame / frameRateMs : 1; if (reverse) { anim.value -= speed * frameDelta; } else { anim.value += speed * frameDelta; } }, true); (0, _reactNativeReanimated.useDerivedValue)(() => { if (position) { position.value = anim.value; } }); (0, _reactNativeReanimated.useAnimatedReaction)(() => { if (textMeasurement.value.width === 0 || parentMeasurement.value.width === 0 || textMeasurement.value.height === 0 || parentMeasurement.value.height === 0) { return 0; } return Math.round(direction === 'horizontal' ? parentMeasurement.value.width / textMeasurement.value.width : parentMeasurement.value.height / textMeasurement.value.height) + 1; }, v => { if (v === 0) { return; } // This is going to cover the case when the text/element size // is greater than the actual parent size // Double this to cover the entire screen twice, in this way we can // reset the position of the first element when its going to move out // of the screen without any noticible glitch (0, _reactNativeReanimated.runOnJS)(setCloneTimes)(v + 2); }, [direction]); // Pan Gestures function start() { frameCallback.setActive(true); } function stop() { frameCallback.setActive(false); } React.useImperativeHandle(ref, () => ({ start, stop, isActive: frameCallback.isActive })); const pan = _reactNativeGestureHandler.Gesture.Pan().enabled(withGesture).onBegin(() => { (0, _reactNativeReanimated.runOnJS)(stop)(); }).onChange(e => { anim.value += -(direction === 'horizontal' ? e.changeX : e.changeY); }).onFinalize(e => { anim.value = (0, _reactNativeReanimated.withDecay)({ velocity: -(direction === 'horizontal' ? e.velocityX : e.velocityY) }, finished => { if (finished) { (0, _reactNativeReanimated.runOnJS)(start)(); } }); }); return /*#__PURE__*/React.createElement(_reactNativeReanimated.default.View, { key: direction, style: style, onLayout: ev => { parentMeasurement.value = ev.nativeEvent.layout; }, pointerEvents: "box-none" }, /*#__PURE__*/React.createElement(_reactNativeGestureHandler.GestureDetector, { gesture: pan }, /*#__PURE__*/React.createElement(_reactNativeReanimated.default.View, { style: styles.row, pointerEvents: "box-none" }, /*#__PURE__*/React.createElement(_reactNativeReanimated.default.ScrollView, { horizontal: direction === 'horizontal', style: styles.hidden, pointerEvents: "box-none" }, /*#__PURE__*/React.createElement(_reactNative.View, { onLayout: ev => { textMeasurement.value = ev.nativeEvent.layout; } }, children)), cloneTimes > 0 && [...Array(cloneTimes).keys()].map(index => { return /*#__PURE__*/React.createElement(AnimatedChild, { key: `clone-${index}`, index: index, anim: anim, textMeasurement: textMeasurement, spacing: spacing, direction: direction }, children); })))); })); const styles = _reactNative.StyleSheet.create({ hidden: { opacity: 0, zIndex: -9999 }, row: { flexDirection: 'row' } }); //# sourceMappingURL=index.js.map