partycles 1.1.3 → 1.1.5
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.md +115 -25
- package/dist/animations/animations/coins.d.ts +3 -1
- package/dist/animations/animations/coins.d.ts.map +1 -1
- package/dist/animations/animations/hearts.d.ts +3 -1
- package/dist/animations/animations/hearts.d.ts.map +1 -1
- package/dist/animations/animations/index.d.ts.map +1 -1
- package/dist/animations/coins.d.ts +3 -1
- package/dist/animations/coins.d.ts.map +1 -1
- package/dist/animations/hearts.d.ts +3 -1
- package/dist/animations/hearts.d.ts.map +1 -1
- package/dist/animations/hearts.esm.js +7 -1
- package/dist/animations/hearts.esm.js.map +1 -1
- package/dist/animations/hearts.js +7 -1
- package/dist/animations/hearts.js.map +1 -1
- package/dist/animations/types.d.ts +9 -0
- package/dist/animations/types.d.ts.map +1 -1
- package/dist/animations/useReward.d.ts.map +1 -1
- package/dist/index.esm.js +45 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +45 -4
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/useReward.d.ts.map +1 -1
- package/package.json +14 -3
package/README.md
CHANGED
@@ -12,11 +12,11 @@ A lightweight, performant React library for adding delightful animation effects
|
|
12
12
|
## ✨ Features
|
13
13
|
|
14
14
|
- 🎯 **Simple API** - Just one hook to rule them all
|
15
|
-
- 🎨 **
|
15
|
+
- 🎨 **19 Beautiful Animations** - Confetti, sparkles, hearts, stars, fireworks, bubbles, snow, emoji, coins, petals, aurora, fireflies, paint, balloons, galaxy, glitch, magicdust, crystals, and leaves
|
16
16
|
- 📦 **Tiny Bundle** - Zero dependencies, optimized for performance
|
17
17
|
- 🚀 **Performant** - Optimized animations using requestAnimationFrame
|
18
18
|
- 🎮 **Full Control** - Customize colors, particle count, physics, and more
|
19
|
-
- 📱 **
|
19
|
+
- 📱 **Mobile Optimized** - Automatic performance optimizations for mobile devices
|
20
20
|
- 🔧 **TypeScript Support** - Fully typed for excellent DX
|
21
21
|
- ⚡ **React 18 Ready** - Built with the latest React features
|
22
22
|
|
@@ -52,7 +52,7 @@ That's it! No configuration needed - it just works. 🎊
|
|
52
52
|
|
53
53
|
- **Zero Dependencies** - No bloat, just pure React code
|
54
54
|
- **One Hook** - Simple `useReward` hook handles everything
|
55
|
-
- **
|
55
|
+
- **19 Animations** - From confetti to magical effects, we've got you covered
|
56
56
|
- **Fully Typed** - Great TypeScript support out of the box
|
57
57
|
- **Customizable** - Tweak colors, physics, particle count, and more
|
58
58
|
- **Performant** - Optimized animations that won't slow down your app
|
@@ -66,7 +66,7 @@ The main hook for creating reward animations.
|
|
66
66
|
#### Parameters
|
67
67
|
|
68
68
|
- `elementId` (string): The ID of the element to animate from
|
69
|
-
- `animationType` (string): One of: `'confetti'`, `'sparkles'`, `'hearts'`, `'stars'`, `'fireworks'`, `'bubbles'`, `'snow'`, `'emoji'`, `'coins'`, `'
|
69
|
+
- `animationType` (string): One of: `'confetti'`, `'sparkles'`, `'hearts'`, `'stars'`, `'fireworks'`, `'bubbles'`, `'snow'`, `'emoji'`, `'coins'`, `'petals'`, `'aurora'`, `'fireflies'`, `'paint'`, `'balloons'`, `'galaxy'`, `'glitch'`, `'magicdust'`, `'crystals'`, `'leaves'`
|
70
70
|
- `config` (optional): Animation configuration object
|
71
71
|
|
72
72
|
#### Returns
|
@@ -91,6 +91,15 @@ interface AnimationConfig {
|
|
91
91
|
wind?: number; // Horizontal wind force (default: 0)
|
92
92
|
friction?: number; // Air friction (default: 0.99)
|
93
93
|
};
|
94
|
+
// NEW: Optional enhanced effects
|
95
|
+
effects?: {
|
96
|
+
flutter?: boolean; // Paper-like floating for confetti
|
97
|
+
twinkle?: boolean; // Brightness variation for stars/sparkles
|
98
|
+
pulse?: boolean; // Heartbeat effect for hearts
|
99
|
+
spin3D?: boolean; // 3D rotation for coins
|
100
|
+
wobble?: boolean; // Realistic wobble for bubbles
|
101
|
+
windDrift?: boolean; // Horizontal drift for snow/leaves
|
102
|
+
};
|
94
103
|
}
|
95
104
|
```
|
96
105
|
|
@@ -103,7 +112,9 @@ Classic celebration effect with colorful paper pieces.
|
|
103
112
|
const { reward } = useReward('buttonId', 'confetti', {
|
104
113
|
particleCount: 30,
|
105
114
|
spread: 60,
|
106
|
-
colors: ['#ff0000', '#00ff00', '#0000ff']
|
115
|
+
colors: ['#ff0000', '#00ff00', '#0000ff'],
|
116
|
+
// NEW: Enable paper flutter effect
|
117
|
+
effects: { flutter: true }
|
107
118
|
});
|
108
119
|
```
|
109
120
|
|
@@ -202,16 +213,6 @@ const { reward } = useReward('buttonId', 'coins', {
|
|
202
213
|
});
|
203
214
|
```
|
204
215
|
|
205
|
-
### Lightning ⚡
|
206
|
-
Electric energy bursts for powerful actions.
|
207
|
-
|
208
|
-
```tsx
|
209
|
-
const { reward } = useReward('buttonId', 'lightning', {
|
210
|
-
particleCount: 20,
|
211
|
-
spread: 360
|
212
|
-
});
|
213
|
-
```
|
214
|
-
|
215
216
|
### Petals 🌸
|
216
217
|
Delicate flower petals floating in the wind.
|
217
218
|
|
@@ -252,16 +253,6 @@ const { reward } = useReward('buttonId', 'paint', {
|
|
252
253
|
});
|
253
254
|
```
|
254
255
|
|
255
|
-
### Music 🎵
|
256
|
-
Musical notes floating upward.
|
257
|
-
|
258
|
-
```tsx
|
259
|
-
const { reward } = useReward('buttonId', 'music', {
|
260
|
-
particleCount: 20,
|
261
|
-
physics: { gravity: -0.08 }
|
262
|
-
});
|
263
|
-
```
|
264
|
-
|
265
256
|
### Balloons 🎈
|
266
257
|
Floating balloons with realistic physics.
|
267
258
|
|
@@ -282,6 +273,46 @@ const { reward } = useReward('buttonId', 'galaxy', {
|
|
282
273
|
});
|
283
274
|
```
|
284
275
|
|
276
|
+
### Glitch 📺
|
277
|
+
Digital glitch effect for tech themes.
|
278
|
+
|
279
|
+
```tsx
|
280
|
+
const { reward } = useReward('buttonId', 'glitch', {
|
281
|
+
particleCount: 30,
|
282
|
+
elementSize: 40
|
283
|
+
});
|
284
|
+
```
|
285
|
+
|
286
|
+
### Magic Dust ✨
|
287
|
+
Magical sparkling dust particles.
|
288
|
+
|
289
|
+
```tsx
|
290
|
+
const { reward } = useReward('buttonId', 'magicdust', {
|
291
|
+
particleCount: 35,
|
292
|
+
colors: ['#9c27b0', '#673ab7', '#3f51b5']
|
293
|
+
});
|
294
|
+
```
|
295
|
+
|
296
|
+
### Crystals 💎
|
297
|
+
Shimmering crystal fragments.
|
298
|
+
|
299
|
+
```tsx
|
300
|
+
const { reward } = useReward('buttonId', 'crystals', {
|
301
|
+
particleCount: 20,
|
302
|
+
elementSize: 25
|
303
|
+
});
|
304
|
+
```
|
305
|
+
|
306
|
+
### Leaves 🍃
|
307
|
+
Falling autumn leaves with natural movement.
|
308
|
+
|
309
|
+
```tsx
|
310
|
+
const { reward } = useReward('buttonId', 'leaves', {
|
311
|
+
particleCount: 30,
|
312
|
+
physics: { gravity: 0.05, wind: 0.2 }
|
313
|
+
});
|
314
|
+
```
|
315
|
+
|
285
316
|
## 💡 Examples
|
286
317
|
|
287
318
|
### Form Submission Success
|
@@ -354,6 +385,54 @@ function Achievement({ unlocked, name }) {
|
|
354
385
|
}
|
355
386
|
```
|
356
387
|
|
388
|
+
## ✨ Enhanced Effects (v1.1.5+)
|
389
|
+
|
390
|
+
Make animations more realistic with optional effects:
|
391
|
+
|
392
|
+
```tsx
|
393
|
+
// Confetti with paper flutter
|
394
|
+
const { reward } = useReward('confetti-btn', 'confetti', {
|
395
|
+
effects: { flutter: true }
|
396
|
+
});
|
397
|
+
|
398
|
+
// Stars with twinkling
|
399
|
+
const { reward } = useReward('star-btn', 'stars', {
|
400
|
+
effects: { twinkle: true }
|
401
|
+
});
|
402
|
+
|
403
|
+
// Hearts with pulse/heartbeat
|
404
|
+
const { reward } = useReward('heart-btn', 'hearts', {
|
405
|
+
effects: { pulse: true }
|
406
|
+
});
|
407
|
+
|
408
|
+
// Coins with 3D spin
|
409
|
+
const { reward } = useReward('coin-btn', 'coins', {
|
410
|
+
effects: { spin3D: true }
|
411
|
+
});
|
412
|
+
|
413
|
+
// Snow with wind drift
|
414
|
+
const { reward } = useReward('snow-btn', 'snow', {
|
415
|
+
effects: { windDrift: true }
|
416
|
+
});
|
417
|
+
|
418
|
+
// Bubbles with wobble
|
419
|
+
const { reward } = useReward('bubble-btn', 'bubbles', {
|
420
|
+
effects: { wobble: true }
|
421
|
+
});
|
422
|
+
|
423
|
+
// Combine multiple effects
|
424
|
+
const { reward } = useReward('magic-btn', 'sparkles', {
|
425
|
+
effects: {
|
426
|
+
twinkle: true,
|
427
|
+
// Other effects work too!
|
428
|
+
},
|
429
|
+
physics: {
|
430
|
+
gravity: 0.2,
|
431
|
+
wind: 0.1
|
432
|
+
}
|
433
|
+
});
|
434
|
+
```
|
435
|
+
|
357
436
|
## 🎯 Best Practices
|
358
437
|
|
359
438
|
1. **Unique IDs**: Ensure each animated element has a unique ID
|
@@ -448,6 +527,17 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
448
527
|
4. Push to the branch (`git push origin feature/amazing-feature`)
|
449
528
|
5. Open a Pull Request
|
450
529
|
|
530
|
+
## 📈 Changelog
|
531
|
+
|
532
|
+
### v1.1.3 (Latest)
|
533
|
+
- 🚀 Added automatic mobile performance optimizations
|
534
|
+
- 🐛 Fixed Safari compatibility issues
|
535
|
+
- 📦 Streamlined bundle size by removing 7 animations
|
536
|
+
- 🔧 Fixed CI/CD pipeline and npm publishing
|
537
|
+
|
538
|
+
### v1.0.0
|
539
|
+
- 🎉 Initial release with 26 animations
|
540
|
+
|
451
541
|
## 📄 License
|
452
542
|
|
453
543
|
MIT © Jonathan Leane
|
@@ -4,5 +4,7 @@ export declare const createCoinParticles: (origin: {
|
|
4
4
|
x: number;
|
5
5
|
y: number;
|
6
6
|
}, config: AnimationConfig) => Particle[];
|
7
|
-
export declare const renderCoinParticle: (particle: Particle
|
7
|
+
export declare const renderCoinParticle: (particle: Particle & {
|
8
|
+
config?: AnimationConfig;
|
9
|
+
}) => React.ReactNode;
|
8
10
|
//# sourceMappingURL=coins.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,
|
1
|
+
{"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAoD5F,CAAC"}
|
@@ -4,5 +4,7 @@ export declare const createHeartParticles: (origin: {
|
|
4
4
|
x: number;
|
5
5
|
y: number;
|
6
6
|
}, config: AnimationConfig) => Particle[];
|
7
|
-
export declare const renderHeartParticle: (particle: Particle
|
7
|
+
export declare const renderHeartParticle: (particle: Particle & {
|
8
|
+
config?: AnimationConfig;
|
9
|
+
}) => React.ReactNode;
|
8
10
|
//# sourceMappingURL=hearts.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,
|
1
|
+
{"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAqB7F,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAsBpE,MAAM,MAAM,eAAe,GAAG,CAC5B,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,MAAM,EAAE,eAAe,KACpB,QAAQ,EAAE,CAAC;AAChB,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,KAAK,CAAC,SAAS,CAAC;AAEvE,UAAU,gBAAgB;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,gBAAgB,CAAC;CAClC;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CA6E9D,CAAC"}
|
@@ -4,5 +4,7 @@ export declare const createCoinParticles: (origin: {
|
|
4
4
|
x: number;
|
5
5
|
y: number;
|
6
6
|
}, config: AnimationConfig) => Particle[];
|
7
|
-
export declare const renderCoinParticle: (particle: Particle
|
7
|
+
export declare const renderCoinParticle: (particle: Particle & {
|
8
|
+
config?: AnimationConfig;
|
9
|
+
}) => React.ReactNode;
|
8
10
|
//# sourceMappingURL=coins.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,
|
1
|
+
{"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAoD5F,CAAC"}
|
@@ -4,5 +4,7 @@ export declare const createHeartParticles: (origin: {
|
|
4
4
|
x: number;
|
5
5
|
y: number;
|
6
6
|
}, config: AnimationConfig) => Particle[];
|
7
|
-
export declare const renderHeartParticle: (particle: Particle
|
7
|
+
export declare const renderHeartParticle: (particle: Particle & {
|
8
|
+
config?: AnimationConfig;
|
9
|
+
}) => React.ReactNode;
|
8
10
|
//# sourceMappingURL=hearts.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,
|
1
|
+
{"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAqB7F,CAAC"}
|
@@ -34,8 +34,14 @@ const createHeartParticles = (origin, config) => {
|
|
34
34
|
return particles;
|
35
35
|
};
|
36
36
|
const renderHeartParticle = (particle) => {
|
37
|
-
|
37
|
+
var _a, _b;
|
38
|
+
// Calculate pulse effect if enabled
|
39
|
+
const pulse = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.pulse)
|
40
|
+
? 1 + Math.sin(particle.life * 0.2) * 0.1
|
41
|
+
: 1;
|
42
|
+
return (React.createElement("svg", { key: particle.id, width: particle.size * pulse, height: particle.size * pulse, viewBox: "0 0 24 24", fill: particle.color, style: {
|
38
43
|
filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,
|
44
|
+
transition: 'width 0.1s ease-out, height 0.1s ease-out',
|
39
45
|
} },
|
40
46
|
React.createElement("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })));
|
41
47
|
};
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"hearts.esm.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle): React.ReactNode => {\n return (\n <svg\n key={particle.id}\n width={particle.size}\n height={particle.size}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":";;AAEO,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,GAAW,KAAY;AAChE,IAAA,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG;AAC1C,CAAC;AAMM,MAAM,UAAU,GAAG,MAAa;AACrC,IAAA,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAEM,MAAM,cAAc,GAAG,CAAC,MAAgB,KAAY;IACzD,QACE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS;AAE/E,CAAC;;ACdD,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;MAE9D,oBAAoB,GAAG,CAClC,MAAgC,EAChC,MAAuB,KACT;AACd,IAAA,MAAM,EACJ,aAAa,GAAG,EAAE,EAClB,aAAa,GAAG,EAAE,EAClB,MAAM,GAAG,WAAW,EACpB,WAAW,GAAG,EAAE,GACjB,GAAG,MAAM;IAEV,MAAM,SAAS,GAAe,EAAE;AAEhC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;AACtC,QAAA,MAAM,QAAQ,GAAG,aAAa,CAAC,aAAa,GAAG,GAAG,EAAE,aAAa,GAAG,GAAG,CAAC;QACxE,MAAM,eAAe,GAAG,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC;QAE5C,SAAS,CAAC,IAAI,CAAC;YACb,EAAE,EAAE,UAAU,EAAE;YAChB,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC;YACpC,CAAC,EAAE,MAAM,CAAC,CAAC;AACX,YAAA,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,QAAQ,GAAG,eAAe;AAClE,YAAA,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,QAAQ;AAChD,YAAA,IAAI,EAAE,MAAM,CAAC,QAAQ,IAAI,GAAG;AAC5B,YAAA,OAAO,EAAE,CAAC;YACV,IAAI,EAAE,aAAa,CAAC,WAAW,GAAG,GAAG,EAAE,WAAW,GAAG,GAAG,CAAC;AACzD,YAAA,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC;AAChC,YAAA,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC;AAC9B,SAAA,CAAC;;AAGJ,IAAA,OAAO,SAAS;AAClB;AAEa,MAAA,mBAAmB,GAAG,CAAC,
|
1
|
+
{"version":3,"file":"hearts.esm.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle & { config?: AnimationConfig }): React.ReactNode => {\n // Calculate pulse effect if enabled\n const pulse = particle.config?.effects?.pulse \n ? 1 + Math.sin(particle.life * 0.2) * 0.1 \n : 1;\n \n return (\n <svg\n key={particle.id}\n width={particle.size * pulse}\n height={particle.size * pulse}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n transition: 'width 0.1s ease-out, height 0.1s ease-out',\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":"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"}
|
@@ -36,8 +36,14 @@ const createHeartParticles = (origin, config) => {
|
|
36
36
|
return particles;
|
37
37
|
};
|
38
38
|
const renderHeartParticle = (particle) => {
|
39
|
-
|
39
|
+
var _a, _b;
|
40
|
+
// Calculate pulse effect if enabled
|
41
|
+
const pulse = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.pulse)
|
42
|
+
? 1 + Math.sin(particle.life * 0.2) * 0.1
|
43
|
+
: 1;
|
44
|
+
return (React.createElement("svg", { key: particle.id, width: particle.size * pulse, height: particle.size * pulse, viewBox: "0 0 24 24", fill: particle.color, style: {
|
40
45
|
filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,
|
46
|
+
transition: 'width 0.1s ease-out, height 0.1s ease-out',
|
41
47
|
} },
|
42
48
|
React.createElement("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })));
|
43
49
|
};
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"hearts.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle): React.ReactNode => {\n return (\n <svg\n key={particle.id}\n width={particle.size}\n height={particle.size}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":";;;;AAEO,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,GAAW,KAAY;AAChE,IAAA,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG;AAC1C,CAAC;AAMM,MAAM,UAAU,GAAG,MAAa;AACrC,IAAA,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAEM,MAAM,cAAc,GAAG,CAAC,MAAgB,KAAY;IACzD,QACE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS;AAE/E,CAAC;;ACdD,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;MAE9D,oBAAoB,GAAG,CAClC,MAAgC,EAChC,MAAuB,KACT;AACd,IAAA,MAAM,EACJ,aAAa,GAAG,EAAE,EAClB,aAAa,GAAG,EAAE,EAClB,MAAM,GAAG,WAAW,EACpB,WAAW,GAAG,EAAE,GACjB,GAAG,MAAM;IAEV,MAAM,SAAS,GAAe,EAAE;AAEhC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;AACtC,QAAA,MAAM,QAAQ,GAAG,aAAa,CAAC,aAAa,GAAG,GAAG,EAAE,aAAa,GAAG,GAAG,CAAC;QACxE,MAAM,eAAe,GAAG,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC;QAE5C,SAAS,CAAC,IAAI,CAAC;YACb,EAAE,EAAE,UAAU,EAAE;YAChB,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC;YACpC,CAAC,EAAE,MAAM,CAAC,CAAC;AACX,YAAA,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,QAAQ,GAAG,eAAe;AAClE,YAAA,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,QAAQ;AAChD,YAAA,IAAI,EAAE,MAAM,CAAC,QAAQ,IAAI,GAAG;AAC5B,YAAA,OAAO,EAAE,CAAC;YACV,IAAI,EAAE,aAAa,CAAC,WAAW,GAAG,GAAG,EAAE,WAAW,GAAG,GAAG,CAAC;AACzD,YAAA,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC;AAChC,YAAA,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC;AAC9B,SAAA,CAAC;;AAGJ,IAAA,OAAO,SAAS;AAClB;AAEa,MAAA,mBAAmB,GAAG,CAAC,
|
1
|
+
{"version":3,"file":"hearts.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle & { config?: AnimationConfig }): React.ReactNode => {\n // Calculate pulse effect if enabled\n const pulse = particle.config?.effects?.pulse \n ? 1 + Math.sin(particle.life * 0.2) * 0.1 \n : 1;\n \n return (\n <svg\n key={particle.id}\n width={particle.size * pulse}\n height={particle.size * pulse}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n transition: 'width 0.1s ease-out, height 0.1s ease-out',\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":"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"}
|
@@ -10,6 +10,7 @@ export interface Particle {
|
|
10
10
|
rotation: number;
|
11
11
|
color: string;
|
12
12
|
element?: React.ReactNode;
|
13
|
+
config?: AnimationConfig;
|
13
14
|
}
|
14
15
|
export interface AnimationConfig {
|
15
16
|
particleCount?: number;
|
@@ -25,6 +26,14 @@ export interface AnimationConfig {
|
|
25
26
|
wind?: number;
|
26
27
|
friction?: number;
|
27
28
|
};
|
29
|
+
effects?: {
|
30
|
+
flutter?: boolean;
|
31
|
+
twinkle?: boolean;
|
32
|
+
pulse?: boolean;
|
33
|
+
spin3D?: boolean;
|
34
|
+
wobble?: boolean;
|
35
|
+
windDrift?: boolean;
|
36
|
+
};
|
28
37
|
}
|
29
38
|
export type AnimationType = 'confetti' | 'sparkles' | 'fireworks' | 'hearts' | 'stars' | 'bubbles' | 'snow' | 'emoji' | 'coins' | 'petals' | 'aurora' | 'fireflies' | 'paint' | 'balloons' | 'galaxy' | 'leaves' | 'glitch' | 'magicdust' | 'crystals';
|
30
39
|
export interface UseRewardConfig extends AnimationConfig {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;CACH;AAED,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,GACV,WAAW,GACX,QAAQ,GACR,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,OAAO,GACP,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,aAAa,EAAE,aAAa,CAAC;CAC9B"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"useReward.d.ts","sourceRoot":"","sources":["../src/useReward.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAY,MAAM,SAAS,CAAC;AAQnE,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,GACpB,WAAW,MAAM,EACjB,eAAe,aAAa,EAC5B,SAAS,eAAe,KACvB,
|
1
|
+
{"version":3,"file":"useReward.d.ts","sourceRoot":"","sources":["../src/useReward.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAY,MAAM,SAAS,CAAC;AAQnE,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,GACpB,WAAW,MAAM,EACjB,eAAe,aAAa,EAC5B,SAAS,eAAe,KACvB,eAsNF,CAAC"}
|
package/dist/index.esm.js
CHANGED
@@ -131,8 +131,14 @@ const createHeartParticles = (origin, config) => {
|
|
131
131
|
return particles;
|
132
132
|
};
|
133
133
|
const renderHeartParticle = (particle) => {
|
134
|
-
|
134
|
+
var _a, _b;
|
135
|
+
// Calculate pulse effect if enabled
|
136
|
+
const pulse = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.pulse)
|
137
|
+
? 1 + Math.sin(particle.life * 0.2) * 0.1
|
138
|
+
: 1;
|
139
|
+
return (React.createElement("svg", { key: particle.id, width: particle.size * pulse, height: particle.size * pulse, viewBox: "0 0 24 24", fill: particle.color, style: {
|
135
140
|
filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,
|
141
|
+
transition: 'width 0.1s ease-out, height 0.1s ease-out',
|
136
142
|
} },
|
137
143
|
React.createElement("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })));
|
138
144
|
};
|
@@ -368,14 +374,21 @@ const createCoinParticles = (origin, config) => {
|
|
368
374
|
return particles;
|
369
375
|
};
|
370
376
|
const renderCoinParticle = (particle) => {
|
371
|
-
|
377
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
378
|
+
const spinSpeed = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.spin3D) ? 8 : 2; // Faster spin with 3D effect
|
372
379
|
const currentRotation = particle.rotation + (120 - particle.life) * spinSpeed;
|
380
|
+
// 3D effect: scale X based on rotation to simulate perspective
|
381
|
+
const scaleX = ((_d = (_c = particle.config) === null || _c === void 0 ? void 0 : _c.effects) === null || _d === void 0 ? void 0 : _d.spin3D)
|
382
|
+
? Math.abs(Math.cos((currentRotation * Math.PI) / 180))
|
383
|
+
: 1;
|
373
384
|
return (React.createElement("div", { key: particle.id, style: {
|
374
385
|
width: `${particle.size}px`,
|
375
386
|
height: `${particle.size}px`,
|
376
387
|
background: `radial-gradient(ellipse at 30% 30%, ${particle.color}, #B8860B)`,
|
377
388
|
borderRadius: '50%',
|
378
|
-
transform:
|
389
|
+
transform: ((_f = (_e = particle.config) === null || _e === void 0 ? void 0 : _e.effects) === null || _f === void 0 ? void 0 : _f.spin3D)
|
390
|
+
? `rotateY(${currentRotation}deg) scaleX(${scaleX})`
|
391
|
+
: `rotate(${currentRotation}deg)`,
|
379
392
|
transformStyle: 'preserve-3d',
|
380
393
|
boxShadow: `
|
381
394
|
inset -2px -2px 4px rgba(0, 0, 0, 0.3),
|
@@ -385,6 +398,7 @@ const renderCoinParticle = (particle) => {
|
|
385
398
|
border: `1px solid ${particle.color}`,
|
386
399
|
position: 'relative',
|
387
400
|
overflow: 'hidden',
|
401
|
+
backfaceVisibility: 'hidden',
|
388
402
|
} },
|
389
403
|
React.createElement("div", { style: {
|
390
404
|
position: 'absolute',
|
@@ -396,6 +410,8 @@ const renderCoinParticle = (particle) => {
|
|
396
410
|
color: '#B8860B',
|
397
411
|
textShadow: '1px 1px 1px rgba(0, 0, 0, 0.3)',
|
398
412
|
fontFamily: 'Arial, sans-serif',
|
413
|
+
opacity: ((_h = (_g = particle.config) === null || _g === void 0 ? void 0 : _g.effects) === null || _h === void 0 ? void 0 : _h.spin3D) && scaleX < 0.3 ? 0 : 1,
|
414
|
+
transition: 'opacity 0.1s',
|
399
415
|
} }, "$")));
|
400
416
|
};
|
401
417
|
|
@@ -1331,7 +1347,8 @@ const useReward = (elementId, animationType, config) => {
|
|
1331
1347
|
? optimizeConfigForMobile(config)
|
1332
1348
|
: undefined;
|
1333
1349
|
// Create particles
|
1334
|
-
particlesRef.current = animationHandler.createParticles(origin, optimizedConfig || {})
|
1350
|
+
particlesRef.current = animationHandler.createParticles(origin, optimizedConfig || {}).map(particle => (Object.assign(Object.assign({}, particle), { config: optimizedConfig || config // Store config in particle for render functions
|
1351
|
+
})));
|
1335
1352
|
// Create container
|
1336
1353
|
const container = document.createElement('div');
|
1337
1354
|
container.style.position = 'fixed';
|
@@ -1376,6 +1393,22 @@ const useReward = (elementId, animationType, config) => {
|
|
1376
1393
|
particle.vy *= friction;
|
1377
1394
|
particle.rotation += particle.vx * 2;
|
1378
1395
|
particle.life -= 1.2;
|
1396
|
+
// Apply optional effects
|
1397
|
+
const effects = config === null || config === void 0 ? void 0 : config.effects;
|
1398
|
+
// Flutter effect for confetti
|
1399
|
+
if ((effects === null || effects === void 0 ? void 0 : effects.flutter) && animationType === 'confetti') {
|
1400
|
+
particle.x += Math.sin(particle.life * 0.1) * 0.5;
|
1401
|
+
particle.rotation += Math.sin(particle.life * 0.05) * 2;
|
1402
|
+
}
|
1403
|
+
// Wind drift for snow/leaves
|
1404
|
+
if ((effects === null || effects === void 0 ? void 0 : effects.windDrift) && (animationType === 'snow' || animationType === 'leaves')) {
|
1405
|
+
particle.x += Math.sin(particle.life * 0.05 + particle.id.charCodeAt(0)) * 0.8;
|
1406
|
+
}
|
1407
|
+
// Wobble effect for bubbles
|
1408
|
+
if ((effects === null || effects === void 0 ? void 0 : effects.wobble) && animationType === 'bubbles') {
|
1409
|
+
particle.x += Math.sin(particle.life * 0.08) * 0.3;
|
1410
|
+
particle.y += Math.cos(particle.life * 0.08) * 0.2;
|
1411
|
+
}
|
1379
1412
|
// Special opacity handling for sparkles
|
1380
1413
|
if (animationType === 'sparkles') {
|
1381
1414
|
if (particle.life > 70) {
|
@@ -1384,6 +1417,14 @@ const useReward = (elementId, animationType, config) => {
|
|
1384
1417
|
else if (particle.life < 30) {
|
1385
1418
|
particle.opacity = particle.life / 30;
|
1386
1419
|
}
|
1420
|
+
// Twinkle effect
|
1421
|
+
if (effects === null || effects === void 0 ? void 0 : effects.twinkle) {
|
1422
|
+
particle.opacity *= 0.5 + Math.sin(particle.life * 0.3) * 0.5;
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
else if (animationType === 'stars' && (effects === null || effects === void 0 ? void 0 : effects.twinkle)) {
|
1426
|
+
// Twinkle effect for stars
|
1427
|
+
particle.opacity = (particle.life / 100) * (0.5 + Math.sin(particle.life * 0.3) * 0.5);
|
1387
1428
|
}
|
1388
1429
|
else {
|
1389
1430
|
particle.opacity = particle.life / 100;
|