From 69e286b504c2f1bbef7d489dc675b9e54ef8d983 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 16 May 2024 19:52:13 -0400
Subject: refactor/cleanup of pres animations.  changed effects to start
 halfway through a zoom transition.

---
 src/client/views/nodes/trails/SlideEffect.tsx | 402 +++++---------------------
 1 file changed, 80 insertions(+), 322 deletions(-)

(limited to 'src/client/views/nodes/trails/SlideEffect.tsx')

diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx
index 03cd88f45..00039e3cb 100644
--- a/src/client/views/nodes/trails/SlideEffect.tsx
+++ b/src/client/views/nodes/trails/SlideEffect.tsx
@@ -5,358 +5,116 @@ import { Doc } from '../../../../fields/Doc';
 import { NumCast } from '../../../../fields/Types';
 import { PresEffect, PresEffectDirection } from './PresEnums';
 import './SlideEffect.scss';
+import { emptyFunction } from '../../../../Utils';
 
 interface SlideEffectProps {
-    // pass in doc to extract width, height, bg
-    doc?: Doc;
+    doc?: Doc; // pass in doc to extract width, height, bg
     dir: PresEffectDirection;
     presEffect: PresEffect;
-    // stiffness (figma) = tension (react-spring)
-    tension: number;
-    // damping (figma) = friction (react-spring)
-    friction: number;
-    mass: number;
+    springSettings: {
+        stiffness: number;
+        damping: number;
+        mass: number;
+    };
     children: React.ReactNode;
     infinite?: boolean;
+    startOpacity?: number; // set to zero to linearly fade in while animating
 }
 
 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,
-            },
-        },
+export default function SpringAnimation({ doc, dir, springSettings, presEffect, children, infinite, startOpacity }: SlideEffectProps) {
+    const expandConfig = {
+        to: { scale: 1, x: 0, y: 0 },
+        from: { scale: 0, x: 0, y: 0 },
     };
-
     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,
-            },
-        },
+        to: { x: 0, y: 0 },
+        from: { x: 0, y: 0 },
     };
-
     const rotateConfig = {
-        from: {
-            x: 0,
-        },
-        to: {
-            x: 360,
-            config: {
-                tension: tension,
-                friction: friction,
-                mass: mass,
-            },
-        },
+        to: { x: 360, y: 0 },
+        from: { x: 0, y: 0 },
     };
-
-    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,
-            },
-        },
+        to: { x: 180, y: 0 },
+        from: { x: 0, y: 0 },
     };
-
-    // 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 bounceConfig = {
+        to: { x: 0, y: 0 },
+        from: (() => {
+            const offset = infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET;
+            switch (dir) {
+                case PresEffectDirection.Left:  return { x: -offset, y:       0, };
+                case PresEffectDirection.Right: return { x:  offset, y:       0, };
+                case PresEffectDirection.Top:   return { x:       0, y: -offset, };
+                case PresEffectDirection.Bottom:return { x:       0, y:  offset, };
+                default:                        return { x:       0, y:       0, }; // no movement for center
+            }})(), // prettier-ignore
     };
-
     const rollConfig = {
-        ...getRollConfigFrom(),
-        to: {
-            opacity: 1,
-            x: 0,
-            y: 0,
-            config: {
-                tension: tension,
-                friction: friction,
-                mass: mass,
-            },
-        },
+        to: { x: 0, y: 0 },
+        from: (() => {
+            switch (dir) {
+                case PresEffectDirection.Left:   return { x: -100, y: -120, };
+                case PresEffectDirection.Right:  return { x:  100, y:  120, };
+                case PresEffectDirection.Top:    return { x: -100, y: -120, };
+                case PresEffectDirection.Bottom: return { x: -100, y: -120, };
+                default:                         return { x:    0, y:    0, };  // no movement for center
+            }})(), // prettier-ignore
     };
 
