import * as React from 'react'; import Transition from '../Transition'; import type {TransitionEffectType} from '../Transition'; import DummyBox from './common/DummyBox'; import Stage from './common/Stage'; import {useIsomorphicLayoutEffect} from '../../utils/useIsomorphicLayoutEffect'; import {useTransformationState} from './common/useTransformationState'; export const CurvedMovement = () => { const [expanded, setExpanded] = React.useState(false); const [effects, setEffects] = React.useState< Record >({ xMove: null, yMove: null, scale: null, }); const elementRef = React.useRef(null); const containerRef = React.useRef(null); const transformation = useTransformationState({ elementRef, containerRef, updateKey: expanded, }); const prevTransformation = React.useRef(); useIsomorphicLayoutEffect(() => { if ( transformation.diffTop === 0 || transformation === prevTransformation.current ) { return; } prevTransformation.current = transformation; const origin = 'left top'; const duration = 240; /** * https://tobiasahlin.com/blog/curved-path-animations-in-css/ * The time difference between axes curves the trajectory of motion. */ const differenceFactor = 0.4; const xMoveDuration = expanded ? duration * (1 - differenceFactor) : duration * (1 + differenceFactor); setEffects({ xMove: { initial: { transform: { translateX: -transformation.diffLeft, }, }, animate: { transform: { translateX: 0, origin, duration: xMoveDuration, }, }, }, yMove: { initial: { transform: { translateY: -transformation.diffTop, }, }, animate: { transform: { translateY: 0, origin, duration, }, }, }, scale: { initial: { transform: { scale: 1 - transformation.diffScaleX, }, }, animate: { transform: { scale: 1, origin, duration, }, }, }, }); }, [expanded, transformation]); return (
setExpanded(b => !b)} color="blue" />
); }; // @ts-ignore TS7006 const getBoxStyle = expanded => { if (!expanded) { return { position: 'absolute', right: 16, bottom: 16, } as const; } }; CurvedMovement.parameters = { layout: 'centered', };