מדריכים · 03
רכיבי Animated רנדרו אלמנטים רגילים שנעים ליעד, מגיבים למחוות ויוצאים בחן.
Animated.<tag> Animated.div, Animated.button, Animated.svg וכל תגית HTML או SVG אחרת מרנדרים את האלמנט הרגיל בלי עטיפה. ה־style שלהם מקבל ערכים, וטרנספורמציות יכולות להיות מערכים כמו ב־React Native.
תנועה סופית של transform ו־opacity על האלמנטים האלה, כולל קפיצים, יכולה להתנגן בדפדפן.
JavaScript כבוי. הקוד שלמטה הוא הדוגמה המלאה.
App.jsx import { useState } from 'react' ;
import { Animated } from '@kkwaenggwari/animated' ;
import './styles.css' ;
const plans = ['Research' , 'Build' , 'Launch' ];
export default function App ({ stiffness = 260 , damping = 22 } ) {
const [selected, setSelected] = useState ('Build' );
return (
<div className ="stage" >
{plans.map((plan, index) => (
<Animated.button
key ={plan}
type ="button"
className ={plan === selected ? 'plan active ' : 'plan '}
onClick ={() => setSelected(plan)}
seed={{ opacity: 0, transform: [{ translateY: 24 }] }}
pose={{
opacity: 1,
transform: [
{ translateY: plan === selected ? -12 : 0 },
{ scale: plan === selected ? 1.06 : 1 },
],
}}
tempo={{ spring: { stiffness, damping } }}
>
<strong > {plan}</strong >
<span > Step {index + 1}</span >
</Animated.button >
))}
</div >
);
}styles.css .stage {
display : flex;
flex-wrap : wrap;
align-items : flex-end;
gap : 16px ;
min-height : 220px ;
padding : 40px 28px 28px ;
}
.plan {
display : grid;
gap : 6px ;
width : 150px ;
padding : 20px ;
border : 1px solid #e4e6ef ;
border-radius : 18px ;
background : #fff ;
color : #16181d ;
font : inherit;
text-align : start;
cursor : pointer;
}
.plan span {
color : #5b6070 ;
font-size : 14px ;
}
.plan .active {
border-color : #2854ff ;
background : #2854ff ;
color : #fff ;
}
.plan .active span {
color : #d6e0ff ;
}seed, pose, poses ו־tempo seed הוא הפריים הראשון, pose היעד הנוכחי (אובייקט או שם של רשומה ב־poses), ו־tempo הוא timing או קפיץ. שינוי של tempo לבד לא מנגן מחדש יעד שלא השתנה.
onRest מופעל כשהאלמנט מגיע.
Card.jsx העתקת הקוד <Animated .article
seed={{ opacity : 0 , transform : [{ translateY : 16 }] }}
pose={selected ? 'raised' : 'rest' }
poses={{
rest : { opacity : 1 , transform : [{ translateY : 0 }, { scale : 1 }] },
raised : { opacity : 1 , transform : [{ translateY : -8 }, { scale : 1.04 }] },
}}
tempo={{ spring : { stiffness : 300 , damping : 26 } }}
onRest={() => console .log ('arrived' )}
/>;תגובה למחוות respond ממפה מחוות ליעדים זמניים: hover, focus, focusWithin, press, longPress, drag, inView ועוד. כשתגובה מסתיימת, האלמנט חוזר ל־pose שלו מכל מקום שבו הוא נמצא.
onResponse מדווח על תחילת כל תגובה ועל סופה, ו־respond={{ press: {} }} צופה במחווה בלי לשנות שום דבר חזותית.
JavaScript כבוי. הקוד שלמטה הוא הדוגמה המלאה.
App.jsx import { Animated } from '@kkwaenggwari/animated' ;
import './styles.css' ;
const actions = ['Share' , 'Save' , 'Export' ];
export default function App ({ lift = 8 , scale = 1.06 } ) {
return (
<div className ="stage" >
{actions.map((action) => (
<Animated.button
key ={action}
type ="button"
className ="action"
pose ={{ transform: [{ translateY: 0 }, { scale: 1 }] }}
respond ={{
hover: { transform: [{ translateY: -lift }, { scale }] },
focus: { transform: [{ translateY: -lift }, { scale }] },
press: { transform: [{ translateY: 0 }, { scale: 0.94 }] },
}}
tempo ={{ spring: { stiffness: 420 , damping: 24 } }}
>
{action}
</Animated.button >
))}
</div >
);
}styles.css .stage {
display : flex;
flex-wrap : wrap;
align-items : center;
justify-content : center;
gap : 16px ;
min-height : 200px ;
padding : 32px ;
}
.action {
min-width : 120px ;
min-height : 56px ;
padding : 0 24px ;
border : 0 ;
border-radius : 16px ;
background : #16181d ;
color : #fff ;
font : inherit;
font-weight : 650 ;
cursor : pointer;
}
.action :focus-visible {
outline : 3px solid #5c7cff ;
outline-offset : 3px ;
}לשתף ברירות מחדל עם Animated.Scope Animated.Scope מעביר שם pose, tempo וברירות מחדל של אנימציה לאלמנטים של Animated שבתוכו.
Menu.jsx העתקת הקוד <Animated .Scope tempo={{ spring : { stiffness : 380 , damping : 30 } }}>
<Animated.li pose ={{ opacity: 1 }} />
<Animated.li pose ={{ opacity: 1 }} />
</Animated .Scope >;הרכיבים שלכם Animated.wrap(Component) — createAnimatedComponent ב־React Native — גורם לרכיב שמעביר ref ומתפרש כאלמנט DOM אחד לקבל את אותם props.
Link.jsx העתקת הקוד import { forwardRef } from 'react' ;
import { Animated } from '@kkwaenggwari/animated' ;
const Link = forwardRef ((props, ref ) => <a ref ={ref} {...props } /> );
const AnimatedLink = Animated .wrap (Link );
<AnimatedLink href ="/pricing" respond ={{ hover: { transform: [{ translateX: 4 }] } }} /> ;