/* eslint-disable react/require-default-props */ import { animated, to, useInView, useSpring } from '@react-spring/web'; import React, { useEffect } from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import { PresEffect, PresEffectDirection } from './PresEnums'; import './SlideEffect.scss'; interface SlideEffectProps { // pass in doc to extract width, height, bg doc?: Doc; dir: PresEffectDirection; presEffect: PresEffect; // stiffness (figma) = tension (react-spring) tension: number; // damping (figma) = friction (react-spring) friction: number; mass: number; children: React.ReactNode; infinite?: boolean; } const DEFAULT_WIDTH = 40; const PREVIEW_OFFSET = 60; const ACTUAL_OFFSET = 200; const infiniteOptions = { loop: true, delay: 500, }; /** * This component wraps around the doc to create an effect animation, and also wraps the preview animations * for the effects as well. */ export default function SpringAnimation({ doc, dir, friction, tension, mass, presEffect, children, infinite }: SlideEffectProps) { const [springs, api] = useSpring( () => ({ from: { x: 0, y: 0, opacity: 0, scale: 1, }, config: { tension, friction, mass, }, onStart: () => {}, onRest: () => {}, }), [tension, friction, mass] ); const [ref, inView] = useInView({ once: true, }); const zoomConfig = { from: { scale: 0, x: 0, y: 0, opacity: 1, }, to: { scale: 1, x: 0, y: 0, opacity: 1, config: { tension: tension, friction: friction, mass: mass, }, }, }; const fadeConfig = { from: { opacity: 0, scale: 1, x: 0, y: 0, }, to: { opacity: 1, scale: 1, x: 0, y: 0, config: { tension: tension, friction: friction, mass: mass, }, }, }; const rotateConfig = { from: { x: 0, }, to: { x: 360, config: { tension: tension, friction: friction, mass: mass, }, }, }; const getBounceConfigFrom = () => { switch (dir) { case PresEffectDirection.Left: return { from: { opacity: 0, x: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET, y: 0, }, }; case PresEffectDirection.Right: return { from: { opacity: 0, x: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET, y: 0, }, }; case PresEffectDirection.Top: return { from: { opacity: 0, x: 0, y: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET, }, }; case PresEffectDirection.Bottom: return { from: { opacity: 0, x: 0, y: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET, }, }; default: // no movement for center return { from: { opacity: 0, x: 0, y: 0, }, }; } }; const bounceConfig = { ...getBounceConfigFrom(), to: [ { opacity: 1, x: 0, y: 0, config: { tension: tension, friction: friction, mass: mass, }, }, ], }; const flipConfig = { from: { x: 0, }, to: { x: 180, config: { tension: tension, friction: friction, mass: mass, }, }, }; // only left and right for now const getRollConfigFrom = () => { switch (dir) { case PresEffectDirection.Left: return { from: { opacity: 0, x: -100, y: -120, }, }; case PresEffectDirection.Right: return { from: { opacity: 0, x: 100, y: 120, }, }; case PresEffectDirection.Top: return { from: { opacity: 0, x: -100, y: -120, }, }; case PresEffectDirection.Bottom: return { from: { opacity: 0, x: -100, y: -120, }, }; default: // no movement for center return { from: { opacity: 0, x: 0, y: 0, }, }; } }; const rollConfig = { ...getRollConfigFrom(), to: { opacity: 1, x: 0, y: 0, config: { tension: tension, friction: friction, mass: mass, }, }, }; // Switch animation depending on slide effect const startAnimation = () => { api.stop(); let config: any = zoomConfig; switch (presEffect) { case PresEffect.Bounce: config = bounceConfig; break; case PresEffect.Zoom: config = zoomConfig; break; case PresEffect.Rotate: config = rotateConfig; break; case PresEffect.Fade: config = fadeConfig; break; case PresEffect.Flip: config = flipConfig; break; case PresEffect.Roll: config = rollConfig; break; case PresEffect.Lightspeed: break; default: break; } if (infinite) { config = { ...config, ...infiniteOptions }; } api.start(config); }; const getRenderDoc = () => { switch (presEffect) { case PresEffect.Rotate: return ( `rotate(${val}deg)`) }}> {children} ); case PresEffect.Flip: return ( // Pass in doc dimensions
{dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? ( <> `perspective(600px) rotateX(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH, backgroundColor: infinite ? '#a825ff' : 'rgb(223, 223, 223);', }} /> `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} ) : ( <> `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }} /> `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} )}
); case PresEffect.Roll: return ( `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) }}> {children} ); default: return ( {children} ); } }; useEffect(() => { if (infinite || !inView) return; setTimeout(() => { startAnimation(); }, 100); }, [inView]); useEffect(() => { if (infinite) { startAnimation(); } }, [presEffect, tension, friction, mass]); return
{getRenderDoc()}
; }