Created
November 13, 2024 12:52
-
-
Save productdevbook/31fc135c0184e578ec9ec785d0c8aab1 to your computer and use it in GitHub Desktop.
Motion Test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { animate } from 'motion' | |
import type { AnimationPlaybackControls, ValueAnimationOptions } from 'motion/react' | |
import { | |
type VNode, | |
computed, | |
defineComponent, | |
h, | |
mergeProps, | |
reactive, | |
useAttrs, | |
useSlots, | |
} from 'vue' | |
export default defineComponent({ | |
name: 'Motion', | |
inheritAttrs: false, | |
props: { | |
as: { | |
type: String, | |
default: 'div', | |
}, | |
transition: { | |
type: Object, | |
required: false, | |
}, | |
animate: { | |
type: [Object, Array], | |
required: false, | |
}, | |
initial: { | |
type: [Object, Array], | |
required: false, | |
}, | |
}, | |
setup(props) { | |
const slots = useSlots() | |
const attrs = useAttrs() | |
const instances = reactive<{ [key: number]: any }>({}) | |
const propsConfig = computed(() => ({ | |
transition: { | |
...getDefaultTransition(props.animate, props.transition), | |
...props.transition, | |
}, | |
animate: { | |
...props.animate, | |
}, | |
initial: { | |
...props.initial, | |
}, | |
})) | |
function setNodeInstance(node: VNode, index: number, style: any) { | |
let animationInstance: AnimationPlaybackControls | null = null | |
node.props ??= {} | |
node.props.style ??= {} | |
node.props.style = { | |
...node.props.style, | |
...style, | |
willChange: 'transform', | |
transform: 'translateZ(0)', | |
} | |
node.props.onVnodeMounted = ({ el }) => { | |
animationInstance = animate(el, propsConfig.value.animate, propsConfig.value.transition) | |
instances[index] = animationInstance | |
} | |
node.props.onVnodeUnmounted = () => { | |
if (animationInstance) | |
animationInstance.stop() | |
} | |
node.props.onVnodeUpdated = ({ el }) => { | |
animationInstance = animate(el, propsConfig.value.animate, propsConfig.value.transition) | |
instances[index] = animationInstance | |
} | |
return node | |
} | |
return () => | |
setNodeInstance( | |
h( | |
props.as, | |
mergeProps({ style: propsConfig.value.initial }, attrs), | |
slots, | |
), | |
0, | |
attrs.style, | |
) | |
}, | |
}) | |
export const transformPropOrder = [ | |
'transformPerspective', | |
'x', | |
'y', | |
'z', | |
'translateX', | |
'translateY', | |
'translateZ', | |
'scale', | |
'scaleX', | |
'scaleY', | |
'rotate', | |
'rotateX', | |
'rotateY', | |
'rotateZ', | |
'skew', | |
'skewX', | |
'skewY', | |
] | |
export const transformProps = new Set(transformPropOrder) | |
const underDampedSpring: Partial<ValueAnimationOptions> = { | |
type: 'spring', | |
stiffness: 500, | |
damping: 25, | |
restSpeed: 10, | |
} | |
function criticallyDampedSpring(target: unknown): Partial<ValueAnimationOptions> { | |
return { | |
type: 'spring', | |
stiffness: 550, | |
damping: target === 0 ? 2 * Math.sqrt(550) : 30, | |
restSpeed: 10, | |
} | |
} | |
const keyframesTransition: Partial<ValueAnimationOptions> = { | |
type: 'keyframes', | |
duration: 0.8, | |
} | |
const ease: Partial<ValueAnimationOptions> = { | |
type: 'keyframes', | |
ease: [0.25, 0.1, 0.35, 1], | |
duration: 0.3, | |
} | |
function getDefaultTransition(valuesKey: any, options: any): any { | |
// Optimize getDefaultTransition function | |
if (options?.keyframes?.length > 2) { | |
return keyframesTransition | |
} | |
else if (valuesKey) { | |
let value: Partial<ValueAnimationOptions<number>> = {} | |
for (const key of Object.keys(valuesKey)) { | |
if (transformProps.has(key)) { | |
value = key.startsWith('scale') | |
? options?.keyframes?.length > 2 | |
? criticallyDampedSpring(options.keyframes[1]) | |
: underDampedSpring | |
: underDampedSpring | |
} | |
} | |
if (Object.keys(value).length > 0) | |
return value | |
} | |
return ease | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment