UNPKG

framer-motion

Version:

A simple and powerful React animation library

1,694 lines (1,677 loc) • 151 kB
/// <reference types="react" /> import * as React$1 from 'react'; import { RefObject, CSSProperties, SVGAttributes, ForwardRefExoticComponent, PropsWithoutRef, RefAttributes, ReactHTML, DetailedHTMLFactory, HTMLAttributes, useEffect } from 'react'; import { Easing as Easing$1, SpringOptions } from 'popmotion'; import { ScrollOptions, InViewOptions } from '@motionone/dom'; /** * @public */ declare type Subscriber<T> = (v: T) => void; /** * @public */ declare type PassiveEffect<T> = (v: T, safeSetter: (v: T) => void) => void; /** * `MotionValue` is used to track the state and velocity of motion values. * * @public */ declare class MotionValue<V = any> { /** * This will be replaced by the build step with the latest version number. * When MotionValues are provided to motion components, warn if versions are mixed. */ version: string; /** * Adds a function that will be notified when the `MotionValue` is updated. * * It returns a function that, when called, will cancel the subscription. * * When calling `onChange` inside a React component, it should be wrapped with the * `useEffect` hook. As it returns an unsubscribe function, this should be returned * from the `useEffect` function to ensure you don't add duplicate subscribers.. * * ```jsx * export const MyComponent = () => { * const x = useMotionValue(0) * const y = useMotionValue(0) * const opacity = useMotionValue(1) * * useEffect(() => { * function updateOpacity() { * const maxXY = Math.max(x.get(), y.get()) * const newOpacity = transform(maxXY, [0, 100], [1, 0]) * opacity.set(newOpacity) * } * * const unsubscribeX = x.onChange(updateOpacity) * const unsubscribeY = y.onChange(updateOpacity) * * return () => { * unsubscribeX() * unsubscribeY() * } * }, []) * * return <motion.div style={{ x }} /> * } * ``` * * @privateRemarks * * We could look into a `useOnChange` hook if the above lifecycle management proves confusing. * * ```jsx * useOnChange(x, () => {}) * ``` * * @param subscriber - A function that receives the latest value. * @returns A function that, when called, will cancel this subscription. * * @public */ onChange(subscription: Subscriber<V>): () => void; clearListeners(): void; /** * Sets the state of the `MotionValue`. * * @remarks * * ```jsx * const x = useMotionValue(0) * x.set(10) * ``` * * @param latest - Latest value to set. * @param render - Whether to notify render subscribers. Defaults to `true` * * @public */ set(v: V, render?: boolean): void; updateAndNotify: (v: V, render?: boolean) => void; /** * Returns the latest state of `MotionValue` * * @returns - The latest state of `MotionValue` * * @public */ get(): V; /** * @public */ getPrevious(): V; /** * Returns the latest velocity of `MotionValue` * * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical. * * @public */ getVelocity(): number; hasAnimated: boolean; /** * Stop the currently active animation. * * @public */ stop(): void; /** * Returns `true` if this value is currently animating. * * @public */ isAnimating(): boolean; private clearAnimation; /** * Destroy and clean up subscribers to this `MotionValue`. * * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually * created a `MotionValue` via the `motionValue` function. * * @public */ destroy(): void; } declare function motionValue<V>(init: V): MotionValue<V>; /** * @public */ declare type ControlsAnimationDefinition = string | string[] | TargetAndTransition | TargetResolver; /** * @public */ interface AnimationControls { /** * Starts an animation on all linked components. * * @remarks * * ```jsx * controls.start("variantLabel") * controls.start({ * x: 0, * transition: { duration: 1 } * }) * ``` * * @param definition - Properties or variant label to animate to * @param transition - Optional `transtion` to apply to a variant * @returns - A `Promise` that resolves when all animations have completed. * * @public */ start(definition: ControlsAnimationDefinition, transitionOverride?: Transition): Promise<any>; /** * Instantly set to a set of properties or a variant. * * ```jsx * // With properties * controls.set({ opacity: 0 }) * * // With variants * controls.set("hidden") * ``` * * @privateRemarks * We could perform a similar trick to `.start` where this can be called before mount * and we maintain a list of of pending actions that get applied on mount. But the * expectation of `set` is that it happens synchronously and this would be difficult * to do before any children have even attached themselves. It's also poor practise * and we should discourage render-synchronous `.start` calls rather than lean into this. * * @public */ set(definition: ControlsAnimationDefinition): void; /** * Stops animations on all linked components. * * ```jsx * controls.stop() * ``` * * @public */ stop(): void; mount(): () => void; } interface Point { x: number; y: number; } interface Axis { min: number; max: number; } interface Box { x: Axis; y: Axis; } interface BoundingBox { top: number; right: number; bottom: number; left: number; } interface AxisDelta { translate: number; scale: number; origin: number; originPoint: number; } interface Delta { x: AxisDelta; y: AxisDelta; } declare type TransformPoint = (point: Point) => Point; /** * Passed in to pan event handlers like `onPan` the `PanInfo` object contains * information about the current state of the tap gesture such as its * `point`, `delta`, `offset` and `velocity`. * * ```jsx * <motion.div onPan={(event, info) => { * console.log(info.point.x, info.point.y) * }} /> * ``` * * @public */ interface PanInfo { /** * Contains `x` and `y` values for the current pan position relative * to the device or page. * * ```jsx * function onPan(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onPan={onPan} /> * ``` * * @public */ point: Point; /** * Contains `x` and `y` values for the distance moved since * the last event. * * ```jsx * function onPan(event, info) { * console.log(info.delta.x, info.delta.y) * } * * <motion.div onPan={onPan} /> * ``` * * @public */ delta: Point; /** * Contains `x` and `y` values for the distance moved from * the first pan event. * * ```jsx * function onPan(event, info) { * console.log(info.offset.x, info.offset.y) * } * * <motion.div onPan={onPan} /> * ``` * * @public */ offset: Point; /** * Contains `x` and `y` values for the current velocity of the pointer, in px/ms. * * ```jsx * function onPan(event, info) { * console.log(info.velocity.x, info.velocity.y) * } * * <motion.div onPan={onPan} /> * ``` * * @public */ velocity: Point; } interface DragControlOptions { snapToCursor?: boolean; cursorProgress?: Point; } /** * Can manually trigger a drag gesture on one or more `drag`-enabled `motion` components. * * ```jsx * const dragControls = useDragControls() * * function startDrag(event) { * dragControls.start(event, { snapToCursor: true }) * } * * return ( * <> * <div onPointerDown={startDrag} /> * <motion.div drag="x" dragControls={dragControls} /> * </> * ) * ``` * * @public */ declare class DragControls { private componentControls; /** * Start a drag gesture on every `motion` component that has this set of drag controls * passed into it via the `dragControls` prop. * * ```jsx * dragControls.start(e, { * snapToCursor: true * }) * ``` * * @param event - PointerEvent * @param options - Options * * @public */ start(event: React$1.MouseEvent | React$1.TouchEvent | React$1.PointerEvent | MouseEvent | TouchEvent | PointerEvent, options?: DragControlOptions): void; } /** * Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop * and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we * might want to initiate that dragging from a different component than the draggable one. * * By creating a `dragControls` using the `useDragControls` hook, we can pass this into * the draggable component's `dragControls` prop. It exposes a `start` method * that can start dragging from pointer events on other components. * * ```jsx * const dragControls = useDragControls() * * function startDrag(event) { * dragControls.start(event, { snapToCursor: true }) * } * * return ( * <> * <div onPointerDown={startDrag} /> * <motion.div drag="x" dragControls={dragControls} /> * </> * ) * ``` * * @public */ declare function useDragControls(): DragControls; declare type DragElastic = boolean | number | Partial<BoundingBox>; /** * @public */ interface DragHandlers { /** * Callback function that fires when dragging starts. * * ```jsx * <motion.div * drag * onDragStart={ * (event, info) => console.log(info.point.x, info.point.y) * } * /> * ``` * * @public */ onDragStart?(event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo): void; /** * Callback function that fires when dragging ends. * * ```jsx * <motion.div * drag * onDragEnd={ * (event, info) => console.log(info.point.x, info.point.y) * } * /> * ``` * * @public */ onDragEnd?(event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo): void; /** * Callback function that fires when the component is dragged. * * ```jsx * <motion.div * drag * onDrag={ * (event, info) => console.log(info.point.x, info.point.y) * } * /> * ``` * * @public */ onDrag?(event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo): void; /** * Callback function that fires a drag direction is determined. * * ```jsx * <motion.div * drag * dragDirectionLock * onDirectionLock={axis => console.log(axis)} * /> * ``` * * @public */ onDirectionLock?(axis: "x" | "y"): void; /** * Callback function that fires when drag momentum/bounce transition finishes. * * ```jsx * <motion.div * drag * onDragTransitionEnd={() => console.log('Drag transition complete')} * /> * ``` * * @public */ onDragTransitionEnd?(): void; } /** * @public */ declare type InertiaOptions = Partial<Omit<Inertia, "velocity" | "type">>; /** * @public */ interface DraggableProps extends DragHandlers { /** * Enable dragging for this element. Set to `false` by default. * Set `true` to drag in both directions. * Set `"x"` or `"y"` to only drag in a specific direction. * * ```jsx * <motion.div drag="x" /> * ``` */ drag?: boolean | "x" | "y"; /** * Properties or variant label to animate to while the drag gesture is recognised. * * ```jsx * <motion.div whileDrag={{ scale: 1.2 }} /> * ``` */ whileDrag?: VariantLabels | TargetAndTransition; /** * If `true`, this will lock dragging to the initially-detected direction. Defaults to `false`. * * ```jsx * <motion.div drag dragDirectionLock /> * ``` */ dragDirectionLock?: boolean; /** * Allows drag gesture propagation to child components. Set to `false` by * default. * * ```jsx * <motion.div drag="x" dragPropagation /> * ``` */ dragPropagation?: boolean; /** * Applies constraints on the permitted draggable area. * * It can accept an object of optional `top`, `left`, `right`, and `bottom` values, measured in pixels. * This will define a distance the named edge of the draggable component. * * Alternatively, it can accept a `ref` to another component created with React's `useRef` hook. * This `ref` should be passed both to the draggable component's `dragConstraints` prop, and the `ref` * of the component you want to use as constraints. * * ```jsx * // In pixels * <motion.div * drag="x" * dragConstraints={{ left: 0, right: 300 }} * /> * * // As a ref to another component * const MyComponent = () => { * const constraintsRef = useRef(null) * * return ( * <motion.div ref={constraintsRef}> * <motion.div drag dragConstraints={constraintsRef} /> * </motion.div> * ) * } * ``` */ dragConstraints?: false | Partial<BoundingBox> | RefObject<Element>; /** * The degree of movement allowed outside constraints. 0 = no movement, 1 = * full movement. * * Set to `0.5` by default. Can also be set as `false` to disable movement. * * By passing an object of `top`/`right`/`bottom`/`left`, individual values can be set * per constraint. Any missing values will be set to `0`. * * ```jsx * <motion.div * drag * dragConstraints={{ left: 0, right: 300 }} * dragElastic={0.2} * /> * ``` */ dragElastic?: DragElastic; /** * Apply momentum from the pan gesture to the component when dragging * finishes. Set to `true` by default. * * ```jsx * <motion.div * drag * dragConstraints={{ left: 0, right: 300 }} * dragMomentum={false} * /> * ``` */ dragMomentum?: boolean; /** * Allows you to change dragging inertia parameters. * When releasing a draggable Frame, an animation with type `inertia` starts. The animation is based on your dragging velocity. This property allows you to customize it. * See {@link https://framer.com/api/animation/#inertia | Inertia} for all properties you can use. * * ```jsx * <motion.div * drag * dragTransition={{ bounceStiffness: 600, bounceDamping: 10 }} * /> * ``` */ dragTransition?: InertiaOptions; /** * Usually, dragging is initiated by pressing down on a component and moving it. For some * use-cases, for instance clicking at an arbitrary point on a video scrubber, we * might want to initiate dragging from a different component than the draggable one. * * By creating a `dragControls` using the `useDragControls` hook, we can pass this into * the draggable component's `dragControls` prop. It exposes a `start` method * that can start dragging from pointer events on other components. * * ```jsx * const dragControls = useDragControls() * * function startDrag(event) { * dragControls.start(event, { snapToCursor: true }) * } * * return ( * <> * <div onPointerDown={startDrag} /> * <motion.div drag="x" dragControls={dragControls} /> * </> * ) * ``` */ dragControls?: DragControls; /** * If true, element will snap back to its origin when dragging ends. * * Enabling this is the equivalent of setting all `dragConstraints` axes to `0` * with `dragElastic={1}`, but when used together `dragConstraints` can define * a wider draggable area and `dragSnapToOrigin` will ensure the element * animates back to its origin on release. */ dragSnapToOrigin?: boolean; /** * By default, if `drag` is defined on a component then an event listener will be attached * to automatically initiate dragging when a user presses down on it. * * By setting `dragListener` to `false`, this event listener will not be created. * * ```jsx * const dragControls = useDragControls() * * function startDrag(event) { * dragControls.start(event, { snapToCursor: true }) * } * * return ( * <> * <div onPointerDown={startDrag} /> * <motion.div * drag="x" * dragControls={dragControls} * dragListener={false} * /> * </> * ) * ``` */ dragListener?: boolean; /** * If `dragConstraints` is set to a React ref, this callback will call with the measured drag constraints. * * @public */ onMeasureDragConstraints?: (constraints: BoundingBox) => BoundingBox | void; /** * Usually, dragging uses the layout project engine, and applies transforms to the underlying VisualElement. * Passing MotionValues as _dragX and _dragY instead applies drag updates to these motion values. * This allows you to manually control how updates from a drag gesture on an element is applied. * * @public */ _dragX?: MotionValue<number>; /** * Usually, dragging uses the layout project engine, and applies transforms to the underlying VisualElement. * Passing MotionValues as _dragX and _dragY instead applies drag updates to these motion values. * This allows you to manually control how updates from a drag gesture on an element is applied. * * @public */ _dragY?: MotionValue<number>; } /** * @public */ interface LayoutProps { /** * If `true`, this component will automatically animate to its new position when * its layout changes. * * ```jsx * <motion.div layout /> * ``` * * This will perform a layout animation using performant transforms. Part of this technique * involved animating an element's scale. This can introduce visual distortions on children, * `boxShadow` and `borderRadius`. * * To correct distortion on immediate children, add `layout` to those too. * * `boxShadow` and `borderRadius` will automatically be corrected if they are already being * animated on this component. Otherwise, set them directly via the `initial` prop. * * If `layout` is set to `"position"`, the size of the component will change instantly and * only its position will animate. If `layout` is set to `"size"`, the position of the * component will change instantly but its size will animate. * * If `layout` is set to `"size"`, the position of the component will change instantly and * only its size will animate. * * If `layout` is set to `"preserve-aspect"`, the component will animate size & position if * the aspect ratio remains the same between renders, and just position if the ratio changes. * * @public */ layout?: boolean | "position" | "size" | "preserve-aspect"; /** * Enable shared layout transitions between different components with the same `layoutId`. * * When a component with a layoutId is removed from the React tree, and then * added elsewhere, it will visually animate from the previous component's bounding box * and its latest animated values. * * ```jsx * {items.map(item => ( * <motion.li layout> * {item.name} * {item.isSelected && <motion.div layoutId="underline" />} * </motion.li> * ))} * ``` * * If the previous component remains in the tree it will crossfade with the new component. * * @public */ layoutId?: string; /** * A callback that will fire when a layout animation on this component starts. * * @public */ onLayoutAnimationStart?(): void; /** * A callback that will fire when a layout animation on this component completes. * * @public */ onLayoutAnimationComplete?(): void; /** * @public */ layoutDependency?: any; /** * Wether a projection node should measure its scroll when it or its descendants update their layout. * * @public */ layoutScroll?: boolean; } declare enum AnimationType { Animate = "animate", Hover = "whileHover", Tap = "whileTap", Drag = "whileDrag", Focus = "whileFocus", InView = "whileInView", Exit = "exit" } declare type AnimationDefinition = VariantLabels | TargetAndTransition | TargetResolver; declare type AnimationOptions$1 = { delay?: number; transitionOverride?: Transition; custom?: any; type?: AnimationType; }; declare function animateVisualElement(visualElement: VisualElement, definition: AnimationDefinition, options?: AnimationOptions$1): Promise<void>; declare type LayoutMeasureListener = (layout: Box, prevLayout?: Box) => void; declare type BeforeLayoutMeasureListener = () => void; declare type LayoutUpdateListener = (layout: Axis, prevLayout: Axis) => void; declare type UpdateListener = (latest: ResolvedValues) => void; declare type AnimationStartListener = (definition: AnimationDefinition) => void; declare type AnimationCompleteListener = (definition: AnimationDefinition) => void; declare type LayoutAnimationStartListener = () => void; declare type LayoutAnimationCompleteListener = () => void; declare type SetAxisTargetListener = () => void; declare type RenderListener = () => void; interface LayoutLifecycles { onBeforeLayoutMeasure?(box: Box): void; onLayoutMeasure?(box: Box, prevBox: Box): void; } interface AnimationLifecycles { /** * Callback with latest motion values, fired max once per frame. * * ```jsx * function onUpdate(latest) { * console.log(latest.x, latest.opacity) * } * * <motion.div animate={{ x: 100, opacity: 0 }} onUpdate={onUpdate} /> * ``` */ onUpdate?(latest: ResolvedValues): void; /** * Callback when animation defined in `animate` begins. * * The provided callback will be called with the triggering animation definition. * If this is a variant, it'll be the variant name, and if a target object * then it'll be the target object. * * This way, it's possible to figure out which animation has started. * * ```jsx * function onStart() { * console.log("Animation started") * } * * <motion.div animate={{ x: 100 }} onAnimationStart={onStart} /> * ``` */ onAnimationStart?(definition: AnimationDefinition): void; /** * Callback when animation defined in `animate` is complete. * * The provided callback will be called with the triggering animation definition. * If this is a variant, it'll be the variant name, and if a target object * then it'll be the target object. * * This way, it's possible to figure out which animation has completed. * * ```jsx * function onComplete() { * console.log("Animation completed") * } * * <motion.div * animate={{ x: 100 }} * onAnimationComplete={definition => { * console.log('Completed animating', definition) * }} * /> * ``` */ onAnimationComplete?(definition: AnimationDefinition): void; } declare type VisualElementLifecycles = LayoutLifecycles & AnimationLifecycles; interface LifecycleManager { onLayoutMeasure: (callback: LayoutMeasureListener) => () => void; notifyLayoutMeasure: LayoutMeasureListener; onBeforeLayoutMeasure: (callback: BeforeLayoutMeasureListener) => () => void; notifyBeforeLayoutMeasure: BeforeLayoutMeasureListener; onLayoutUpdate: (callback: LayoutUpdateListener) => () => void; notifyLayoutUpdate: LayoutUpdateListener; onUpdate: (callback: UpdateListener) => () => void; notifyUpdate: UpdateListener; onAnimationStart: (callback: AnimationStartListener) => () => void; notifyAnimationStart: AnimationStartListener; onAnimationComplete: (callback: AnimationCompleteListener) => () => void; notifyAnimationComplete: AnimationCompleteListener; onLayoutAnimationStart: (callback: LayoutAnimationStartListener) => () => void; notifyLayoutAnimationStart: LayoutAnimationStartListener; onLayoutAnimationComplete: (callback: LayoutAnimationCompleteListener) => () => void; notifyLayoutAnimationComplete: LayoutAnimationCompleteListener; onSetAxisTarget: (callback: SetAxisTargetListener) => () => void; notifySetAxisTarget: SetAxisTargetListener; onRender: (callback: RenderListener) => () => void; notifyRender: RenderListener; onUnmount: (callback: () => void) => () => void; notifyUnmount: () => void; clearAllListeners: () => void; updatePropListeners: (props: MotionProps) => void; } /** @public */ interface EventInfo { point: Point; } /** * @public */ interface FocusHandlers { /** * Properties or variant label to animate to while the focus gesture is recognised. * * ```jsx * <motion.input whileFocus={{ scale: 1.2 }} /> * ``` */ whileFocus?: VariantLabels | TargetAndTransition; } /** * Passed in to tap event handlers like `onTap` the `TapInfo` object contains * information about the tap gesture such as it‘s location. * * ```jsx * function onTap(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onTap={onTap} /> * ``` * * @public */ interface TapInfo { /** * Contains `x` and `y` values for the tap gesture relative to the * device or page. * * ```jsx * function onTapStart(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onTapStart={onTapStart} /> * ``` * * @public */ point: Point; } /** * @public */ interface TapHandlers { /** * Callback when the tap gesture successfully ends on this element. * * ```jsx * function onTap(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onTap={onTap} /> * ``` * * @param event - The originating pointer event. * @param info - An {@link TapInfo} object containing `x` and `y` values for the `point` relative to the device or page. */ onTap?(event: MouseEvent | TouchEvent | PointerEvent, info: TapInfo): void; /** * Callback when the tap gesture starts on this element. * * ```jsx * function onTapStart(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onTapStart={onTapStart} /> * ``` * * @param event - The originating pointer event. * @param info - An {@link TapInfo} object containing `x` and `y` values for the `point` relative to the device or page. */ onTapStart?(event: MouseEvent | TouchEvent | PointerEvent, info: TapInfo): void; /** * Callback when the tap gesture ends outside this element. * * ```jsx * function onTapCancel(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onTapCancel={onTapCancel} /> * ``` * * @param event - The originating pointer event. * @param info - An {@link TapInfo} object containing `x` and `y` values for the `point` relative to the device or page. */ onTapCancel?(event: MouseEvent | TouchEvent | PointerEvent, info: TapInfo): void; /** * Properties or variant label to animate to while the component is pressed. * * ```jsx * <motion.div whileTap={{ scale: 0.8 }} /> * ``` */ whileTap?: VariantLabels | TargetAndTransition; } /** * @public */ interface PanHandlers { /** * Callback function that fires when the pan gesture is recognised on this element. * * **Note:** For pan gestures to work correctly with touch input, the element needs * touch scrolling to be disabled on either x/y or both axis with the * [touch-action](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action) CSS rule. * * ```jsx * function onPan(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onPan={onPan} /> * ``` * * @param event - The originating pointer event. * @param info - A {@link PanInfo} object containing `x` and `y` values for: * * - `point`: Relative to the device or page. * - `delta`: Distance moved since the last event. * - `offset`: Offset from the original pan event. * - `velocity`: Current velocity of the pointer. */ onPan?(event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo): void; /** * Callback function that fires when the pan gesture begins on this element. * * ```jsx * function onPanStart(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onPanStart={onPanStart} /> * ``` * * @param event - The originating pointer event. * @param info - A {@link PanInfo} object containing `x`/`y` values for: * * - `point`: Relative to the device or page. * - `delta`: Distance moved since the last event. * - `offset`: Offset from the original pan event. * - `velocity`: Current velocity of the pointer. */ onPanStart?(event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo): void; /** * Callback function that fires when we begin detecting a pan gesture. This * is analogous to `onMouseStart` or `onTouchStart`. * * ```jsx * function onPanSessionStart(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onPanSessionStart={onPanSessionStart} /> * ``` * * @param event - The originating pointer event. * @param info - An {@link EventInfo} object containing `x`/`y` values for: * * - `point`: Relative to the device or page. */ onPanSessionStart?(event: MouseEvent | TouchEvent | PointerEvent, info: EventInfo): void; /** * Callback function that fires when the pan gesture ends on this element. * * ```jsx * function onPanEnd(event, info) { * console.log(info.point.x, info.point.y) * } * * <motion.div onPanEnd={onPanEnd} /> * ``` * * @param event - The originating pointer event. * @param info - A {@link PanInfo} object containing `x`/`y` values for: * * - `point`: Relative to the device or page. * - `delta`: Distance moved since the last event. * - `offset`: Offset from the original pan event. * - `velocity`: Current velocity of the pointer. */ onPanEnd?(event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo): void; } /** * @public */ interface HoverHandlers { /** * Properties or variant label to animate to while the hover gesture is recognised. * * ```jsx * <motion.div whileHover={{ scale: 1.2 }} /> * ``` */ whileHover?: VariantLabels | TargetAndTransition; /** * Callback function that fires when pointer starts hovering over the component. * * ```jsx * <motion.div onHoverStart={() => console.log('Hover starts')} /> * ``` */ onHoverStart?(event: MouseEvent, info: EventInfo): void; /** * Callback function that fires when pointer stops hovering over the component. * * ```jsx * <motion.div onHoverEnd={() => console.log("Hover ends")} /> * ``` */ onHoverEnd?(event: MouseEvent, info: EventInfo): void; } declare type ViewportEventHandler = (entry: IntersectionObserverEntry | null) => void; interface ViewportOptions { root?: RefObject<Element>; once?: boolean; margin?: string; amount?: "some" | "all" | number; fallback?: boolean; } interface ViewportProps { whileInView?: VariantLabels | TargetAndTransition; onViewportEnter?: ViewportEventHandler; onViewportLeave?: ViewportEventHandler; viewport?: ViewportOptions; } /** * Either a string, or array of strings, that reference variants defined via the `variants` prop. * @public */ declare type VariantLabels = string | string[]; 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 */ interface SVGPathProperties { pathLength?: number; pathOffset?: number; pathSpacing?: number; } 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; } declare type MakeMotion<T> = MakeCustomValueType<{ [K in keyof T]: T[K] | MotionValue<number> | MotionValue<string> | MotionValue<any>; }>; declare type MotionCSS = MakeMotion<Omit$1<CSSProperties, "rotate" | "scale" | "perspective">>; /** * @public */ declare type MotionTransform = MakeMotion<TransformProperties>; /** * @public */ declare type MotionStyle = MotionCSS & MotionTransform & MakeMotion<SVGPathProperties> & MakeCustomValueType<CustomStyles>; /** * @public */ interface RelayoutInfo { delta: { x: number; y: number; width: number; height: number; }; } /** * @public */ declare type ResolveLayoutTransition = (info: RelayoutInfo) => Transition | boolean; /** * @public */ interface AnimationProps { /** * 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) * * ```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; /** * Values to animate to, variant label(s), or `AnimationControls`. * * ```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. * * ```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. * * 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. * ```jsx * const spring = { * type: "spring", * damping: 10, * stiffness: 100 * } * * <motion.div transition={spring} animate={{ scale: 1.2 }} /> * ``` */ transition?: Transition; } /** * @public */ interface MotionAdvancedProps { /** * Custom data to use to resolve dynamic variants differently for each animating component. * * ```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 */ interface MotionProps extends AnimationProps, VisualElementLifecycles, PanHandlers, TapHandlers, HoverHandlers, FocusHandlers, ViewportProps, DraggableProps, LayoutProps, MotionAdvancedProps { /** * * 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. * * ```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; /** * Internal. * * 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 - */ transformValues?<V extends ResolvedValues>(values: V): V; } /** * @public */ declare type ResolvedKeyframesTarget = [null, ...number[]] | number[] | [null, ...string[]] | string[]; /** * @public */ declare type KeyframesTarget = ResolvedKeyframesTarget | [null, ...CustomValueType[]] | CustomValueType[]; /** * @public */ declare type ResolvedSingleTarget = string | number; /** * @public */ declare type SingleTarget = ResolvedSingleTarget | CustomValueType; /** * @public */ declare type ResolvedValueTarget = ResolvedSingleTarget | ResolvedKeyframesTarget; /** * @public */ declare type ValueTarget = SingleTarget | KeyframesTarget; /** * A function that accepts a progress value between `0` and `1` and returns a * new one. * * ```jsx * <motion.div * animate={{ opacity: 0 }} * transition={{ * duration: 1, * ease: progress => progress * progress * }} * /> * ``` * * @public */ declare type EasingFunction = (v: number) => number; /** * The easing function to use. Set as one of: * * - The name of an in-built easing function. * - An array of four numbers to define a cubic bezier curve. * - An easing function, that accepts and returns a progress value between `0` and `1`. * * @public */ declare type Easing = [number, number, number, number] | "linear" | "easeIn" | "easeOut" | "easeInOut" | "circIn" | "circOut" | "circInOut" | "backIn" | "backOut" | "backInOut" | "anticipate" | EasingFunction; /** * Options for orchestrating the timing of animations. * * @public */ interface Orchestration { /** * Delay the animation by this duration (in seconds). Defaults to `0`. * * @remarks * ```javascript * const transition = { * delay: 0.2 * } * ``` * * @public */ delay?: number; /** * Describes the relationship between the transition and its children. Set * to `false` by default. * * @remarks * When using variants, the transition can be scheduled in relation to its * children with either `"beforeChildren"` to finish this transition before * starting children transitions, `"afterChildren"` to finish children * transitions before starting this transition. * * ```jsx * const list = { * hidden: { * opacity: 0, * transition: { when: "afterChildren" } * } * } * * const item = { * hidden: { * opacity: 0, * transition: { duration: 2 } * } * } * * return ( * <motion.ul variants={list} animate="hidden"> * <motion.li variants={item} /> * <motion.li variants={item} /> * </motion.ul> * ) * ``` * * @public */ when?: false | "beforeChildren" | "afterChildren" | string; /** * When using variants, children animations will start after this duration * (in seconds). You can add the `transition` property to both the `Frame` and the `variant` directly. Adding it to the `variant` generally offers more flexibility, as it allows you to customize the delay per visual state. * * ```jsx * const container = { * hidden: { opacity: 0 }, * show: { * opacity: 1, * transition: { * delayChildren: 0.5 * } * } * } * * const item = { * hidden: { opacity: 0 }, * show: { opacity: 1 } * } * * return ( * <motion.ul * variants={container} * initial="hidden" * animate="show" * > * <motion.li variants={item} /> * <motion.li variants={item} /> * </motion.ul> * ) * ``` * * @public */ delayChildren?: number; /** * When using variants, animations of child components can be staggered by this * duration (in seconds). * * For instance, if `staggerChildren` is `0.01`, the first child will be * delayed by `0` seconds, the second by `0.01`, the third by `0.02` and so * on. * * The calculated stagger delay will be added to `delayChildren`. * * ```jsx * const container = { * hidden: { opacity: 0 }, * show: { * opacity: 1, * transition: { * staggerChildren: 0.5 * } * } * } * * const item = { * hidden: { opacity: 0 }, * show: { opacity: 1 } * } * * return ( * <motion.ol * variants={container} * initial="hidden" * animate="show" * > * <motion.li variants={item} /> * <motion.li variants={item} /> * </motion.ol> * ) * ``` * * @public */ staggerChildren?: number; /** * The direction in which to stagger children. * * A value of `1` staggers from the first to the last while `-1` * staggers from the last to the first. * * ```jsx * const container = { * hidden: { opacity: 0 }, * show: { * opacity: 1, * transition: { * delayChildren: 0.5, * staggerDirection: -1 * } * } * } * * const item = { * hidden: { opacity: 0 }, * show: { opacity: 1 } * } * * return ( * <motion.ul * variants={container} * initial="hidden" * animate="show" * > * <motion.li variants={item} size={50} /> * <motion.li variants={item} size={50} /> * </motion.ul> * ) * ``` * * @public */ staggerDirection?: number; } interface Repeat { /** * The number of times to repeat the transition. Set to `Infinity` for perpetual repeating. * * Without setting `repeatType`, this will loop the animation. * * ```jsx * <motion.div * animate={{ rotate: 180 }} * transition={{ repeat: Infinity, duration: 2 }} * /> * ``` * * @public */ repeat?: number; /** * How to repeat the animation. This can be either: * * "loop": Repeats the animation from the start * * "reverse": Alternates between forward and backwards playback * * "mirror": Switches `from` and `to` alternately * * ```jsx * <motion.div * animate={{ rotate: 180 }} * transition={{ * repeat: 1, * repeatType: "reverse", * duration: 2 * }} * /> * ``` * * @public */ repeatType?: "loop" | "reverse" | "mirror"; /** * When repeating an animation, `repeatDelay` will set the * duration of the time to wait, in seconds, between each repetition. * * ```jsx * <motion.div * animate={{ rotate: 180 }} * transition={{ repeat: Infinity, repeatDelay: 1 }} * /> * ``` * * @public */ repeatDelay?: number; } /** * An animation that animates between two or more values over a specific duration of time. * This is the default animation for non-physical values like `color` and `opacity`. * * @public */ interface Tween extends Repeat { /** * Set `type` to `"tween"` to use a duration-based tween animation. * If any non-orchestration `transition` values are set without a `type` property, * this is used as the default animation. * * ```jsx * <motion.path * animate={{ pathLength: 1 }} * transition={{ duration: 2, type: "tween" }} * /> * ``` * * @public */ type?: "tween"; /** * The duration of the tween animation. Set to `0.3` by default, 0r `0.8` if animating a series of keyframes. * * ```jsx * const variants = { * visible: { * opacity: 1, * transition: { duration: 2 } * } * } * ``` * * @public */ duration?: number; /** * The easing function to use. Set as one of the below. * * - The name of an existing easing function. * * - An array of four numbers to define a cubic bezier curve. * * - An easing function, that accepts and returns a value `0-1`. * * If the animating value is set as an array of multiple values for a keyframes * animation, `ease` can be set as an array of easing functions to set different easings between * each of those values. * * * ```jsx * <motion.div * animate={{ opacity: 0 }} * transition={{ ease: [0.17, 0.67, 0.83, 0.67] }} * /> * ``` * * @public */ ease?: Easing | Easing[];