Skip to content

Commit d7555b5

Browse files
committed
feat: animation list
1 parent dadb8b7 commit d7555b5

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { useEffect, useMemo, useState } from 'react'
2+
3+
import { AnimatePresence, motion } from 'motion/react'
4+
import clsx from 'clsx'
5+
6+
const AnimatedListItem = ({ children }) => {
7+
const animations = {
8+
initial: { scale: 0, opacity: 0 },
9+
animate: { scale: 1, opacity: 1, originY: 0 },
10+
exit: { scale: 0, opacity: 0 },
11+
transition: { type: 'spring', stiffness: 350, damping: 40 },
12+
}
13+
14+
return (
15+
<motion.div {...animations} layout className="mx-auto w-full">
16+
{children}
17+
</motion.div>
18+
)
19+
}
20+
21+
const AnimatedList = React.memo(({ children, className, delay = 1000, ...props }) => {
22+
const [index, setIndex] = useState(0)
23+
const childrenArray = useMemo(() => React.Children.toArray(children), [children])
24+
25+
useEffect(() => {
26+
if (index < childrenArray.length - 1) {
27+
const timeout = setTimeout(() => {
28+
setIndex((prevIndex) => (prevIndex + 1) % childrenArray.length)
29+
}, delay)
30+
31+
return () => clearTimeout(timeout)
32+
}
33+
}, [index, delay, childrenArray.length])
34+
35+
const itemsToShow = useMemo(() => {
36+
const result = childrenArray.slice(0, index + 1).reverse()
37+
return result
38+
}, [index, childrenArray])
39+
40+
return (
41+
<div className={clsx(`flex flex-col items-center gap-4`, className)} {...props}>
42+
<AnimatePresence>
43+
{itemsToShow.map((item) => (
44+
<AnimatedListItem key={item.key}>{item}</AnimatedListItem>
45+
))}
46+
</AnimatePresence>
47+
</div>
48+
)
49+
})
50+
51+
export default AnimatedList

src/pages/demo/index.jsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import SongPng from '@assets/images/song.png'
1515
import XuePng from '@assets/images/xue.png'
1616

1717
import { Command, Cannabis, Beer, Mail } from 'lucide-react'
18+
import ScriptView from '@stateless/ScriptView'
19+
import AnimatedList from '@stateless/AnimatedList'
1820

1921
import styles from './index.module.less'
20-
import ScriptView from '@stateless/ScriptView'
2122

2223
const companies = [SpringPng, HePng, SongPng, XuePng]
2324
const columns = [
@@ -99,6 +100,21 @@ const ProDemo = () => {
99100
return (
100101
<FixTabPanel>
101102
<ScriptView showMultiplePackageOptions={true} codeLanguage="shell" commandMap={customCommandMap} />
103+
<section style={{ height: 240, overflow: 'hidden', margin: 20 }}>
104+
<AnimatedList>
105+
{Array.from({ length: 10 }, () => {
106+
id: Math.random()
107+
})
108+
.flat()
109+
.map((item, index) => (
110+
<div className="flex flex-col items-center justify-center gap-4">
111+
<div className="flex items-center justify-center gap-4">
112+
<div className="h-16 w-100 rounded-full bg-gradient-to-br from-purple-500 to-blue-500" />
113+
</div>
114+
</div>
115+
))}
116+
</AnimatedList>
117+
</section>
102118
<StarBack />
103119
<StickyCard cards={[...Array.from({ length: 4 }, () => ({ id: Math.random() }))]} />
104120
<div className="relative w-full overflow-hidden bg-[#0a192f]">

0 commit comments

Comments
 (0)