UNPKG

react-native-fiesta

Version:

A set of celebration animations powered by Skia. Engage more with your users by celebrating in your React Native application.

105 lines (102 loc) 4.76 kB
import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useState, useRef } from 'react'; import { StyleSheet } from 'react-native'; import { Canvas, Group } from '@shopify/react-native-skia'; import { cancelAnimation, runOnJS, useDerivedValue, useSharedValue, withSpring } from 'react-native-reanimated'; import { screenHeight } from '../constants/dimensions'; import { screenWidth } from '../constants/dimensions'; import { shuffleArray } from '../utils/array'; import { colorsFromTheme } from '../utils/colors'; import { FiestaThemes } from '../constants/theming'; import { FiestaSpeed, singleItemFadeSpeed } from '../constants/speed'; export let PopperDirection = /*#__PURE__*/function (PopperDirection) { PopperDirection["Ascending"] = "Ascending"; PopperDirection["Descending"] = "Descending"; return PopperDirection; }({}); export const Popper = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({ spacing = 30, theme = FiestaThemes.Default, renderItem, autoPlay = true, direction = PopperDirection.Descending, positionSpringConfig = FiestaSpeed.Normal, fadeSpringConfig = singleItemFadeSpeed }, ref) => { // properties that might be controlled are also defined as states and refs const [controlledTheme, setControlledTheme] = useState(theme); const controlledDirection = useRef(direction); const controlledPositionSpringConfig = useRef(positionSpringConfig); const controlledFadeSpringConfig = useRef(fadeSpringConfig); const [displayCanvas, setDisplayCanvas] = useState(autoPlay); const initialPosition = controlledDirection.current === PopperDirection.Ascending ? screenHeight : -screenHeight / 2; const finalPosition = controlledDirection.current === PopperDirection.Ascending ? -screenHeight : screenHeight; const optimalNumberOfItems = useMemo(() => Math.floor(screenWidth / spacing), [spacing]); const itemsToRenderArray = useMemo(() => [...Array(optimalNumberOfItems)], [optimalNumberOfItems]); const yPositions = useMemo(() => shuffleArray(itemsToRenderArray.map((_, i) => i * spacing)), [itemsToRenderArray, spacing]); const containerYPosition = useSharedValue(0); const opacity = useSharedValue(1); const colors = useMemo(() => colorsFromTheme(controlledTheme, optimalNumberOfItems), [controlledTheme, optimalNumberOfItems]); const changeItemPosition = useCallback(() => { containerYPosition.value = withSpring(finalPosition, controlledPositionSpringConfig.current, finished => { if (finished) { containerYPosition.value = initialPosition; runOnJS(setDisplayCanvas)(false); } }); opacity.value = withSpring(0, controlledFadeSpringConfig.current); }, [containerYPosition, controlledFadeSpringConfig, controlledPositionSpringConfig, finalPosition, initialPosition, opacity]); const transform = useDerivedValue(() => [{ translateY: containerYPosition.value }]); useImperativeHandle(ref, () => ({ start(params) { // cancel any ongoing animation cancelAnimation(containerYPosition); setDisplayCanvas(false); // reset the container position and opacity containerYPosition.value = initialPosition; opacity.value = 1; if (params !== null && params !== void 0 && params.theme) { setControlledTheme(params.theme); } if (params !== null && params !== void 0 && params.direction) { controlledDirection.current = params.direction; } if (params !== null && params !== void 0 && params.positionSpringConfig) { controlledPositionSpringConfig.current = params.positionSpringConfig; } if (params !== null && params !== void 0 && params.fadeSpringConfig) { controlledFadeSpringConfig.current = params.fadeSpringConfig; } // plays the animation again setDisplayCanvas(true); changeItemPosition(); } })); // when the controlled direction changes, reset the container position useEffect(() => { containerYPosition.value = initialPosition; }, [containerYPosition, controlledDirection, initialPosition]); useEffect(() => { displayCanvas && changeItemPosition(); }, [displayCanvas, changeItemPosition]); if (!displayCanvas) return null; return /*#__PURE__*/React.createElement(Canvas, { style: styles.canvas, pointerEvents: "none" }, /*#__PURE__*/React.createElement(Group, { transform: transform, opacity: opacity }, /*#__PURE__*/React.createElement(React.Fragment, null, itemsToRenderArray.map((_, index) => renderItem({ x: spacing * index, y: yPositions[index], colors }, index))))); })); const styles = StyleSheet.create({ canvas: { ...StyleSheet.absoluteFillObject, zIndex: 1 } }); //# sourceMappingURL=Popper.js.map