/* 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 (