AnimateSlide
한쪽 변에서 미끄러져 들어오는 효과입니다. 기본 이동 거리가 요소 자신의 크기이므로 정확히 화면 밖에서 출발하며, 있어서는 안 될 자리에 반쯤 그려지는 일이 없습니다.
tsx
import { AnimateSlide } from 'neba';
<div className="overflow-hidden">
<AnimateSlide from="left">
<Alert color="success" title="초대를 보냈습니다" />
</AnimateSlide>
</div>;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| from공통 | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | 어느 변에서 들어오는지. NebaSide가 어디서나 그렇듯 물리적입니다 |
| distance | number | string | '100%' | 이동 거리, CSS 길이 또는 픽셀 수. 100%는 자기 자신의 크기입니다 |
| fade | boolean | true | 이동하면서 함께 페이드인합니다 |
| stagger공통 | number | 0 | 한 자식 뒤 다음 자식이 시작하기까지의 간격(ms). 0이면 상자 자체가 재생되고, 그보다 크면 효과가 자식 하나하나에게 넘어갑니다 |
| durationStep공통 | number | 0 | 자식마다 재생 시간에 더해지는 값(ms). 음수면 뒤로 갈수록 빨라지며, 0 아래로는 내려가지 않습니다 |
| reverse공통 | boolean | false | 마지막 자식부터 실행합니다. 순서만 뒤집히고 각 자식은 그대로 재생됩니다 |
| mode공통 | 'in' | 'out' | 'in' | 들어오는지 나가는지. out은 같은 애니메이션을 거꾸로 재생하고 그 자리에서 멈춥니다 |
| duration공통 | number | 380 | 한 번 재생되는 시간(ms) |
| delay공통 | number | 0 | 시작 전 대기(ms) |
| easing | string | — | CSS 이징 곡선. 기본값은 라이브러리의 곡선 |
| repeat공통 | number | 'infinite' | 1 | 반복 횟수 |
| alternate공통 | boolean | false | 한 번 걸러 거꾸로 재생합니다. 반복이 처음으로 튀지 않고 되돌아옵니다 |
| trigger공통 | 'mount' | 'visible' | 'hover' | 'manual' | 'mount' | 무엇이 재생을 시작하는지. visible은 화면에 들어올 때, hover는 포인터가 올라올 때(포커스 포함), manual은 play가 정합니다 |
| play | boolean | — | trigger가 manual일 때 재생합니다. false → true 될 때마다 처음부터 다시 시작합니다 |
| once공통 | boolean | true | trigger가 visible일 때 처음 한 번만 재생할지. 끄면 화면에 들어올 때마다 다시 재생됩니다 |
| threshold공통 | number | 0.2 | trigger가 visible일 때 화면에 얼마나 들어와야 하는지, 0에서 1 사이 |
| paused공통 | boolean | false | 있는 자리에 붙들어 둡니다 |
| render | useRender.RenderProp | — | div 대신 다른 요소로 렌더링합니다 (render={<aside />}). Base UI의 render prop 그대로 |
| children | ReactNode | — | 미끄러져 들어오는 것 |
나머지 <div> 속성은 모두 루트로 전달됩니다. 모든 Animate*가 공유하는 설정은 Prop 규약에 있습니다.
예시
from
어느 변에서 들어오는지 정하며, top, right, bottom, left를 받습니다. 라이브러리의 다른 곳에서 NebaSide가 그렇듯 논리적이 아니라 물리적입니다. 위에서 내려오는 패널은 어떤 쓰기 방향에서도 위에서 내려옵니다.
overflow: hidden인 상자 안에 넣으면 그 상자의 변 뒤에서 패널이 나타나는 효과가 됩니다.
tsx
import { useState } from 'react';
import { AnimateSlide, Box, Button, Typography } from 'neba';
const EDGES = ['top', 'right', 'bottom', 'left'] as const;
export default function AnimateSlideEdges() {
const [run, setRun] = useState(0);
return (
<div className="flex flex-col items-center gap-4">
<Button size="sm" variant="outline" onClick={() => setRun((count) => count + 1)}>
Play again
</Button>
<div className="flex flex-wrap items-center justify-center gap-3">
{EDGES.map((edge) => (
<div key={edge} className="overflow-hidden">
<AnimateSlide key={`${edge}-${run}`} from={edge} duration={700}>
<Box size="sm">
<Typography level="caption">from {edge}</Typography>
</Box>
</AnimateSlide>
</div>
))}
</div>
</div>
);
}distance
CSS 길이 또는 픽셀 수입니다. 기본값 '100%'는 요소 자신의 너비 또는 높이입니다. 짧은 거리는 등장이 아니라 살짝 미는 정도이고, 그런 것을 목록 전체에 하나씩 걸고 싶다면 AnimateAppear를 쓰세요.
tsx
import { AnimateSlide, Chip } from 'neba';
/* A short distance is a nudge; the default is the element's own size, which
starts it exactly out of frame. */
export default function AnimateSlideDistance() {
return (
<div className="flex items-center gap-3">
<AnimateSlide distance={8} duration={1200} repeat="infinite" alternate fade={false}>
<Chip>8px</Chip>
</AnimateSlide>
<AnimateSlide distance="4rem" duration={1200} repeat="infinite" alternate>
<Chip color="info">4rem</Chip>
</AnimateSlide>
</div>
);
}mode
out은 왔던 길로 되돌려 보내고 화면 밖에서 멈춥니다.
tsx
<AnimateSlide mode="out" from="right">
<Toolbar>…</Toolbar>
</AnimateSlide>stagger
stagger, durationStep, reverse는 상자 대신 자식 하나하나에게 효과를 차례로 넘깁니다. 동작은 AnimateFade와 같고, 그쪽 페이지에 자세히 적혀 있습니다.
접근성
- 축소된 모션 설정에서는 애니메이션이 통째로 꺼지고 내용은 제자리에 그냥 있습니다.
- 요소는
translate로 움직이므로 재생되는 동안 페이지의 레이아웃이 다시 계산되지 않고, 아래의 어떤 것도 밀려나지 않습니다.