import { useSpring, animated, easings, to, useInView } from '@react-spring/web'; import React, { useEffect, useState } from 'react'; import { PresEffect, PresEffectDirection } from './PresEnums'; import './SlideEffect.scss'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; interface Props { // pass in doc to extract width, height, bg doc?: Doc; dir: PresEffectDirection; presEffect: PresEffect; friction: number; tension: 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, }; // TODO: add visibility detector when the slide comes into view export default function SpringAnimation({ doc, dir, friction, tension, mass, presEffect, children, infinite }: Props) { const [springs, api] = useSpring( () => ({ from: { x: 0, y: 0, opacity: 0, scale: 1, }, config: { tension: tension, friction: friction, mass: mass, }, onStart: () => {}, onRest: () => {}, }), [tension, friction, mass] ); const [ref, inView] = useInView({ once: true, }); // Whether the animation is currently playing const [animating, setAnimating] = useState(false); 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, }, }, }; const lightspeedConfig = { from: { opacity: 0, }, to: [], }; // Switch animation depending on slide effect const startAnimation = () => { 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 flipRender = () => { // return ( //
// 1 - o), transform }} /> // // {children} // //
// ); // }; 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(() => { // // TODO: Control start with slide visibility instead // setTimeout(() => { // startAnimation(); // }, 200); // }, []); useEffect(() => { if (infinite || !inView) return; console.log('in view'); // TODO: Control start with slide visibility instead setTimeout(() => { startAnimation(); }, 100); }, [inView]); useEffect(() => { if (infinite) { startAnimation(); } }, []); return
{getRenderDoc()}
; }