react-gsap-aos 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +385 -0
- package/README.md +1 -381
- package/README.zh-TW.md +7 -5
- package/dist/client.d.mts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +50 -68
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +50 -68
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
package/README.en.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# react-gsap-aos
|
|
2
|
+
|
|
3
|
+
English | [中文文檔](README.zh-TW.md)
|
|
4
|
+
|
|
5
|
+
A lightweight GSAP + ScrollTrigger integration with an AOS-like API, specifically designed for React and Next.js applications.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/react-gsap-aos)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
[Live Demo](https://react-gsap-aos-nextjs.vercel.app)
|
|
11
|
+
|
|
12
|
+
## What is react-gsap-aos?
|
|
13
|
+
|
|
14
|
+
`react-gsap-aos` bridges the gap between GSAP's powerful animation capabilities and the simplicity of AOS (Animate On Scroll). It provides:
|
|
15
|
+
|
|
16
|
+
- **Familiar API**: If you've used AOS, you already know how to use this
|
|
17
|
+
- **GSAP Power**: Built on GSAP + ScrollTrigger for smooth, performant animations
|
|
18
|
+
- **React-First**: Designed specifically for React and Next.js with proper SSR support
|
|
19
|
+
- **TypeScript**: Full type safety for animations, easings, and anchor placements
|
|
20
|
+
- **Automatic Cleanup**: Properly manages animation lifecycle with React's component lifecycle
|
|
21
|
+
|
|
22
|
+
### Problem It Solves
|
|
23
|
+
|
|
24
|
+
While AOS is great for vanilla JavaScript, integrating it with React can be problematic:
|
|
25
|
+
|
|
26
|
+
- Manual initialization and cleanup required
|
|
27
|
+
- Not SSR-friendly
|
|
28
|
+
- Limited TypeScript support
|
|
29
|
+
- Difficult to use with dynamic content
|
|
30
|
+
|
|
31
|
+
`react-gsap-aos` by React solution that automatically handles DOM mutations, component lifecycle, and SSR scenarios.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- 🎬 Scroll-triggered animations powered by GSAP + ScrollTrigger
|
|
36
|
+
- 🎯 AOS-like API with `data-aos` attributes
|
|
37
|
+
- ⚛️ Built for React / Next.js with SSR support
|
|
38
|
+
- 🔄 Automatic animation management with DOM mutations
|
|
39
|
+
- 📦 Multiple parallel scopes without interference
|
|
40
|
+
- 🎨 34 animation presets (fade, slide, flip, zoom variants)
|
|
41
|
+
- 🎭 17 easing options from GSAP
|
|
42
|
+
- 📍 9 anchor placement options for precise triggering
|
|
43
|
+
- 🧹 Automatic cleanup on component unmount
|
|
44
|
+
- 💪 Full TypeScript support
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install react-gsap-aos gsap @gsap/react
|
|
50
|
+
# or
|
|
51
|
+
yarn add react-gsap-aos gsap @gsap/react
|
|
52
|
+
# or
|
|
53
|
+
pnpm add react-gsap-aos gsap @gsap/react
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Peer Dependencies
|
|
57
|
+
|
|
58
|
+
- `react` >= 17
|
|
59
|
+
- `gsap` ^3.12.5
|
|
60
|
+
- `@gsap/react` ^2.1.2
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { AOSProvider } from "react-gsap-aos/client";
|
|
66
|
+
|
|
67
|
+
export default function Demo() {
|
|
68
|
+
return (
|
|
69
|
+
<AOSProvider className="overflow-hidden">
|
|
70
|
+
<div data-aos-container>
|
|
71
|
+
<div data-aos="fade-up" data-aos-offset="200">
|
|
72
|
+
Hello AOS
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</AOSProvider>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
### Setting up AOSProvider
|
|
83
|
+
|
|
84
|
+
Wrap your animated content with `AOSProvider`. All child elements with `data-aos` attributes will be automatically animated.
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { AOSProvider } from "react-gsap-aos/client";
|
|
88
|
+
|
|
89
|
+
export default function Demo() {
|
|
90
|
+
return (
|
|
91
|
+
<AOSProvider className="overflow-hidden">
|
|
92
|
+
{/* Your animated content */}
|
|
93
|
+
</AOSProvider>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> The `overflow-hidden` class prevents elements from overflowing during their initial animation state.
|
|
99
|
+
|
|
100
|
+
⚠️ **Important**: Do not nest `AOSProvider` components, as this will cause duplicate listeners and animations.
|
|
101
|
+
|
|
102
|
+
### Configuring Animations with Data Attributes
|
|
103
|
+
|
|
104
|
+
Use `data-aos-*` attributes to configure animation behavior:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<div
|
|
108
|
+
data-aos="fade-up"
|
|
109
|
+
data-aos-offset={120}
|
|
110
|
+
data-aos-delay={0}
|
|
111
|
+
data-aos-duration={400}
|
|
112
|
+
data-aos-easing="ease-out-cubic"
|
|
113
|
+
data-aos-mirror={false}
|
|
114
|
+
data-aos-once={false}
|
|
115
|
+
data-aos-anchor-placement="top-bottom"
|
|
116
|
+
>
|
|
117
|
+
Animated content
|
|
118
|
+
</div>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Using toAOSProps Helper
|
|
122
|
+
|
|
123
|
+
For better TypeScript support and validation, use the `toAOSProps` helper:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { toAOSProps } from "react-gsap-aos";
|
|
127
|
+
|
|
128
|
+
<div
|
|
129
|
+
{...toAOSProps({
|
|
130
|
+
animation: "fade-up",
|
|
131
|
+
offset: 120,
|
|
132
|
+
delay: 0,
|
|
133
|
+
duration: 400,
|
|
134
|
+
easing: "power2.out",
|
|
135
|
+
once: false,
|
|
136
|
+
mirror: false,
|
|
137
|
+
anchorPlacement: "top-bottom",
|
|
138
|
+
})}
|
|
139
|
+
>
|
|
140
|
+
Animated content
|
|
141
|
+
</div>;
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Container Positioning with data-aos-container
|
|
145
|
+
|
|
146
|
+
To ensure accurate ScrollTrigger calculations, mark parent containers with `data-aos-container`:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<AOSProvider className="overflow-hidden">
|
|
150
|
+
{/* ✅ Correct: Container specified */}
|
|
151
|
+
<div data-aos-container>
|
|
152
|
+
<div data-aos="fade-up" data-aos-offset="200">
|
|
153
|
+
Hello AOS
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
{/* ❌ Incorrect: May cause offset issues */}
|
|
158
|
+
<div data-aos="fade-up" data-aos-offset="200">
|
|
159
|
+
Hello AOS
|
|
160
|
+
</div>
|
|
161
|
+
</AOSProvider>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Nested data-aos-container usage is **not recommended**:
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
<div data-aos-container>
|
|
168
|
+
<div data-aos="fade-up">Parent animation</div>
|
|
169
|
+
|
|
170
|
+
<div data-aos-container>
|
|
171
|
+
<div data-aos="zoom-in">Nested animation</div>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Nested containers increase the complexity of animation initialization and ScrollTrigger refresh timing. While animations will still register, users need to manually call `ScrollTrigger.refresh()` at the appropriate time.
|
|
177
|
+
|
|
178
|
+
## API Reference
|
|
179
|
+
|
|
180
|
+
### AOSProvider
|
|
181
|
+
|
|
182
|
+
A wrapper component that provides animation scope for its children.
|
|
183
|
+
|
|
184
|
+
**Props:**
|
|
185
|
+
|
|
186
|
+
| Prop | Type | Default | Description |
|
|
187
|
+
| ----------- | --------------------------- | ----------- | ------------------------------------------ |
|
|
188
|
+
| `component` | `React.ElementType` | `'div'` | The container element to render |
|
|
189
|
+
| `className` | `string` | `undefined` | CSS classes for the container |
|
|
190
|
+
| `options` | `Partial<AnimationOptions>` | `undefined` | Default animation options for all children |
|
|
191
|
+
| `children` | `React.ReactNode` | - | Child elements |
|
|
192
|
+
|
|
193
|
+
**Example:**
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
<AOSProvider
|
|
197
|
+
component="section"
|
|
198
|
+
className="overflow-hidden"
|
|
199
|
+
options={{
|
|
200
|
+
duration: 600,
|
|
201
|
+
easing: "power2.out",
|
|
202
|
+
once: true,
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
{/* Children will inherit these default options */}
|
|
206
|
+
</AOSProvider>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
> The default options only affect animations generated subsequently. This is intentional behavior.
|
|
210
|
+
|
|
211
|
+
### useAOSScope
|
|
212
|
+
|
|
213
|
+
The core hook that powers `AOSProvider`. Use this when you need direct control over the container ref.
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
function useAOSScope<E extends HTMLElement = HTMLElement>(
|
|
217
|
+
options?: Partial<AnimationOptions>,
|
|
218
|
+
): { containerRef: React.RefObject<E> };
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Example:**
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
"use client";
|
|
225
|
+
|
|
226
|
+
import { useAOSScope } from "react-gsap-aos/client";
|
|
227
|
+
|
|
228
|
+
export default function Demo() {
|
|
229
|
+
const { containerRef } = useAOSScope<HTMLDivElement>({
|
|
230
|
+
easing: "bounce.out",
|
|
231
|
+
duration: 800,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<div ref={containerRef} className="overflow-hidden">
|
|
236
|
+
<div data-aos="fade-up">Animated content</div>
|
|
237
|
+
</div>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
⚠️ **Important**:
|
|
243
|
+
|
|
244
|
+
- Do not nest `useAOSScope` calls
|
|
245
|
+
- Use in client components only (add `"use client"` directive)
|
|
246
|
+
- Avoid placing in `app/layout.tsx` for proper cleanup
|
|
247
|
+
|
|
248
|
+
**Parallel Usage:**
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
function Demo() {
|
|
252
|
+
return (
|
|
253
|
+
<div>
|
|
254
|
+
<Section1 />
|
|
255
|
+
<Section2 />
|
|
256
|
+
</div>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function Section1() {
|
|
261
|
+
const { containerRef } = useAOSScope<HTMLDivElement>();
|
|
262
|
+
return <div ref={containerRef}>...</div>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function Section2() {
|
|
266
|
+
const { containerRef } = useAOSScope<HTMLDivElement>();
|
|
267
|
+
return <div ref={containerRef}>...</div>;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### toAOSProps
|
|
272
|
+
|
|
273
|
+
Converts animation options to data attributes with type safety.
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
import { toAOSProps } from "react-gsap-aos";
|
|
277
|
+
|
|
278
|
+
const props = toAOSProps({
|
|
279
|
+
animation: "fade-up",
|
|
280
|
+
duration: 600,
|
|
281
|
+
easing: "power2.out",
|
|
282
|
+
});
|
|
283
|
+
// Returns: { "data-aos": "fade-up", "data-aos-duration": 600, ... }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### refreshScrollTrigger
|
|
287
|
+
|
|
288
|
+
Manually refresh AOS animation positions, wrapper around [`ScrollTrigger.refresh`](<https://gsap.com/docs/v3/Plugins/ScrollTrigger/refresh()>).
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
import { refreshScrollTrigger } from "react-gsap-aos";
|
|
292
|
+
|
|
293
|
+
// Call after dynamic DOM changes
|
|
294
|
+
refreshScrollTrigger();
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Example with Dynamic Content:**
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
"use client";
|
|
301
|
+
|
|
302
|
+
import { useState, useEffect } from "react";
|
|
303
|
+
import { AOSProvider, refreshScrollTrigger } from "react-gsap-aos/client";
|
|
304
|
+
|
|
305
|
+
export default function DynamicList() {
|
|
306
|
+
const [visible, setVisible] = useState(true);
|
|
307
|
+
const [items, setItems] = useState([1, 2, 3]);
|
|
308
|
+
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
// Refresh after visible change
|
|
311
|
+
refreshScrollTrigger();
|
|
312
|
+
}, [visible]);
|
|
313
|
+
|
|
314
|
+
return (
|
|
315
|
+
<AOSProvider className="overflow-hidden">
|
|
316
|
+
<button onClick={() => setVisible((e) => !e)}>switch visible</button>
|
|
317
|
+
// When visible changes, the layout changes.
|
|
318
|
+
{visible ? <div className="h-80" /> : null}
|
|
319
|
+
<div data-aos-container>
|
|
320
|
+
<div key={item} data-aos="fade-up">
|
|
321
|
+
Hello AOS
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
</AOSProvider>
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Animation Options
|
|
330
|
+
|
|
331
|
+
| Option | Type | Data Attribute | Default | Description |
|
|
332
|
+
| ----------------- | ----------------- | --------------------------- | -------------- | ------------------------------ |
|
|
333
|
+
| `animation` | `Animation` | `data-aos` | `undefined` | Animation type |
|
|
334
|
+
| `offset` | `number` | `data-aos-offset` | `120` | Offset (px) from trigger point |
|
|
335
|
+
| `delay` | `number` | `data-aos-delay` | `0` | Animation delay (ms) |
|
|
336
|
+
| `duration` | `number` | `data-aos-duration` | `400` | Animation duration (ms) |
|
|
337
|
+
| `easing` | `Easing` | `data-aos-easing` | `"none"` | Easing function |
|
|
338
|
+
| `once` | `boolean` | `data-aos-once` | `false` | Animate only once |
|
|
339
|
+
| `mirror` | `boolean` | `data-aos-mirror` | `false` | Reverse animation on scroll up |
|
|
340
|
+
| `anchorPlacement` | `AnchorPlacement` | `data-aos-anchor-placement` | `"top-bottom"` | Trigger position |
|
|
341
|
+
| `markers` | `boolean` | `data-aos-markers` | `false` | ScrollTrigger markers |
|
|
342
|
+
|
|
343
|
+
## Available Types
|
|
344
|
+
|
|
345
|
+
### Animation Types (34 total)
|
|
346
|
+
|
|
347
|
+
**Fade Animations:**
|
|
348
|
+
|
|
349
|
+
- `fade`, `fade-up`, `fade-down`, `fade-left`, `fade-right`
|
|
350
|
+
- `fade-up-right`, `fade-up-left`, `fade-down-right`, `fade-down-left`
|
|
351
|
+
|
|
352
|
+
**Flip Animations:**
|
|
353
|
+
|
|
354
|
+
- `flip-up`, `flip-down`, `flip-left`, `flip-right`
|
|
355
|
+
|
|
356
|
+
**Slide Animations:**
|
|
357
|
+
|
|
358
|
+
- `slide-up`, `slide-down`, `slide-left`, `slide-right`
|
|
359
|
+
|
|
360
|
+
**Zoom Animations:**
|
|
361
|
+
|
|
362
|
+
- `zoom-in`, `zoom-in-up`, `zoom-in-down`, `zoom-in-left`, `zoom-in-right`
|
|
363
|
+
- `zoom-out`, `zoom-out-up`, `zoom-out-down`, `zoom-out-left`, `zoom-out-right`
|
|
364
|
+
|
|
365
|
+
### Easing Types (17 total)
|
|
366
|
+
|
|
367
|
+
- `none`
|
|
368
|
+
- `power1`, `power1.in`, `power1.out`, `power1.inOut`
|
|
369
|
+
- `power2`, `power2.in`, `power2.out`, `power2.inOut`
|
|
370
|
+
- `power3`, `power3.in`, `power3.out`, `power3.inOut`
|
|
371
|
+
- `power4`, `power4.in`, `power4.out`, `power4.inOut`
|
|
372
|
+
- `back`, `back.in`, `back.out`, `back.inOut`
|
|
373
|
+
- `bounce`, `bounce.in`, `bounce.out`, `bounce.inOut`
|
|
374
|
+
- `circ`, `circ.in`, `circ.out`, `circ.inOut`
|
|
375
|
+
- `elastic`, `elastic.in`, `elastic.out`, `elastic.inOut`
|
|
376
|
+
- `expo`, `expo.in`, `expo.out`, `expo.inOut`
|
|
377
|
+
- `sine`, `sine.in`, `sine.out`, `sine.inOut`
|
|
378
|
+
|
|
379
|
+
### Anchor Placement Types (9 total)
|
|
380
|
+
|
|
381
|
+
Format: `[element-position]-[viewport-position]`
|
|
382
|
+
|
|
383
|
+
- `top-bottom`, `top-center`, `top-top`
|
|
384
|
+
- `center-bottom`, `center-center`, `center-top`
|
|
385
|
+
- `bottom-bottom`, `bottom-center`, `bottom-top`
|