-    // Switch animation depending on slide effect
-    const startAnimation = () => {
-        api.stop();
-        let config: any = zoomConfig;
+    // prettier-ignore
+    const effectConfig = (() => {
         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 };
-        }
+            case PresEffect.Fade:       return fadeConfig;
+            case PresEffect.Bounce:     return bounceConfig;
+            case PresEffect.Rotate:     return rotateConfig;
+            case PresEffect.Flip:       return flipConfig;
+            case PresEffect.Roll:       return rollConfig;
+            case PresEffect.Lightspeed: return { from: {}, to: {} };
+            case PresEffect.Expand:     
+            default:                    return expandConfig;
+        } // prettier-ignore
+    })();
 
-        api.start(config);
-    };
-
-    const getRenderDoc = () => {
-        switch (presEffect) {
-            case PresEffect.Rotate:
-                return (
-                    <animated.div ref={ref} style={{ transform: to(springs.x, val => `rotate(${val}deg)`) }}>
-                        {children}
-                    </animated.div>
-                );
-            case PresEffect.Flip:
-                return (
-                    // Pass in doc dimensions
-                    <div className="flip-container" ref={ref}>
-                        {dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? (
-                            <>
-                                <animated.div
-                                    className="flip-side flip-back"
-                                    style={{
-                                        transform: to(springs.x, val => `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);',
-                                    }}
-                                />
-                                <animated.div
-                                    className="flip-side flip-front"
-                                    style={{ transform: to(springs.x, val => `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}>
-                                    {children}
-                                </animated.div>
-                            </>
-                        ) : (
-                            <>
-                                <animated.div
-                                    className="flip-side flip-back"
-                                    style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}
-                                />
-                                <animated.div
-                                    className="flip-side flip-front"
-                                    style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}>
-                                    {children}
-                                </animated.div>
-                            </>
-                        )}
-                    </div>
-                );
-            case PresEffect.Roll:
-                return (
-                    <animated.div ref={ref} style={{ opacity: springs.opacity, transform: to([springs.x, springs.y], (val, val2) => `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) }}>
-                        {children}
-                    </animated.div>
-                );
-            default:
-                return (
-                    <animated.div
-                        ref={ref}
-                        style={{
-                            ...springs,
-                        }}>
-                        {children}
-                    </animated.div>
-                );
-        }
-    };
-
-    useEffect(() => {
-        if (infinite || !inView) return;
-        setTimeout(() => {
-            startAnimation();
-        }, 100);
-    }, [inView]);
+    const [springs, api] = useSpring(
+        () => ({
+            to: { ...effectConfig.to, opacity: 1 },
+            from: { ...effectConfig.from, opacity: startOpacity ?? 1 },
+            config: { tension: springSettings.stiffness, friction: springSettings.damping, mass: springSettings.mass },
+            onStart: emptyFunction,
+            onRest: emptyFunction,
+        }),
+        [springSettings]
+    );
 
+    const [ref, inView] = useInView({
+        once: true,
+    });
     useEffect(() => {
-        if (infinite) {
-            startAnimation();
+        if (inView) {
+            api.start({ loop: infinite, delay: infinite ? 500 : 0 });
         }
-    }, [presEffect, tension, friction, mass]);
-
-    return <div>{getRenderDoc()}</div>;
+    }, [inView]);
+    const animatedDiv = (style: any) => (
+        <animated.div ref={ref} style={{ ...style, opacity: to(springs.opacity, val => `${val}`) }}>
+            {children}
+        </animated.div>
+    );
+    const [width, height] = [NumCast(doc?.width, DEFAULT_WIDTH), NumCast(doc?.height, DEFAULT_WIDTH)];
+    const flipAxis = dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? 'X' : 'Y';
+    const [rotateX, rotateY] = flipAxis === 'X' ? ['180deg', undefined] : [undefined, '180deg'];
+    switch (presEffect) {
+        case PresEffect.Flip:  return animatedDiv({ transform: to(springs.x, val => `perspective(600px) rotate${flipAxis}(${val}deg)`), width, height, rotateX, rotateY })
+        case PresEffect.Rotate:return animatedDiv({ transform: to(springs.x, val => `rotate(${val}deg)`) });
+        case PresEffect.Roll:  return animatedDiv({ transform: to([springs.x, springs.y], (val, val2) => `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) });
+        default:               return animatedDiv(springs);
+    } // prettier-ignore
 }
-- 
cgit v1.2.3-70-g09d2

