概要
趣味でローディングアニメーションを作成したのですが、使わなくなったので、こちらにて供養したいと思います。
Requirement
- Framer Motion
- Chakra UI
Framer Motion x Chakra UI を使うためのコンポーネントの作成
↑を参考に、以下のようなコンポーネントをつくります。
motion-box.tsx
import { motion, HTMLMotionProps } from 'framer-motion'
import { chakra, HTMLChakraProps } from '@chakra-ui/react'
type Merge<P, T> = Omit<P, keyof T> & T
type MotionBoxProps = Merge<HTMLChakraProps<'div'>, HTMLMotionProps<'div'>>
export const MotionBox: React.FC<MotionBoxProps> = motion(chakra.div)
もしくは、
上記の motion-box については公式のようなコンポーネントの作り方でもOK。
(私は好みで前者の方をつかいました)
ローディングアニメーション
loading-modal.tsx
import { MotionBox } from './motion-box'
import {
Modal,
Box,
ModalOverlay,
useBreakpointValue
} from '@chakra-ui/react'
const LoadingCircle = ({ animateScale }: {animateScale: Array<number>}) => {
return (
<MotionBox
width={'30px'}
height={'30px'}
borderRadius={'50%'}
mr={6}
ml={-3}
bg={'white'}
animate={{scale: animateScale}}
transition={{
duration: 1.5,
ease: "linear",
repeat: Infinity,
repeatType: "reverse",
}}
/>
)
}
export const LoadingModal = ({ isOpen, onClose }: { isOpen: boolean, onClose: () => void}) => {
const isPc = useBreakpointValue({base: false, md: true})
return (
<>
<Modal isOpen={isOpen} onClose={onClose} scrollBehavior={'inside'} size={'xl'}>
<Box position={'relative'}>
<ModalOverlay>
<Box
display={'flex'}
position={'absolute'}
zIndex={10000} // ModalOverlayが 1300 程度
top={'50%'}
left={isPc ? '50%' : '40vw'}
>
<LoadingCircle
animateScale={
[2, 1, 1]
}
/>
<LoadingCircle
animateScale={
[1, 2, 1]
}
/>
<LoadingCircle
animateScale={
[1, 1, 2]
}
/>
</Box>
</ModalOverlay>
</Box>
</Modal>
</>
)
}
使い方
Chakra UI の useDisclosure()
を使って、簡単に実装できます。
.tsx
import { useDisclosure } from '@chakra-ui/react'
export SampleComponent () => {
const { isOpen, onOpen, onClose } = useDisclosure()
// 例えばページの遷移ならそれ依存配列に入れる
useEffect(()=>{
onClose()
}, [某])
// 何かしらをトリガーにしてアニメーションを表示
const onClick = () => {
...
onOpen()
}
return (
<>
...
<LoadingModal isOpen={isOpen} onClose={onClose} />
</>
)
}