UNPKG

framer-motion

Version:

An open source and production-ready motion library for React on the web

465 lines (441 loc) • 12.5 kB
import { CSSProperties } from "react" import { MotionValue } from "../value" import { AnimationControls } from "../animation/animation-controls" import { Variants, Target, Transition, TargetAndTransition, Omit, MakeCustomValueType, } from "../types" import { GestureHandlers } from "../gestures" import { DraggableProps } from "../gestures/drag/types" import { LayoutProps } from "./features/layout/types" import { ResolvedValues } from "../render/types" import { VisualElementLifecycles } from "../render/utils/lifecycles" export type MotionStyleProp = string | number | MotionValue /** * Either a string, or array of strings, that reference variants defined via the `variants` prop. * @public */ export type VariantLabels = string | string[] export interface TransformProperties { x?: string | number y?: string | number z?: string | number translateX?: string | number translateY?: string | number translateZ?: string | number rotate?: string | number rotateX?: string | number rotateY?: string | number rotateZ?: string | number scale?: string | number scaleX?: string | number scaleY?: string | number scaleZ?: string | number skew?: string | number skewX?: string | number skewY?: string | number originX?: string | number originY?: string | number originZ?: string | number perspective?: string | number transformPerspective?: string | number } /** * @public */ export interface SVGPathProperties { pathLength?: number pathOffset?: number pathSpacing?: number } export interface CustomStyles { /** * Framer Library custom prop types. These are not actually supported in Motion - preferably * we'd have a way of external consumers injecting supported styles into this library. */ size?: string | number radius?: string | number shadow?: string image?: string } export type MakeMotion<T> = MakeCustomValueType< { [K in keyof T]: | T[K] | MotionValue<number> | MotionValue<string> | MotionValue<any> // A permissive type for Custom value types } > export type MotionCSS = MakeMotion< Omit<CSSProperties, "rotate" | "scale" | "perspective"> > /** * @public */ export type MotionTransform = MakeMotion<TransformProperties> /** * @public */ export type MotionStyle = MotionCSS & MotionTransform & MakeMotion<SVGPathProperties> & MakeCustomValueType<CustomStyles> export type OnUpdate = (v: Target) => void /** * @public */ export interface RelayoutInfo { delta: { x: number y: number width: number height: number } } /** * @public */ export type ResolveLayoutTransition = ( info: RelayoutInfo ) => Transition | boolean /** * @public */ export interface AnimationProps { /** * Values to animate to, variant label(s), or `AnimationControls`. * * @library * * ```jsx * // As values * <Frame animate={{ opacity: 1 }} /> * * // As variant * <Frame animate="visible" variants={variants} /> * * // Multiple variants * <Frame animate={["visible", "active"]} variants={variants} /> * * // AnimationControls * <Frame animate={animation} /> * ``` * * @motion * * ```jsx * // As values * <motion.div animate={{ opacity: 1 }} /> * * // As variant * <motion.div animate="visible" variants={variants} /> * * // Multiple variants * <motion.div animate={["visible", "active"]} variants={variants} /> * * // AnimationControls * <motion.div animate={animation} /> * ``` */ animate?: AnimationControls | TargetAndTransition | VariantLabels | boolean /** * A target to animate to when this component is removed from the tree. * * This component **must** be the first animatable child of an `AnimatePresence` to enable this exit animation. * * This limitation exists because React doesn't allow components to defer unmounting until after * an animation is complete. Once this limitation is fixed, the `AnimatePresence` component will be unnecessary. * * @library * * ```jsx * import { Frame, AnimatePresence } from 'framer' * * export function MyComponent(props) { * return ( * <AnimatePresence> * {props.isVisible && ( * <Frame * initial={{ opacity: 0 }} * animate={{ opacity: 1 }} * exit={{ opacity: 0 }} * /> * )} * </AnimatePresence> * ) * } * ``` * * @motion * * ```jsx * import { AnimatePresence, motion } from 'framer-motion' * * export const MyComponent = ({ isVisible }) => { * return ( * <AnimatePresence> * {isVisible && ( * <motion.div * initial={{ opacity: 0 }} * animate={{ opacity: 1 }} * exit={{ opacity: 0 }} * /> * )} * </AnimatePresence> * ) * } * ``` */ exit?: TargetAndTransition | VariantLabels /** * Variants allow you to define animation states and organise them by name. They allow * you to control animations throughout a component tree by switching a single `animate` prop. * * Using `transition` options like `delayChildren` and `staggerChildren`, you can orchestrate * when children animations play relative to their parent. * * @library * * After passing variants to one or more `Frame`'s `variants` prop, these variants * can be used in place of values on the `animate`, `initial`, `whileFocus`, `whileTap` and `whileHover` props. * * ```jsx * const variants = { * active: { * backgroundColor: "#f00" * }, * inactive: { * backgroundColor: "#fff", * transition: { duration: 2 } * } * } * * <Frame variants={variants} animate="active" /> * ``` * * @motion * * After passing variants to one or more `motion` component's `variants` prop, these variants * can be used in place of values on the `animate`, `initial`, `whileFocus`, `whileTap` and `whileHover` props. * * ```jsx * const variants = { * active: { * backgroundColor: "#f00" * }, * inactive: { * backgroundColor: "#fff", * transition: { duration: 2 } * } * } * * <motion.div variants={variants} animate="active" /> * ``` */ variants?: Variants /** * Default transition. If no `transition` is defined in `animate`, it will use the transition defined here. * * @library * * ```jsx * const spring = { * type: "spring", * damping: 10, * stiffness: 100 * } * * <Frame transition={spring} animate={{ scale: 1.2 }} /> * ``` * * @motion * * ```jsx * const spring = { * type: "spring", * damping: 10, * stiffness: 100 * } * * <motion.div transition={spring} animate={{ scale: 1.2 }} /> * ``` */ transition?: Transition } /** * @public */ export interface MotionAdvancedProps { /** * Custom data to use to resolve dynamic variants differently for each animating component. * * @library * * ```jsx * const variants = { * visible: (custom) => ({ * opacity: 1, * transition: { delay: custom * 0.2 } * }) * } * * <Frame custom={0} animate="visible" variants={variants} /> * <Frame custom={1} animate="visible" variants={variants} /> * <Frame custom={2} animate="visible" variants={variants} /> * ``` * * @motion * * ```jsx * const variants = { * visible: (custom) => ({ * opacity: 1, * transition: { delay: custom * 0.2 } * }) * } * * <motion.div custom={0} animate="visible" variants={variants} /> * <motion.div custom={1} animate="visible" variants={variants} /> * <motion.div custom={2} animate="visible" variants={variants} /> * ``` * * @public */ custom?: any /** * @public * Set to `false` to prevent inheriting variant changes from its parent. */ inherit?: boolean } /** * Props for `motion` components. * * @public */ export interface MotionProps extends AnimationProps, VisualElementLifecycles, GestureHandlers, DraggableProps, LayoutProps, MotionAdvancedProps { /** * Properties, variant label or array of variant labels to start in. * * Set to `false` to initialise with the values in `animate` (disabling the mount animation) * * @library * * ```jsx * // As values * <Frame initial={{ opacity: 1 }} /> * * // As variant * <Frame initial="visible" variants={variants} /> * * // Multiple variants * <Frame initial={["visible", "active"]} variants={variants} /> * * // As false (disable mount animation) * <Frame initial={false} animate={{ opacity: 0 }} /> * ``` * * @motion * * ```jsx * // As values * <motion.div initial={{ opacity: 1 }} /> * * // As variant * <motion.div initial="visible" variants={variants} /> * * // Multiple variants * <motion.div initial={["visible", "active"]} variants={variants} /> * * // As false (disable mount animation) * <motion.div initial={false} animate={{ opacity: 0 }} /> * ``` */ initial?: boolean | Target | VariantLabels /** * @library * * The React DOM `style` prop, useful for setting CSS properties that aren't explicitly exposed by `Frame` props. * * ```jsx * <Frame style={{ mixBlendMode: "difference" }} /> * ``` * * @motion * * The React DOM `style` prop, enhanced with support for `MotionValue`s and separate `transform` values. * * ```jsx * export const MyComponent = () => { * const x = useMotionValue(0) * * return <motion.div style={{ x, opacity: 1, scale: 0.5 }} /> * } * ``` */ style?: MotionStyle /** * By default, Framer Motion generates a `transform` property with a sensible transform order. `transformTemplate` * can be used to create a different order, or to append/preprend the automatically generated `transform` property. * * @library * * ```jsx * function transformTemplate({ x, rotate }) { * return `rotate(${rotate}deg) translateX(${x}px)` * } * * <Frame x={0} rotate={180} transformTemplate={transformTemplate} /> * ``` * * @motion * * ```jsx * <motion.div * style={{ x: 0, rotate: 180 }} * transformTemplate={ * ({ x, rotate }) => `rotate(${rotate}deg) translateX(${x}px)` * } * /> * ``` * * @param transform - The latest animated transform props. * @param generatedTransform - The transform string as automatically generated by Framer Motion * * @public */ transformTemplate?( transform: TransformProperties, generatedTransform: string ): string /** * This allows values to be transformed before being animated or set as styles. * * For instance, this allows custom values in Framer Library like `size` to be converted into `width` and `height`. * It also allows us a chance to take a value like `Color` and convert it to an animatable color string. * * A few structural typing changes need making before this can be a public property: * - Allow `Target` values to be appended by user-defined types (delete `CustomStyles` - does `size` throw a type error?) * - Extract `CustomValueType` as a separate user-defined type (delete `CustomValueType` and animate a `Color` - does this throw a type error?). * * @param values - * * @internal */ transformValues?<V extends ResolvedValues>(values: V): V } export type TransformTemplate = ( transform: TransformProperties, generatedTransform: string ) => string