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
JavaScript
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