Motion
Motion
は、framer-motion
にYamada UIのスタイルシステムを拡張した便利なコンポーネントです。
インポート
import { Motion } from "@yamada-ui/react"
使い方
Motion
コンポーネントは、内部的にFramer Motionを使用しています。さらに詳しいコンポーネントの機能を知りたい場合は、こちらをご覧ください。
initial
・animate
・exit
にスタイルを設定することで、要素にアニメーションを実装できます。また、transition
に所要時間や遅延時間を設定することもできます。
initial
: 要素の初期値のスタイルオブジェクトです。animate
:initial
から変化(アニメーション)させたいスタイルオブジェクトです。exit
: 要素がDOMツリー
上から削除されたときに変化(アニメーション)させたいスタイルオブジェクトです。transition
: 所要時間や遅延時間を設定するオブジェクトです。
initial
・animate
・exit
・transition
で使われるスタイルオブジェクトは、Yamada UIのStyle props
ではありません。スタイルオブジェクトのプロパティは、Framer Motionのドキュメントをご覧ください。
編集可能な例
<Center p="lg"> <Motion initial={{ x: -100 }} animate={{ x: 100 }} transition={{ duration: 2, ease: "easeInOut", repeat: Infinity, }} p="md" rounded="md" bg="primary" color="white" > Look me! </Motion> </Center>
AnimatePresence
を使う
Reactでは、要素がDOMツリー
から削除されるとアニメーションは維持されません。AnimatePresence
コンポーネントでラッピングすることで、アニメーションが終了するまで要素はDOMツリー
上で維持されます。
編集可能な例
const [isVisible, { toggle }] = useBoolean() return ( <> <Button onClick={toggle}>Click me!</Button> <Center h="3xs" gap="md"> <AnimatePresence> {isVisible ? ( <Motion initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 1 }} bg="primary" color="white" p="md" rounded="md" > Enabled "AnimatePresence" </Motion> ) : null} </AnimatePresence> {isVisible ? ( <Motion initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 1 }} bg="secondary" color="white" p="md" rounded="md" > Disabled "AnimatePresence" </Motion> ) : null} </Center> </> )
useAnimationFrame
を使う
useAnimationFrame
は、要素のアニメーションフレームごとに1回コールバックを実行します。コールバックは、コールバックが最初に呼び出されてからの合計時間と最後のアニメーションフレームからの合計時間を取得することができます。
編集可能な例
const containerRef = useRef<HTMLDivElement>(null) useAnimationFrame((time, delta) => { const rotate = Math.sin(time / 10000) * 200 const y = (1 + Math.sin(time / 1000)) * -50 containerRef.current.style.transform = `translateY(${y}px) rotateX(${rotate}deg) rotateY(${rotate}deg)` }) const sides = useMemo( () => [ { transform: "rotateY(0deg) translateZ(60px)", bg: "red.500" }, { transform: "rotateY(90deg) translateZ(60px)", bg: "orange.500" }, { transform: "rotateY(180deg) translateZ(60px)", bg: "pink.500" }, { transform: "rotateY(-90deg) translateZ(60px)", bg: "purple.500" }, { transform: "rotateX(90deg) translateZ(60px);", bg: "blue.500" }, { transform: "rotateX(-90deg) translateZ(60px)", bg: "green.500" }, ], [], ) return ( <Center h="md"> <Box css={{ perspective: "800px" }} w="120px" h="120px"> <Box ref={containerRef} position="relative" w="120px" h="120px" transformStyle="preserve-3d" > {sides.map(({ transform, bg }) => ( <Box key={bg.split(".")[0]} position="absolute" w="full" h="full" bg={bg} opacity="0.6" transform={transform} /> ))} </Box> </Box> </Center> )
キーフレーム
スタイルオブジェクトのプロパティに配列を渡すことで、キーフレームを設定することができます。各キーフレームは、アニメーション全体で均等な間隔で配置されます。transition
にtimes
を設定すると間隔をオーバーライドすることができます。
編集可能な例
<Center h="md"> <Motion animate={{ scale: [1, 2, 2, 1, 1], rotate: [0, 0, 180, 180, 0], borderRadius: ["0%", "0%", "50%", "50%", "0%"], }} transition={{ duration: 2, ease: "easeInOut", times: [0, 0.2, 0.5, 0.8, 1], repeat: Infinity, repeatDelay: 1, }} w="3xs" h="3xs" bg="primary" /> </Center>
アニメーションをもっと知りたい場合は、こちらをご覧ください。
ジェスチャー
ホバー・クリック・タップ・フォーカスを検出し、アニメーションを実装することができます。
ホバー
ホバーのジェスチャは、ポインタが要素上に移動したか離れたかを検出します。
onMouseEnter
とonMouseLeave
との違いは、実際のマウスイベントの結果としてのみ発火することが保証されています。
whileHover
: 要素がホバーされたときに発火するアニメーションです。onHoverStart
: ポインタが要素上に移動したときに発火するコールバック関数です。onHoverEnd
: ポインタが要素上から離れたときに発火するコールバック関数です。
編集可能な例
<Center p="lg"> <Motion as="button" whileHover={{ scale: 1.1 }} onHoverStart={(ev) => console.log("Hover starts")} onHoverEnd={(ev) => console.log("Hover ends")} p="md" rounded="md" bg="primary" color="white" > Hover me! </Motion> </Center>
ホバーのアニメーションをもっと知りたい場合は、こちらをご覧ください。
クリック・タップ
クリック・タップのジェスチャは、主ポインタ(左クリックやタッチなど)が同じ要素を押し下げか、放したかを検出します。
whileTap
: 要素がクリック・タップされたときに発火するアニメーションです。onTap
: 要素上でクリック・タップが正常に終了したときに発火するコールバック関数です。onTapStart
: 要素上でクリック・タップが開始されたときに発火するコールバック関数です。onTapCancel
: クリック・タップがキャンセルされた(要素外で放した)ときに発火するコールバック関数です。
編集可能な例
<Center p="lg"> <Motion as="button" whileTap={{ scale: 1.1 }} onTap={(ev, { point }) => console.log("Tap ends", "x:", point.x, "y:", point.y) } onTapStart={(ev, { point }) => console.log("Tap starts", "x:", point.x, "y:", point.y) } onTapCancel={(ev, { point }) => console.log("Tap cancels", "x:", point.x, "y:", point.y) } p="md" rounded="md" bg="primary" color="white" > Click me! </Motion> </Center>
クリック・タップのアニメーションをもっと知りたい場合は、こちらをご覧ください。
フォーカス
フォーカスのジェスチャは、CSS
のセレクターであるfocus-visible
と同じルールに従って、要素がフォーカスをされたかを検出します。
編集可能な例
<Center p="lg"> <Motion as="button" whileFocus={{ scale: 1.1 }} p="md" rounded="md" bg="primary" color="white" > Focus me! </Motion> </Center>
フォーカスのアニメーションをもっと知りたい場合は、こちらをご覧ください。
ドラッグ
ポインタの移動を検出し、要素を追従させます。
要素がドラッグを有効にする場合は、drag
をtrue
にするか、x
またはy
を渡します。x
またはy
を渡した場合、x軸
またはy軸
のみ追従します。
onDrag
: ドラッグ中に発火するコールバック関数です。onDragStart
: ドラッグが開始されたときに発火するコールバック関数です。onDragEnd
: ドラッグが終了したときに発火するコールバック関数です。
編集可能な例
<Center h="md" gap="md"> <Motion drag onDrag={(ev, { point }) => console.log("Drag", "x:", point.x, "y:", point.y) } onDragStart={(ev, { point }) => console.log("Drag starts", "x:", point.x, "y:", point.y) } onDragEnd={(ev, { point }) => console.log("Drag ends", "x:", point.x, "y:", point.y) } p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="primary" color="white" > Drag me! </Motion> <Motion drag="x" p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="secondary" color="white" > Only X </Motion> <Motion drag="y" p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="warning" color="white" > Only Y </Motion> </Center>
可能領域を制約する
dragConstraints
にtop
・right
・bottom
・left
ごとに値(ピクセル単位)を設定したオブジェクトか、ref
を渡すことでドラッグの可能領域を制約することができます。
編集可能な例
const containerRef = useRef<HTMLDivElement>(null) return ( <Center ref={containerRef} h="md" gap="md"> <Motion drag dragConstraints={containerRef} p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="primary" color="white" > Drag me! </Motion> <Motion drag dragConstraints={{ top: 0, right: 100, bottom: 100, left: 0, }} p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="secondary" color="white" > Only right & bottom </Motion> </Center> )
弾力と勢い
dragElastic
にtrue
・false
・数値
またはtop
・right
・bottom
・left
ごとに数値を設定したオブジェクトを渡すことで、制約の外側で許可された動きの程度を設定できます。0
が動きなし、1
が完全に動きます。デフォルトは0.5
が設定されています。
編集可能な例
const containerRef = useRef<HTMLDivElement>(null) return ( <Center ref={containerRef} h="md" p="md" gap="md"> <Motion drag dragConstraints={containerRef} dragElastic={0} p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="primary" color="white" > Drag me! </Motion> </Center> )
dragMomentum
にtrue
またはfalse
を渡すことで、パンのジェスチャーの勢いを要素に適応します。デフォルトは、true
が設定されています。
編集可能な例
const containerRef = useRef<HTMLDivElement>(null) return ( <Center ref={containerRef} h="md" p="md" gap="md"> <Motion drag dragConstraints={containerRef} dragMomentum={false} p="md" cursor="grab" _active={{ cursor: "grabbing" }} rounded="md" bg="primary" color="white" > Drag me! </Motion> </Center> )
ドラッグのアニメーションをもっと知りたい場合は、こちらをご覧ください。
スクロール
要素がビューポートに出入りしたことを検出し、アニメーションを実装することができます。
whileInView
: 要素がビューポートに入ったときに発火するアニメーションです。viewport
: ビューポートの検出方法を設定するオブジェクトです。once
:true
の場合、要素がビューポートに入った1回だけアニメーションが発火します。root
:ref
を渡すことで、指定された要素のビューポートが仕様されます。指定された要素がない場合は、ウィンドウのビューポートが指定されます。margin
: 要素がビューポートに入ったかどうかを検出するときにビューポートに追加するマージンです。デフォルトでは"0px"
です。CSS
のmargin
のように記述("0px -20px 0px 100px"
)します。amount
:"some"
・"all"
・数値を渡すことでビューポートと交差する必要がある要素の高さを設定します。デフォルトは、"some"
です。
onViewportEnter
: 要素がビューポートに入ったときに発火するコールバック関数です。onViewportLeave
: 要素がビューポートに離れたときに発火するコールバック関数です。
編集可能な例
const containerRef = useRef<HTMLDivElement>(null) return ( <> <Text>Please scroll</Text> <Box ref={containerRef} h="md" p="md" overflowY="auto"> <HStack mt="24rem" justifyContent="center"> <Motion initial={{ x: -100 }} whileInView={{ x: 0 }} viewport={{ root: containerRef }} transition={{ duration: 1 }} onViewportEnter={(entry) => console.log("Scroll entires", entry)} onViewportLeave={(entry) => console.log("Scroll leaves", entry)} p="md" rounded="md" bg="primary" color="white" > You found me! </Motion> <Motion initial={{ x: 100 }} whileInView={{ x: 0 }} viewport={{ once: true, root: containerRef }} transition={{ duration: 1 }} onViewportEnter={(entry) => console.log("Scroll entires", entry)} onViewportLeave={(entry) => console.log("Scroll leaves", entry)} p="md" rounded="md" bg="secondary" color="white" > Once me! </Motion> </HStack> </Box> </> )
useScroll
を使う
useScroll
は、4つのインスタンスを返します。そのインスタンスを使うことで、スクロールに合わせたアニメーションを実装することができます。
scrollX
: ウィンドウのオフセット間のスクロール(x軸
)情報のインスタンス。scrollY
: ウィンドウのオフセット間のスクロール(x軸
)情報のインスタンス。scrollXProgress
: 引数で指定された要素のオフセット間のスクロール(x軸
)情報のインスタンス。scrollYProgress
: 引数で指定された要素のオフセット間のスクロール(y軸
)情報のインスタンス。
編集可能な例
const containerRef = useRef<HTMLDivElement>(null) const { scrollYProgress } = useScroll({ container: containerRef }) const scale = useTransform(scrollYProgress, [0, 1], [0.2, 2]) return ( <Box ref={containerRef} position="relative" h="md" overflowY="auto"> <Box h="9xl"> <Box w="2xs" h="2xs" position="sticky" top="50%" left="50%" transform="translate(-50%, -50%)" > <Motion style={{ scale }} w="full" h="full" overflow="hidden" bg={["blackAlpha.200", "whiteAlpha.200"]} rounded="3xl" > <Motion style={{ scaleY: scrollYProgress }} w="inherit" h="inherit" bg="primary" transformOrigin="50% 100%" /> </Motion> </Box> </Box> </Box> )
スクロールのアニメーションをもっと知りたい場合は、こちらをご覧ください。
グローバルなコンフィグ
プロジェクト全体でMotion
コンポーネントに共通の設定を付与したい場合は、UIProvider
のconfig
に設定します。
import { UIProvider, extendConfig } from "@yamada-ui/react"const customConfig = extendConfig({motion: {config: {transition: { duration: 2 },},},})const App = () => {return (<UIProvider config={customConfig}><YourApplication /></UIProvider>)}
コンフィグをカスタマイズしたい場合は、こちらををご覧ください。
GitHubでこのページを編集する