framer-motion
Version:
An open source and production-ready motion library for React on the web
70 lines (64 loc) • 1.65 kB
text/typescript
import { useState, useRef } from "react"
import { wrap } from "popmotion"
type Cycle = (i?: number) => void
type CycleState<T> = [T, Cycle]
/**
* Cycles through a series of visual properties. Can be used to toggle between or cycle through animations. It works similar to `useState` in React. It is provided an initial array of possible states, and returns an array of two arguments.
*
* @library
*
* ```jsx
* import * as React from "react"
* import { Frame, useCycle } from "framer"
*
* export function MyComponent() {
* const [x, cycleX] = useCycle(0, 50, 100)
*
* return (
* <Frame
* animate={{ x: x }}
* onTap={() => cycleX()}
* />
* )
* }
* ```
*
* @motion
*
* An index value can be passed to the returned `cycle` function to cycle to a specific index.
*
* ```jsx
* import * as React from "react"
* import { motion, useCycle } from "framer-motion"
*
* export const MyComponent = () => {
* const [x, cycleX] = useCycle(0, 50, 100)
*
* return (
* <motion.div
* animate={{ x: x }}
* onTap={() => cycleX()}
* />
* )
* }
* ```
*
* @param items - items to cycle through
* @returns [currentState, cycleState]
*
* @public
*/
export function useCycle<T>(...items: T[]): CycleState<T> {
const index = useRef(0)
const [item, setItem] = useState(items[index.current])
return [
item,
(next?: number) => {
index.current =
typeof next !== "number"
? wrap(0, items.length, index.current + 1)
: next
setItem(items[index.current])
},
]
}