awesome-coverflow-carousel 0.1.3

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 AwesomeCoverflowCarousel Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2026-27] [Pravinkumar Dabade]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,578 @@
1
+ # AwesomeCoverflowCarousel
2
+
3
+ A beautiful, interactive 3D Coverflowcarousel component for React with smooth animations, multiple themes, and flexible data handling. Perfect for showcasing products, portfolios, or any collection of items in an eye-catching carousel format.
4
+
5
+ ## Features
6
+
7
+ - **3D CoverflowCarousel** - Visually stunning 3D perspective effects
8
+ - **4 Built-in Themes** - Dark, Light, Neon, and Glass themes
9
+ - **Multiple Control Methods** - Mouse drag, keyboard arrows, touch & programmatic
10
+ - **Auto-Rotate** - Automatic carousel rotation with customizable speed
11
+ - **Responsive** - Works seamlessly on different screen sizes
12
+ - **Smooth Physics** - Realistic inertia and friction animations
13
+ - **Glow Effects** - Beautiful focus glow for the active item
14
+ - **Highly Customizable** - Full control over speed, friction, perspective, and more
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install awesome-coverflow-carousel
20
+ ```
21
+
22
+ Or with pnpm:
23
+
24
+ ```bash
25
+ pnpm add awesome-coverflow-carousel
26
+ ```
27
+
28
+ Or with yarn:
29
+
30
+ ```bash
31
+ yarn add awesome-coverflow-carousel
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```jsx
37
+ import { AwesomeCoverflowCarousel } from 'awesome-coverflow-carousel';
38
+ import 'awesome-coverflow-carousel/dist/style.css';
39
+
40
+ const slides = [
41
+ { title: 'Slide 1', description: 'First slide', image: 'url1.jpg' },
42
+ { title: 'Slide 2', description: 'Second slide', image: 'url2.jpg' },
43
+ ];
44
+
45
+ export default function App() {
46
+ return (
47
+ <div
48
+ style={{
49
+ minHeight: '100vh',
50
+ padding: '48px 20px 64px',
51
+ background:
52
+ 'radial-gradient(70% 50% at 50% 35%, rgba(0,245,255,0.18) 0%, rgba(0,0,0,0) 60%), linear-gradient(180deg, #05070f 0%, #060b1a 55%, #070b12 100%)',
53
+ color: '#e6f0ff',
54
+ display: 'flex',
55
+ flexDirection: 'column',
56
+ alignItems: 'center',
57
+ justifyContent: 'center',
58
+ gap: '18px',
59
+ }}
60
+ >
61
+ <h1 style={{ margin: 0, fontSize: 'clamp(28px, 5vw, 56px)', letterSpacing: '-0.02em' }}>
62
+ Explore the Universe of <span style={{ color: '#00f5ff' }}>Possibilities</span>
63
+ </h1>
64
+ <p style={{ margin: 0, opacity: 0.7 }}>
65
+ Explore the full spectrum of products by clicking on any card
66
+ </p>
67
+
68
+ <div style={{ width: '100%', maxWidth: 980, height: '60vh', minHeight: 420 }}>
69
+ <AwesomeCoverflowCarousel data={slides} theme="dark" />
70
+ </div>
71
+ </div>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ## Data Format
77
+
78
+ Each item in the carousel requires the following structure:
79
+
80
+ ```js
81
+ const slide = {
82
+ title: 'Slide 1', // Required: Title displayed on the card
83
+ description: 'First slide', // Optional: Subtitle or description
84
+ image: 'url1.jpg', // Optional: Image URL
85
+ tag: 'Featured', // Optional: Tag label
86
+ color: '#ff6b6b', // Optional: Background color (hex)
87
+ onClick: () => {}, // Optional: Click handler
88
+ };
89
+ ```
90
+
91
+ For TypeScript users, this object shape maps directly to the `SlideData` type exported by the package.
92
+
93
+ ## Component Props
94
+
95
+ | Prop | Type | Default | Description |
96
+ |------|------|---------|-------------|
97
+ | `data` | `SlideData[]` | **Required** | Array of slide objects to display in the carousel |
98
+ | `autoRotate` | `boolean` | `true` | Enable automatic carousel rotation |
99
+ | `rotationSpeed` | `number` | `2800` | Time in milliseconds between auto-rotations |
100
+ | `friction` | `number` | `0.88` | Friction coefficient for inertia animations (0-1). Higher = more damping |
101
+ | `focusGlow` | `boolean` | `true` | Enable glow effect on the focused card |
102
+ | `theme` | `'dark' \| 'light' \| 'neon' \| 'glass'` | `'dark'` | Visual theme for the carousel |
103
+ | `perspective` | `number` | `1100` | 3D perspective depth in pixels |
104
+ | `onFocusChange` | `(index: number) => void` | `undefined` | Callback fired when the focused item changes |
105
+ | `className` | `string` | `undefined` | Custom CSS class for the carousel container |
106
+
107
+ ## Available Themes
108
+
109
+ ### Dark Theme
110
+ Modern dark theme with cyan accents. Perfect for tech products and modern designs.
111
+
112
+ ```jsx
113
+ <AwesomeCoverflowCarousel data={slides} theme="dark" />
114
+ ```
115
+
116
+ ### Light Theme
117
+ Clean light theme with violet accents. Great for portfolios and creative showcases.
118
+
119
+ ```jsx
120
+ <AwesomeCoverflowCarousel data={slides} theme="light" />
121
+ ```
122
+
123
+ ### Neon Theme
124
+ Vibrant neon magenta and cyan theme. Bold and eye-catching for entertainment and gaming.
125
+
126
+ ```jsx
127
+ <AwesomeCoverflowCarousel data={slides} theme="neon" />
128
+ ```
129
+
130
+ ### Glass Theme
131
+ Frosted glass effect with semi-transparent cards. Modern and elegant for premium brands.
132
+
133
+ ```jsx
134
+ <AwesomeCoverflowCarousel data={slides} theme="glass" />
135
+ ```
136
+
137
+ ## Usage Examples
138
+
139
+ ### Example 1: Static Data Source
140
+
141
+ Use hardcoded data directly in your component:
142
+
143
+ ```jsx
144
+ import { AwesomeCoverflowCarousel } from 'awesome-coverflow-carousel';
145
+ import 'awesome-coverflow-carousel/dist/style.css';
146
+
147
+ export default function StaticDataExample() {
148
+ const staticSlides = [
149
+ {
150
+ title: 'Product A',
151
+ description: 'Premium quality product',
152
+ image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=500&h=300&fit=crop',
153
+ tag: 'Featured',
154
+ onClick: () => console.log('Product A clicked')
155
+ },
156
+ {
157
+ title: 'Product B',
158
+ description: 'Best seller item',
159
+ image: 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=500&h=300&fit=crop',
160
+ tag: 'Sale',
161
+ onClick: () => console.log('Product B clicked')
162
+ },
163
+ {
164
+ title: 'Product C',
165
+ description: 'New arrival',
166
+ image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=500&h=300&fit=crop',
167
+ tag: 'New',
168
+ onClick: () => console.log('Product C clicked')
169
+ },
170
+ {
171
+ title: 'Product D',
172
+ description: 'Limited edition',
173
+ image: 'https://images.unsplash.com/photo-1517457373614-b7152f800fd1?w=500&h=300&fit=crop',
174
+ tag: 'Limited',
175
+ onClick: () => console.log('Product D clicked')
176
+ },
177
+ ];
178
+
179
+ return (
180
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
181
+ <h1 style={{ textAlign: 'center', padding: '20px' }}>Static Data Example</h1>
182
+ <div style={{ flex: 1 }}>
183
+ <AwesomeCoverflowCarousel
184
+ data={staticSlides}
185
+ theme="dark"
186
+ onFocusChange={(index) => console.log('Focused item:', index)}
187
+ />
188
+ </div>
189
+ </div>
190
+ );
191
+ }
192
+ ```
193
+
194
+ ### Example 2: JSON File Data Source
195
+
196
+ Load carousel data from a JSON file:
197
+
198
+ ```jsx
199
+ import { useEffect, useState } from 'react';
200
+ import { AwesomeCoverflowCarousel } from 'awesome-coverflow-carousel';
201
+ import 'awesome-coverflow-carousel/dist/style.css';
202
+
203
+ export default function JSONDataExample() {
204
+ const [slides, setSlides] = useState([]);
205
+ const [loading, setLoading] = useState(true);
206
+ const [error, setError] = useState(null);
207
+
208
+ useEffect(() => {
209
+ // Load slides from JSON file in public folder
210
+ fetch('/carousel-data.json')
211
+ .then((response) => {
212
+ if (!response.ok) throw new Error('Failed to load data');
213
+ return response.json();
214
+ })
215
+ .then((data) => {
216
+ setSlides(data);
217
+ setLoading(false);
218
+ })
219
+ .catch((err) => {
220
+ setError(err.message);
221
+ setLoading(false);
222
+ });
223
+ }, []);
224
+
225
+ if (loading) return <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>;
226
+ if (error) return <div style={{ textAlign: 'center', padding: '20px', color: 'red' }}>Error: {error}</div>;
227
+
228
+ return (
229
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
230
+ <h1 style={{ textAlign: 'center', padding: '20px' }}>JSON File Data Example</h1>
231
+ <div style={{ flex: 1 }}>
232
+ <AwesomeCoverflowCarousel
233
+ data={slides}
234
+ theme="light"
235
+ autoRotate={true}
236
+ rotationSpeed={3000}
237
+ onFocusChange={(index) => console.log('Focused item:', index)}
238
+ />
239
+ </div>
240
+ </div>
241
+ );
242
+ }
243
+ ```
244
+
245
+ **Sample `carousel-data.json` (place in `public` folder):**
246
+
247
+ ```json
248
+ [
249
+ {
250
+ "title": "Portfolio Project 1",
251
+ "description": "Award-winning design system",
252
+ "image": "https://images.unsplash.com/photo-1561070791-2526d30994b5?w=500&h=300&fit=crop",
253
+ "tag": "Design",
254
+ "color": "#1e3a8a"
255
+ },
256
+ {
257
+ "title": "Portfolio Project 2",
258
+ "description": "Enterprise web application",
259
+ "image": "https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=500&h=300&fit=crop",
260
+ "tag": "Development",
261
+ "color": "#064e3b"
262
+ },
263
+ {
264
+ "title": "Portfolio Project 3",
265
+ "description": "Mobile app with 10M+ downloads",
266
+ "image": "https://images.unsplash.com/photo-1560807707-38cc612d91b3?w=500&h=300&fit=crop",
267
+ "tag": "Mobile",
268
+ "color": "#5b1f39"
269
+ },
270
+ {
271
+ "title": "Portfolio Project 4",
272
+ "description": "Real-time data visualization",
273
+ "image": "https://images.unsplash.com/photo-1516321295223-4f2d3f2cf1e1?w=500&h=300&fit=crop",
274
+ "tag": "Analytics",
275
+ "color": "#78350f"
276
+ }
277
+ ]
278
+ ```
279
+
280
+ ### Example 3: REST API Data Source
281
+
282
+ Fetch carousel data from a REST API:
283
+
284
+ ```jsx
285
+ import { useEffect, useState } from 'react';
286
+ import { AwesomeCoverflowCarousel } from 'awesome-coverflow-carousel';
287
+ import 'awesome-coverflow-carousel/dist/style.css';
288
+
289
+ export default function RESTAPIExample() {
290
+ const [slides, setSlides] = useState([]);
291
+ const [loading, setLoading] = useState(true);
292
+ const [error, setError] = useState(null);
293
+ const [focusedItem, setFocusedItem] = useState(null);
294
+
295
+ useEffect(() => {
296
+ // Fetch from a REST API endpoint
297
+ fetch('https://api.example.com/carousel-items')
298
+ .then((response) => {
299
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
300
+ return response.json();
301
+ })
302
+ .then((data) => {
303
+ // Transform API response to match SlideData format
304
+ const transformedData = data.map((item) => ({
305
+ title: item.name || item.title,
306
+ description: item.summary || item.description,
307
+ image: item.thumbnail || item.image,
308
+ tag: item.category || item.type,
309
+ color: item.accentColor,
310
+ onClick: () => console.log(`Clicked: ${item.id}`)
311
+ }));
312
+ setSlides(transformedData);
313
+ setLoading(false);
314
+ })
315
+ .catch((err) => {
316
+ setError(err.message);
317
+ setLoading(false);
318
+ });
319
+ }, []);
320
+
321
+ const handleFocusChange = (index) => {
322
+ setFocusedItem(slides[index] || null);
323
+ console.log(`Focused on: ${slides[index]?.title}`);
324
+ };
325
+
326
+ if (loading) {
327
+ return (
328
+ <div style={{ textAlign: 'center', padding: '20px', color: '#999' }}>
329
+ Loading carousel data...
330
+ </div>
331
+ );
332
+ }
333
+
334
+ if (error) {
335
+ return (
336
+ <div style={{ textAlign: 'center', padding: '20px', color: 'red' }}>
337
+ Error loading data: {error}
338
+ </div>
339
+ );
340
+ }
341
+
342
+ return (
343
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
344
+ <h1 style={{ textAlign: 'center', padding: '20px' }}>REST API Data Example</h1>
345
+
346
+ {focusedItem && (
347
+ <div style={{
348
+ textAlign: 'center',
349
+ padding: '10px 20px',
350
+ backgroundColor: 'rgba(0, 245, 255, 0.1)',
351
+ borderBottom: '1px solid rgba(0, 245, 255, 0.2)',
352
+ }}>
353
+ <p>Currently viewing: <strong>{focusedItem.title}</strong></p>
354
+ {focusedItem.description && <p style={{ fontSize: '0.9em', color: '#aaa' }}>{focusedItem.description}</p>}
355
+ </div>
356
+ )}
357
+
358
+ <div style={{ flex: 1 }}>
359
+ <AwesomeCoverflowCarousel
360
+ data={slides}
361
+ theme="neon"
362
+ autoRotate={false}
363
+ friction={0.85}
364
+ perspective={1200}
365
+ focusGlow={true}
366
+ onFocusChange={handleFocusChange}
367
+ />
368
+ </div>
369
+
370
+ <div style={{
371
+ textAlign: 'center',
372
+ padding: '15px',
373
+ fontSize: '0.85em',
374
+ color: '#888',
375
+ borderTop: '1px solid rgba(255, 255, 255, 0.1)',
376
+ }}>
377
+ Use arrow keys or drag to navigate • Current count: {slides.length} items
378
+ </div>
379
+ </div>
380
+ );
381
+ }
382
+ ```
383
+
384
+ ## Customization Examples
385
+
386
+ ### Custom Styling with Themes
387
+
388
+ ```jsx
389
+ import { AwesomeCoverflowCarousel } from 'awesome-coverflow-carousel';
390
+ import 'awesome-coverflow-carousel/dist/style.css';
391
+
392
+ export default function CustomizedCarousel() {
393
+ const carouselContainer = {
394
+ width: '100%',
395
+ height: '100vh',
396
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
397
+ };
398
+
399
+ const slides = [/* your slides */];
400
+
401
+ return (
402
+ <div style={carouselContainer}>
403
+ <AwesomeCoverflowCarousel
404
+ data={slides}
405
+ theme="glass"
406
+ autoRotate={true}
407
+ rotationSpeed={3500}
408
+ friction={0.90}
409
+ perspective={1300}
410
+ focusGlow={true}
411
+ onFocusChange={(index) => {
412
+ // Custom handler
413
+ }}
414
+ />
415
+ </div>
416
+ );
417
+ }
418
+ ```
419
+
420
+ ### Controlled Carousel with External Controls
421
+
422
+ ```jsx
423
+ import { useRef, useState } from 'react';
424
+ import { AwesomeCoverflowCarousel } from 'awesome-coverflow-carousel';
425
+ import 'awesome-coverflow-carousel/dist/style.css';
426
+
427
+ export default function ControlledCarousel() {
428
+ const carouselRef = useRef(null);
429
+ const [focusedIndex, setFocusedIndex] = useState(0);
430
+
431
+ const slides = [
432
+ { title: 'Slide 1', description: 'First', image: 'url1.jpg' },
433
+ { title: 'Slide 2', description: 'Second', image: 'url2.jpg' },
434
+ { title: 'Slide 3', description: 'Third', image: 'url3.jpg' },
435
+ ];
436
+
437
+ return (
438
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
439
+ <div style={{ flex: 1 }}>
440
+ <AwesomeCoverflowCarousel
441
+ ref={carouselRef}
442
+ data={slides}
443
+ theme="dark"
444
+ onFocusChange={setFocusedIndex}
445
+ />
446
+ </div>
447
+
448
+ <div style={{ display: 'flex', gap: '10px', justifyContent: 'center', padding: '20px' }}>
449
+ <button onClick={() => {/* prev */}}>← Previous</button>
450
+ <span>{focusedIndex + 1} / {slides.length}</span>
451
+ <button onClick={() => {/* next */}}>Next →</button>
452
+ </div>
453
+ </div>
454
+ );
455
+ }
456
+ ```
457
+
458
+ ## Interaction Methods
459
+
460
+ ### Mouse Interactions
461
+ - **Drag**: Click and drag left/right to rotate the carousel
462
+ - **Click**: Click on a side item to bring it to center
463
+
464
+ ### Keyboard Interactions
465
+ - **Arrow Left**: Rotate to previous item
466
+ - **Arrow Right**: Rotate to next item
467
+
468
+ ### Mouse Events
469
+ - **Hover**: Pauses auto-rotation when hovering over the carousel
470
+ - **Leave**: Resumes auto-rotation when mouse leaves
471
+
472
+ ## Performance Tips
473
+
474
+ 1. **Optimize Images**: Use optimized image URLs for better performance
475
+ 2. **Lazy Loading**: Load large datasets progressively
476
+ 3. **Memoize Callbacks**: Use `useCallback` for `onFocusChange` handlers
477
+ 4. **Responsive Container**: Set appropriate dimensions for different screen sizes
478
+
479
+ ```jsx
480
+ // Example with responsive sizing
481
+ <div style={{
482
+ width: '100%',
483
+ height: window.innerWidth < 768 ? '60vh' : '100vh'
484
+ }}>
485
+ <AwesomeCoverflowCarousel data={slides} />
486
+ </div>
487
+ ```
488
+
489
+ ## Styling
490
+
491
+ The component comes with built-in styles. Import the CSS file:
492
+
493
+ ```jsx
494
+ import 'awesome-coverflow-carousel/dist/style.css';
495
+ ```
496
+
497
+ All theme colors and styles are defined in the included CSS. You can override default styles with custom CSS classes:
498
+
499
+ ```css
500
+ /* Override carousel styles */
501
+ .custom-carousel {
502
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
503
+ }
504
+ ```
505
+
506
+ ```jsx
507
+ <AwesomeCoverflowCarousel
508
+ data={slides}
509
+ className="custom-carousel"
510
+ />
511
+ ```
512
+
513
+ ## Browser Support
514
+
515
+ - Chrome/Edge (latest)
516
+ - Firefox (latest)
517
+ - Safari (latest)
518
+ - Mobile browsers (iOS Safari, Chrome Mobile)
519
+
520
+ ## API Reference
521
+
522
+ ### Component Props (Detailed)
523
+
524
+ #### `data: SlideData[]` (Required)
525
+ Array of slide objects. Each object must have at least a `title` property. See [Data Format](#data-format) above.
526
+
527
+ #### `autoRotate: boolean` (Default: `true`)
528
+ When enabled, the carousel automatically rotates to the next item after `rotationSpeed` milliseconds.
529
+
530
+ #### `rotationSpeed: number` (Default: `2800`)
531
+ Time in milliseconds between auto-rotations. Only applies if `autoRotate` is `true`.
532
+
533
+ #### `friction: number` (Default: `0.88`)
534
+ Controls how quickly animations decelerate. Range: 0-1
535
+ - `0.8` - More responsive, snappier animations
536
+ - `0.88` - Default, balanced feel
537
+ - `0.95` - Slower, smoother animations
538
+
539
+ #### `focusGlow: boolean` (Default: `true`)
540
+ Displays a glowing effect around the currently focused card. The glow color matches the selected theme.
541
+
542
+ #### `theme: 'dark' | 'light' | 'neon' | 'glass'` (Default: `'dark'`)
543
+ Selects the visual appearance of the carousel. See [Available Themes](#available-themes).
544
+
545
+ #### `perspective: number` (Default: `1100`)
546
+ Controls the 3D perspective depth in pixels. Higher values create less dramatic 3D effects.
547
+ - `800` - Strong 3D effect, cards spread wider
548
+ - `1100` - Default, balanced 3D
549
+ - `1500` - Subtle 3D, cards closer together
550
+
551
+ #### `onFocusChange: (index: number) => void`
552
+ Callback function fired whenever the focused item changes. Receives the index of the newly focused item.
553
+
554
+ #### `className: string`
555
+ Custom CSS class applied to the carousel container for additional customization.
556
+
557
+ ## Troubleshooting
558
+
559
+ ### Carousel not rotating
560
+ - Check that `autoRotate` is set to `true`
561
+ - Verify `rotationSpeed` is not too high (should be in milliseconds)
562
+ - Ensure the data array has at least 2 items
563
+
564
+ ### Images not displaying
565
+ - Verify image URLs are accessible and correct
566
+ - Check browser console for CORS errors
567
+ - Use absolute URLs for remote images
568
+
569
+ ### 3D effects not visible
570
+ - Ensure CSS is imported: `import 'awesome-coverflow-carousel/dist/style.css'`
571
+ - Check that `perspective` prop is not set too high
572
+ - Verify browser supports 3D transforms (all modern browsers)
573
+
574
+ ### Performance issues on mobile
575
+ - Reduce the number of images or use smaller dimensions
576
+ - Set `autoRotate={false}` if performance is critical
577
+ - Use optimized/compressed images
578
+
@@ -0,0 +1,37 @@
1
+ [
2
+ {
3
+ "title": "Portfolio Project 1",
4
+ "description": "Award-winning design system",
5
+ "image": "https://images.unsplash.com/photo-1561070791-2526d30994b5?w=500&h=300&fit=crop",
6
+ "tag": "Design",
7
+ "color": "#1e3a8a"
8
+ },
9
+ {
10
+ "title": "Portfolio Project 2",
11
+ "description": "Enterprise web application",
12
+ "image": "https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=500&h=300&fit=crop",
13
+ "tag": "Development",
14
+ "color": "#064e3b"
15
+ },
16
+ {
17
+ "title": "Portfolio Project 3",
18
+ "description": "Mobile app with 10M+ downloads",
19
+ "image": "https://images.unsplash.com/photo-1560807707-38cc612d91b3?w=500&h=300&fit=crop",
20
+ "tag": "Mobile",
21
+ "color": "#5b1f39"
22
+ },
23
+ {
24
+ "title": "Portfolio Project 4",
25
+ "description": "Real-time data visualization",
26
+ "image": "https://images.unsplash.com/photo-1516321295223-4f2d3f2cf1e1?w=500&h=300&fit=crop",
27
+ "tag": "Analytics",
28
+ "color": "#78350f"
29
+ },
30
+ {
31
+ "title": "E-Commerce Platform",
32
+ "description": "Full-stack shopping experience",
33
+ "image": "https://images.unsplash.com/photo-1460925895917-adf4e565e6c1?w=500&h=300&fit=crop",
34
+ "tag": "Commerce",
35
+ "color": "#4c0519"
36
+ }
37
+ ]
package/dist/index.js ADDED
@@ -0,0 +1,310 @@
1
+ import { jsx as c, jsxs as A } from "react/jsx-runtime";
2
+ import { useRef as d, useState as tt, useCallback as v, useEffect as z, useMemo as rt } from "react";
3
+ const et = {
4
+ name: "dark",
5
+ background: "transparent",
6
+ cardBg: "rgba(10, 15, 30, 0.85)",
7
+ cardBorder: "rgba(0, 245, 255, 0.2)",
8
+ cardText: "#f1f5f9",
9
+ cardSubtext: "#94a3b8",
10
+ focusGlow: "0 0 40px rgba(0, 245, 255, 0.5), 0 0 80px rgba(0, 245, 255, 0.2)",
11
+ navBg: "rgba(0, 245, 255, 0.1)",
12
+ navText: "#00f5ff",
13
+ indicatorActive: "#00f5ff",
14
+ indicatorInactive: "rgba(0, 245, 255, 0.25)"
15
+ }, nt = {
16
+ name: "light",
17
+ background: "transparent",
18
+ cardBg: "rgba(255, 255, 255, 0.92)",
19
+ cardBorder: "rgba(124, 58, 237, 0.25)",
20
+ cardText: "#1e293b",
21
+ cardSubtext: "#64748b",
22
+ focusGlow: "0 0 40px rgba(124, 58, 237, 0.35), 0 8px 32px rgba(0,0,0,0.15)",
23
+ navBg: "rgba(124, 58, 237, 0.1)",
24
+ navText: "#7c3aed",
25
+ indicatorActive: "#7c3aed",
26
+ indicatorInactive: "rgba(124, 58, 237, 0.2)"
27
+ }, at = {
28
+ name: "neon",
29
+ background: "transparent",
30
+ cardBg: "rgba(5, 0, 20, 0.9)",
31
+ cardBorder: "rgba(255, 0, 255, 0.4)",
32
+ cardText: "#fff",
33
+ cardSubtext: "#f0abfc",
34
+ focusGlow: "0 0 50px rgba(255,0,255,0.6), 0 0 100px rgba(0,255,255,0.3)",
35
+ navBg: "rgba(255, 0, 255, 0.1)",
36
+ navText: "#ff00ff",
37
+ indicatorActive: "#ff00ff",
38
+ indicatorInactive: "rgba(255,0,255,0.2)"
39
+ }, ot = {
40
+ name: "glass",
41
+ background: "transparent",
42
+ cardBg: "rgba(255, 255, 255, 0.08)",
43
+ cardBorder: "rgba(255, 255, 255, 0.2)",
44
+ cardText: "#ffffff",
45
+ cardSubtext: "rgba(255,255,255,0.65)",
46
+ focusGlow: "0 8px 32px rgba(255,255,255,0.15), inset 0 1px 0 rgba(255,255,255,0.3)",
47
+ navBg: "rgba(255,255,255,0.1)",
48
+ navText: "#ffffff",
49
+ indicatorActive: "#ffffff",
50
+ indicatorInactive: "rgba(255,255,255,0.3)"
51
+ }, W = {
52
+ dark: et,
53
+ light: nt,
54
+ neon: at,
55
+ glass: ot
56
+ }, j = 220, H = 300, X = 155, it = 55, Y = 0.8, ct = 0.64, st = 0.72, dt = 0.4, lt = 3.4;
57
+ function bt({
58
+ data: e,
59
+ autoRotate: s = !0,
60
+ rotationSpeed: l = 2800,
61
+ friction: n = 0.88,
62
+ focusGlow: h = !0,
63
+ theme: q = "dark",
64
+ perspective: F = 1100,
65
+ onFocusChange: f,
66
+ className: U
67
+ }) {
68
+ const o = e.length, Z = W[q] || W.dark, p = d(0), g = d(0), b = d(0), m = d(0), u = d(!1), G = d(0), L = d(0), k = d(null), S = d(!1), [T, I] = tt(0), M = v(() => {
69
+ if (u.current) return;
70
+ const t = p.current, a = g.current, i = a - t;
71
+ b.current = b.current * n + i * (1 - n) * 0.28;
72
+ const r = t + b.current;
73
+ if (p.current = r, I(r), Math.abs(i) < 8e-4 && Math.abs(b.current) < 8e-4) {
74
+ p.current = a, I(a);
75
+ return;
76
+ }
77
+ m.current = requestAnimationFrame(M);
78
+ }, [n]), y = v(() => {
79
+ cancelAnimationFrame(m.current), m.current = requestAnimationFrame(M);
80
+ }, [M]), x = v((t) => {
81
+ g.current += t, b.current = 0, y();
82
+ const a = (Math.round(g.current) % o + o) % o;
83
+ f == null || f(a);
84
+ }, [o, y, f]);
85
+ z(() => {
86
+ if (!s) return;
87
+ const t = () => {
88
+ k.current = setTimeout(() => {
89
+ !u.current && !S.current && x(1), t();
90
+ }, l);
91
+ };
92
+ return t(), () => {
93
+ k.current && clearTimeout(k.current);
94
+ };
95
+ }, [s, l, x]);
96
+ const K = v((t) => {
97
+ u.current = !0, G.current = t.clientX, L.current = p.current, b.current = 0, cancelAnimationFrame(m.current), t.target.setPointerCapture(t.pointerId);
98
+ }, []), N = v((t) => {
99
+ if (!u.current) return;
100
+ const i = -((t.clientX - G.current) / X), r = L.current + i;
101
+ p.current = r, g.current = r, I(r);
102
+ }, []), V = v((t) => {
103
+ if (!u.current) return;
104
+ u.current = !1, g.current = Math.round(p.current), y();
105
+ const a = (Math.round(g.current) % o + o) % o;
106
+ f == null || f(a);
107
+ }, [o, y, f]);
108
+ z(() => {
109
+ const t = (a) => {
110
+ a.key === "ArrowLeft" && x(-1), a.key === "ArrowRight" && x(1);
111
+ };
112
+ return window.addEventListener("keydown", t), () => window.removeEventListener("keydown", t);
113
+ }, [x]), z(() => () => cancelAnimationFrame(m.current), []);
114
+ const J = (Math.round(T) % o + o) % o, Q = rt(() => e.map((t, a) => {
115
+ let i = a - T;
116
+ i = i - Math.round(i / o) * o;
117
+ const r = Math.abs(i), R = i >= 0 ? 1 : -1, B = r < lt, E = R * Math.min(it + r * 8, 85), $ = i * X, C = Math.max(0, 100 - r * 70), w = r < 0.05 ? 1 : r < 1.5 ? 1 - (1 - Y) * r : Math.max(ct, Y - (r - 1) * 0.1), D = r < 0.05 ? 1 : r < 1.5 ? 1 - (1 - st) * r : Math.max(0, dt - (r - 2) * 0.25), _ = Math.round(100 - r * 20);
118
+ return { slide: t, i: a, visible: B, rotY: r < 0.05 ? 0 : E, translateX: $, translateZ: C, scale: w, opacity: D, zIndex: _, dist: i };
119
+ }), [e, T, o]);
120
+ return /* @__PURE__ */ c(
121
+ "div",
122
+ {
123
+ className: U,
124
+ style: {
125
+ position: "relative",
126
+ width: "100%",
127
+ height: "100%",
128
+ cursor: u.current ? "grabbing" : "grab",
129
+ userSelect: "none",
130
+ outline: "none",
131
+ overflow: "hidden"
132
+ },
133
+ onPointerDown: K,
134
+ onPointerMove: N,
135
+ onPointerUp: V,
136
+ onMouseEnter: () => {
137
+ S.current = !0;
138
+ },
139
+ onMouseLeave: () => {
140
+ S.current = !1;
141
+ },
142
+ tabIndex: 0,
143
+ role: "region",
144
+ "aria-label": "Coverflow Carousel",
145
+ children: /* @__PURE__ */ c("div", { style: {
146
+ position: "absolute",
147
+ inset: 0,
148
+ perspective: `${F}px`,
149
+ perspectiveOrigin: "50% 50%",
150
+ display: "flex",
151
+ alignItems: "center",
152
+ justifyContent: "center"
153
+ }, children: /* @__PURE__ */ c("div", { style: { position: "relative", width: 0, height: 0, transformStyle: "preserve-3d" }, children: Q.map(({ slide: t, i: a, visible: i, rotY: r, translateX: R, translateZ: B, scale: E, opacity: $, zIndex: C, dist: w }) => {
154
+ if (!i) return null;
155
+ const D = a === J, _ = Math.abs(w);
156
+ return /* @__PURE__ */ c(
157
+ "div",
158
+ {
159
+ style: {
160
+ position: "absolute",
161
+ width: `${j}px`,
162
+ height: `${H}px`,
163
+ left: `${-j / 2}px`,
164
+ top: `${-H / 2}px`,
165
+ transform: `translateX(${R}px) translateZ(${B}px) rotateY(${r}deg) scale(${E})`,
166
+ opacity: $,
167
+ zIndex: C,
168
+ transition: u.current ? "none" : "transform 0.55s cubic-bezier(0.25,0.46,0.45,0.94), opacity 0.5s ease",
169
+ willChange: "transform, opacity",
170
+ cursor: "pointer"
171
+ },
172
+ onClick: () => {
173
+ var P, O;
174
+ _ > 0.3 ? x(Math.round(w)) : ((P = t.onClick) == null || P.call(t), (O = t.imageClick) == null || O.call(t));
175
+ },
176
+ children: /* @__PURE__ */ c(
177
+ ft,
178
+ {
179
+ slide: t,
180
+ isFocused: D,
181
+ focusGlow: h,
182
+ theme: Z
183
+ }
184
+ )
185
+ },
186
+ a
187
+ );
188
+ }) }) })
189
+ }
190
+ );
191
+ }
192
+ function ft({ slide: e, isFocused: s, focusGlow: l, theme: n }) {
193
+ const h = s && l ? n.focusGlow : void 0;
194
+ return /* @__PURE__ */ A("div", { style: {
195
+ width: "100%",
196
+ height: "100%",
197
+ borderRadius: "18px",
198
+ overflow: "hidden",
199
+ position: "relative",
200
+ background: n.cardBg,
201
+ border: `1.5px solid ${s ? n.indicatorActive : n.cardBorder}`,
202
+ boxShadow: h || (s ? "0 24px 64px rgba(0,0,0,0.65), 0 8px 24px rgba(0,0,0,0.4)" : "0 8px 32px rgba(0,0,0,0.4)"),
203
+ backdropFilter: "blur(12px)",
204
+ WebkitBackdropFilter: "blur(12px)",
205
+ transition: "border-color 0.4s, box-shadow 0.4s",
206
+ display: "flex",
207
+ flexDirection: "column"
208
+ }, children: [
209
+ /* @__PURE__ */ A("div", { style: { flex: "0 0 65%", position: "relative", overflow: "hidden" }, children: [
210
+ e.image ? /* @__PURE__ */ c(
211
+ "img",
212
+ {
213
+ src: e.image,
214
+ alt: e.title,
215
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
216
+ }
217
+ ) : /* @__PURE__ */ c(ut, { title: e.title, color: e.color, accent: n.indicatorActive }),
218
+ e.tag && /* @__PURE__ */ c("span", { style: {
219
+ position: "absolute",
220
+ top: 10,
221
+ right: 10,
222
+ background: n.indicatorActive,
223
+ color: "#000",
224
+ fontSize: "9px",
225
+ fontWeight: 800,
226
+ letterSpacing: "0.08em",
227
+ padding: "3px 9px",
228
+ borderRadius: "100px",
229
+ fontFamily: "var(--font-display)",
230
+ textTransform: "uppercase"
231
+ }, children: e.tag }),
232
+ /* @__PURE__ */ c("div", { style: {
233
+ position: "absolute",
234
+ bottom: 0,
235
+ left: 0,
236
+ right: 0,
237
+ height: "50%",
238
+ background: `linear-gradient(to bottom, transparent, ${n.cardBg})`
239
+ } })
240
+ ] }),
241
+ /* @__PURE__ */ A("div", { style: {
242
+ flex: 1,
243
+ padding: "12px 16px 16px",
244
+ display: "flex",
245
+ flexDirection: "column",
246
+ justifyContent: "center",
247
+ gap: "5px"
248
+ }, children: [
249
+ /* @__PURE__ */ c("div", { style: {
250
+ fontFamily: "var(--font-display)",
251
+ fontWeight: 800,
252
+ fontSize: "15px",
253
+ color: n.cardText,
254
+ lineHeight: 1.25,
255
+ letterSpacing: "-0.02em"
256
+ }, children: e.title }),
257
+ e.description && /* @__PURE__ */ c("div", { style: {
258
+ fontFamily: "var(--font-body)",
259
+ fontSize: "11px",
260
+ color: n.cardSubtext,
261
+ lineHeight: 1.5,
262
+ fontWeight: 300
263
+ }, children: e.description }),
264
+ s && /* @__PURE__ */ c("div", { style: {
265
+ marginTop: "6px",
266
+ padding: "7px 16px",
267
+ borderRadius: "100px",
268
+ background: n.indicatorActive,
269
+ color: "#000",
270
+ fontSize: "10px",
271
+ fontWeight: 800,
272
+ fontFamily: "var(--font-display)",
273
+ letterSpacing: "0.05em",
274
+ textTransform: "uppercase",
275
+ cursor: "pointer",
276
+ alignSelf: "flex-start"
277
+ }, children: "Learn More →" })
278
+ ] })
279
+ ] });
280
+ }
281
+ function ut({ title: e, color: s, accent: l }) {
282
+ const n = ["#020d2e", "#1e1b4b", "#0c1445", "#1a0533", "#0d2137", "#1f1235", "#0a1400", "#1a1000", "#001820", "#160028"], h = s || n[e.charCodeAt(0) % n.length];
283
+ return /* @__PURE__ */ A("div", { style: {
284
+ width: "100%",
285
+ height: "100%",
286
+ background: `linear-gradient(145deg, ${h} 0%, ${l}22 100%)`,
287
+ display: "flex",
288
+ alignItems: "center",
289
+ justifyContent: "center",
290
+ position: "relative"
291
+ }, children: [
292
+ /* @__PURE__ */ c("div", { style: {
293
+ position: "absolute",
294
+ inset: 0,
295
+ background: `radial-gradient(circle at 60% 40%, ${l}38, transparent 65%)`
296
+ } }),
297
+ /* @__PURE__ */ c("span", { style: {
298
+ fontFamily: "var(--font-display)",
299
+ fontWeight: 900,
300
+ fontSize: "52px",
301
+ color: l,
302
+ opacity: 0.88,
303
+ position: "relative",
304
+ zIndex: 1
305
+ }, children: e.slice(0, 2).toUpperCase() })
306
+ ] });
307
+ }
308
+ export {
309
+ bt as AwesomeCoverflowCarousel
310
+ };
@@ -0,0 +1 @@
1
+ (function(d,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],t):(d=typeof globalThis<"u"?globalThis:d||self,t(d.AwesomeCoverflowCarousel={},d.jsxRuntime,d.React))})(this,(function(d,t,n){"use strict";const j={dark:{name:"dark",background:"transparent",cardBg:"rgba(10, 15, 30, 0.85)",cardBorder:"rgba(0, 245, 255, 0.2)",cardText:"#f1f5f9",cardSubtext:"#94a3b8",focusGlow:"0 0 40px rgba(0, 245, 255, 0.5), 0 0 80px rgba(0, 245, 255, 0.2)",navBg:"rgba(0, 245, 255, 0.1)",navText:"#00f5ff",indicatorActive:"#00f5ff",indicatorInactive:"rgba(0, 245, 255, 0.25)"},light:{name:"light",background:"transparent",cardBg:"rgba(255, 255, 255, 0.92)",cardBorder:"rgba(124, 58, 237, 0.25)",cardText:"#1e293b",cardSubtext:"#64748b",focusGlow:"0 0 40px rgba(124, 58, 237, 0.35), 0 8px 32px rgba(0,0,0,0.15)",navBg:"rgba(124, 58, 237, 0.1)",navText:"#7c3aed",indicatorActive:"#7c3aed",indicatorInactive:"rgba(124, 58, 237, 0.2)"},neon:{name:"neon",background:"transparent",cardBg:"rgba(5, 0, 20, 0.9)",cardBorder:"rgba(255, 0, 255, 0.4)",cardText:"#fff",cardSubtext:"#f0abfc",focusGlow:"0 0 50px rgba(255,0,255,0.6), 0 0 100px rgba(0,255,255,0.3)",navBg:"rgba(255, 0, 255, 0.1)",navText:"#ff00ff",indicatorActive:"#ff00ff",indicatorInactive:"rgba(255,0,255,0.2)"},glass:{name:"glass",background:"transparent",cardBg:"rgba(255, 255, 255, 0.08)",cardBorder:"rgba(255, 255, 255, 0.2)",cardText:"#ffffff",cardSubtext:"rgba(255,255,255,0.65)",focusGlow:"0 8px 32px rgba(255,255,255,0.15), inset 0 1px 0 rgba(255,255,255,0.3)",navBg:"rgba(255,255,255,0.1)",navText:"#ffffff",indicatorActive:"#ffffff",indicatorInactive:"rgba(255,255,255,0.3)"}},_=220,P=300,z=155,X=55,G=.8,Y=.64,q=.72,F=.4,U=3.4;function Z({data:o,autoRotate:l=!0,rotationSpeed:f=2800,friction:a=.88,focusGlow:v=!0,theme:V="dark",perspective:J=1100,onFocusChange:u,className:Q}){const c=o.length,ee=j[V]||j.dark,g=n.useRef(0),b=n.useRef(0),x=n.useRef(0),y=n.useRef(0),p=n.useRef(!1),L=n.useRef(0),O=n.useRef(0),w=n.useRef(null),A=n.useRef(!1),[T,S]=n.useState(0),C=n.useCallback(()=>{if(p.current)return;const e=g.current,i=b.current,s=i-e;x.current=x.current*a+s*(1-a)*.28;const r=e+x.current;if(g.current=r,S(r),Math.abs(s)<8e-4&&Math.abs(x.current)<8e-4){g.current=i,S(i);return}y.current=requestAnimationFrame(C)},[a]),m=n.useCallback(()=>{cancelAnimationFrame(y.current),y.current=requestAnimationFrame(C)},[C]),h=n.useCallback(e=>{b.current+=e,x.current=0,m();const i=(Math.round(b.current)%c+c)%c;u==null||u(i)},[c,m,u]);n.useEffect(()=>{if(!l)return;const e=()=>{w.current=setTimeout(()=>{!p.current&&!A.current&&h(1),e()},f)};return e(),()=>{w.current&&clearTimeout(w.current)}},[l,f,h]);const te=n.useCallback(e=>{p.current=!0,L.current=e.clientX,O.current=g.current,x.current=0,cancelAnimationFrame(y.current),e.target.setPointerCapture(e.pointerId)},[]),re=n.useCallback(e=>{if(!p.current)return;const s=-((e.clientX-L.current)/z),r=O.current+s;g.current=r,b.current=r,S(r)},[]),ne=n.useCallback(e=>{if(!p.current)return;p.current=!1,b.current=Math.round(g.current),m();const i=(Math.round(b.current)%c+c)%c;u==null||u(i)},[c,m,u]);n.useEffect(()=>{const e=i=>{i.key==="ArrowLeft"&&h(-1),i.key==="ArrowRight"&&h(1)};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[h]),n.useEffect(()=>()=>cancelAnimationFrame(y.current),[]);const oe=(Math.round(T)%c+c)%c,ae=n.useMemo(()=>o.map((e,i)=>{let s=i-T;s=s-Math.round(s/c)*c;const r=Math.abs(s),I=s>=0?1:-1,M=r<U,B=I*Math.min(X+r*8,85),E=s*z,$=Math.max(0,100-r*70),k=r<.05?1:r<1.5?1-(1-G)*r:Math.max(Y,G-(r-1)*.1),D=r<.05?1:r<1.5?1-(1-q)*r:Math.max(0,F-(r-2)*.25),R=Math.round(100-r*20);return{slide:e,i,visible:M,rotY:r<.05?0:B,translateX:E,translateZ:$,scale:k,opacity:D,zIndex:R,dist:s}}),[o,T,c]);return t.jsx("div",{className:Q,style:{position:"relative",width:"100%",height:"100%",cursor:p.current?"grabbing":"grab",userSelect:"none",outline:"none",overflow:"hidden"},onPointerDown:te,onPointerMove:re,onPointerUp:ne,onMouseEnter:()=>{A.current=!0},onMouseLeave:()=>{A.current=!1},tabIndex:0,role:"region","aria-label":"Coverflow Carousel",children:t.jsx("div",{style:{position:"absolute",inset:0,perspective:`${J}px`,perspectiveOrigin:"50% 50%",display:"flex",alignItems:"center",justifyContent:"center"},children:t.jsx("div",{style:{position:"relative",width:0,height:0,transformStyle:"preserve-3d"},children:ae.map(({slide:e,i,visible:s,rotY:r,translateX:I,translateZ:M,scale:B,opacity:E,zIndex:$,dist:k})=>{if(!s)return null;const D=i===oe,R=Math.abs(k);return t.jsx("div",{style:{position:"absolute",width:`${_}px`,height:`${P}px`,left:`${-_/2}px`,top:`${-P/2}px`,transform:`translateX(${I}px) translateZ(${M}px) rotateY(${r}deg) scale(${B})`,opacity:E,zIndex:$,transition:p.current?"none":"transform 0.55s cubic-bezier(0.25,0.46,0.45,0.94), opacity 0.5s ease",willChange:"transform, opacity",cursor:"pointer"},onClick:()=>{var W,H;R>.3?h(Math.round(k)):((W=e.onClick)==null||W.call(e),(H=e.imageClick)==null||H.call(e))},children:t.jsx(K,{slide:e,isFocused:D,focusGlow:v,theme:ee})},i)})})})})}function K({slide:o,isFocused:l,focusGlow:f,theme:a}){const v=l&&f?a.focusGlow:void 0;return t.jsxs("div",{style:{width:"100%",height:"100%",borderRadius:"18px",overflow:"hidden",position:"relative",background:a.cardBg,border:`1.5px solid ${l?a.indicatorActive:a.cardBorder}`,boxShadow:v||(l?"0 24px 64px rgba(0,0,0,0.65), 0 8px 24px rgba(0,0,0,0.4)":"0 8px 32px rgba(0,0,0,0.4)"),backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)",transition:"border-color 0.4s, box-shadow 0.4s",display:"flex",flexDirection:"column"},children:[t.jsxs("div",{style:{flex:"0 0 65%",position:"relative",overflow:"hidden"},children:[o.image?t.jsx("img",{src:o.image,alt:o.title,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}}):t.jsx(N,{title:o.title,color:o.color,accent:a.indicatorActive}),o.tag&&t.jsx("span",{style:{position:"absolute",top:10,right:10,background:a.indicatorActive,color:"#000",fontSize:"9px",fontWeight:800,letterSpacing:"0.08em",padding:"3px 9px",borderRadius:"100px",fontFamily:"var(--font-display)",textTransform:"uppercase"},children:o.tag}),t.jsx("div",{style:{position:"absolute",bottom:0,left:0,right:0,height:"50%",background:`linear-gradient(to bottom, transparent, ${a.cardBg})`}})]}),t.jsxs("div",{style:{flex:1,padding:"12px 16px 16px",display:"flex",flexDirection:"column",justifyContent:"center",gap:"5px"},children:[t.jsx("div",{style:{fontFamily:"var(--font-display)",fontWeight:800,fontSize:"15px",color:a.cardText,lineHeight:1.25,letterSpacing:"-0.02em"},children:o.title}),o.description&&t.jsx("div",{style:{fontFamily:"var(--font-body)",fontSize:"11px",color:a.cardSubtext,lineHeight:1.5,fontWeight:300},children:o.description}),l&&t.jsx("div",{style:{marginTop:"6px",padding:"7px 16px",borderRadius:"100px",background:a.indicatorActive,color:"#000",fontSize:"10px",fontWeight:800,fontFamily:"var(--font-display)",letterSpacing:"0.05em",textTransform:"uppercase",cursor:"pointer",alignSelf:"flex-start"},children:"Learn More →"})]})]})}function N({title:o,color:l,accent:f}){const a=["#020d2e","#1e1b4b","#0c1445","#1a0533","#0d2137","#1f1235","#0a1400","#1a1000","#001820","#160028"],v=l||a[o.charCodeAt(0)%a.length];return t.jsxs("div",{style:{width:"100%",height:"100%",background:`linear-gradient(145deg, ${v} 0%, ${f}22 100%)`,display:"flex",alignItems:"center",justifyContent:"center",position:"relative"},children:[t.jsx("div",{style:{position:"absolute",inset:0,background:`radial-gradient(circle at 60% 40%, ${f}38, transparent 65%)`}}),t.jsx("span",{style:{fontFamily:"var(--font-display)",fontWeight:900,fontSize:"52px",color:f,opacity:.88,position:"relative",zIndex:1},children:o.slice(0,2).toUpperCase()})]})}d.AwesomeCoverflowCarousel=Z,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ :root{--awesome-carousel-dark-bg: #030712;--awesome-carousel-light-text: #f1f5f9;--awesome-carousel-secondary-text: #94a3b8;--awesome-carousel-cyan: #00f5ff;--awesome-carousel-violet: #7c3aed;--awesome-carousel-amber: #f59e0b;--awesome-carousel-card-dark-bg: rgba(10, 15, 30, .85);--awesome-carousel-card-dark-border: rgba(0, 245, 255, .2);--awesome-carousel-glow-dark: 0 0 40px rgba(0, 245, 255, .5), 0 0 80px rgba(0, 245, 255, .2);--awesome-carousel-nav-dark-bg: rgba(0, 245, 255, .1);--awesome-carousel-nav-dark-text: #00f5ff;--awesome-carousel-indicator-active-dark: #00f5ff;--awesome-carousel-indicator-inactive-dark: rgba(0, 245, 255, .25)}@media(prefers-color-scheme:light){:root{--awesome-carousel-dark-bg: #f8fafc;--awesome-carousel-light-text: #1e293b;--awesome-carousel-secondary-text: #64748b}}.awesome-carousel-root *,.awesome-carousel-root *:before,.awesome-carousel-root *:after{box-sizing:border-box;margin:0;padding:0}.awesome-carousel-root{position:relative;width:100%;height:100%;font-family:DM Sans,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.awesome-coverflow-carousel{position:relative;width:100%;height:100%;overflow:hidden;background:transparent;cursor:grab;-webkit-user-select:none;user-select:none;outline:none}.awesome-coverflow-carousel:active{cursor:grabbing}.awesome-coverflow-carousel[role=region]{outline:none}.awesome-coverflow-carousel:focus-visible{outline:2px solid var(--awesome-carousel-cyan);outline-offset:4px}.awesome-carousel-stage{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;perspective:1100px;perspective-origin:50% 50%;transform-style:preserve-3d}.awesome-carousel-stage__inner{position:relative;width:0;height:0;transform-style:preserve-3d}.awesome-carousel-card{position:absolute;width:220px;height:300px;border-radius:18px;overflow:hidden;will-change:transform,opacity;transform-style:preserve-3d;backface-visibility:hidden}.awesome-carousel-card--transition{transition:transform .55s cubic-bezier(.25,.46,.45,.94),opacity .5s ease}.awesome-carousel-card--no-transition{transition:none}.awesome-carousel-card:hover{z-index:1000!important}.awesome-carousel-card__content{width:100%;height:100%;display:flex;flex-direction:column;border-radius:18px;overflow:hidden;position:relative;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);transition:border-color .4s,box-shadow .4s}.awesome-carousel-card__content--dark{background:var(--awesome-carousel-card-dark-bg);border:1.5px solid var(--awesome-carousel-card-dark-border);color:var(--awesome-carousel-light-text);box-shadow:0 8px 32px #0006}.awesome-carousel-card__content--dark.focused{border-color:var(--awesome-carousel-indicator-active-dark);box-shadow:var(--awesome-carousel-glow-dark)}.awesome-carousel-card__content--light{background:#ffffffeb;border:1.5px solid rgba(124,58,237,.25);color:#1e293b;box-shadow:0 8px 32px #00000026}.awesome-carousel-card__content--light.focused{border-color:var(--awesome-carousel-violet);box-shadow:0 0 40px #7c3aed59,0 8px 32px #00000026}.awesome-carousel-card__content--neon{background:#050014e6;border:1.5px solid rgba(255,0,255,.4);color:#fff;box-shadow:0 8px 32px #0006}.awesome-carousel-card__content--neon.focused{border-color:#f0f;box-shadow:0 0 50px #f0f9,0 0 100px #00ffff4d}.awesome-carousel-card__content--glass{background:#ffffff14;border:1.5px solid rgba(255,255,255,.2);color:#fff;box-shadow:0 8px 32px #ffffff26,inset 0 1px #ffffff4d}.awesome-carousel-card__content--glass.focused{border-color:#fff;box-shadow:0 8px 32px #fff3,inset 0 1px #fff6}.awesome-carousel-card__image-area{flex:0 0 65%;position:relative;overflow:hidden;background:#0000004d}.awesome-carousel-card__image{width:100%;height:100%;object-fit:cover;display:block;transition:transform .3s ease}.awesome-carousel-card:hover .awesome-carousel-card__image{transform:scale(1.05)}.awesome-carousel-card__image-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#7c3aed33,#00f5ff33);color:#ffffff4d;font-size:2em}.awesome-carousel-card__text-area{flex:1;padding:16px 14px;display:flex;flex-direction:column;gap:6px;overflow:hidden}.awesome-carousel-card__title{font-size:14px;font-weight:600;line-height:1.4;text-transform:uppercase;letter-spacing:.5px;margin:0}.awesome-carousel-card__description{font-size:12px;line-height:1.3;margin:0;opacity:.8}.awesome-carousel-card__tag{display:inline-block;padding:4px 8px;border-radius:4px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.3px;width:fit-content;margin-top:auto}.awesome-carousel-card__content--dark .awesome-carousel-card__tag{background:var(--awesome-carousel-nav-dark-bg);color:var(--awesome-carousel-nav-dark-text)}.awesome-carousel-card__content--light .awesome-carousel-card__tag{background:#7c3aed1a;color:var(--awesome-carousel-violet)}.awesome-carousel-card__content--neon .awesome-carousel-card__tag{background:#ff00ff26;color:#f0f}.awesome-carousel-card__content--glass .awesome-carousel-card__tag{background:#ffffff26;color:#fff}.sphere-item{transition:transform .2s ease}.sphere-item--lift:hover{transform:translate(-50%,-52%)!important;filter:brightness(1.1)}.sphere-item--zoom:hover{transform:translate(-50%,-50%) scale(1.12)!important}.sphere-item--tilt:hover{transform:translate(-50%,-50%) rotateY(-5deg) rotateX(5deg)!important}.sphere-item:focus{outline:none}.sphere-item:focus-visible{outline:2px solid var(--awesome-carousel-cyan);outline-offset:4px;border-radius:16px}input[type=range]{-webkit-appearance:none;width:100%;height:4px;border-radius:2px;background:#ffffff1a;outline:none;cursor:pointer}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--awesome-carousel-cyan);cursor:pointer;transition:box-shadow .2s ease}input[type=range]::-webkit-slider-thumb:hover{box-shadow:0 0 10px var(--awesome-carousel-cyan)}input[type=range]::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--awesome-carousel-cyan);cursor:pointer;border:none;transition:box-shadow .2s ease}input[type=range]::-moz-range-thumb:hover{box-shadow:0 0 10px var(--awesome-carousel-cyan)}input[type=range]::-moz-range-track{background:transparent;border:none}input[type=range]::-moz-range-progress{background:var(--awesome-carousel-cyan);height:4px;border-radius:2px}@keyframes starfield{0%{transform:translateY(0)}to{transform:translateY(-50%)}}@keyframes pulseGlow{0%,to{opacity:.4;transform:scale(1)}50%{opacity:.8;transform:scale(1.05)}}@keyframes fadeUp{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}@keyframes rotate360{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes cardEntrance{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}@keyframes slideIn{0%{transform:translate(-20px);opacity:0}to{transform:translate(0);opacity:1}}.awesome-carousel-nav{display:flex;gap:10px;justify-content:center;padding:20px;background:transparent}.awesome-carousel-nav__button{padding:8px 16px;border:1px solid currentColor;border-radius:6px;background:transparent;color:inherit;cursor:pointer;font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;transition:all .3s ease;outline:none}.awesome-carousel-nav__button:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0003}.awesome-carousel-nav__button:active{transform:translateY(0)}.awesome-carousel-nav__button:focus-visible{outline:2px solid var(--awesome-carousel-cyan);outline-offset:2px}.awesome-carousel-nav--dark .awesome-carousel-nav__button{color:var(--awesome-carousel-nav-dark-text);border-color:var(--awesome-carousel-nav-dark-text)}.awesome-carousel-nav--dark .awesome-carousel-nav__button:hover{background:var(--awesome-carousel-nav-dark-bg)}.awesome-carousel-nav--light .awesome-carousel-nav__button{color:var(--awesome-carousel-violet);border-color:var(--awesome-carousel-violet)}.awesome-carousel-nav--light .awesome-carousel-nav__button:hover{background:#7c3aed1a}.awesome-carousel-indicators{display:flex;gap:8px;justify-content:center;padding:16px;background:transparent}.awesome-carousel-indicator{width:8px;height:8px;border-radius:50%;cursor:pointer;transition:all .3s ease;border:none;padding:0}.awesome-carousel-indicator:hover{transform:scale(1.3)}.awesome-carousel-indicator:focus-visible{outline:2px solid var(--awesome-carousel-cyan);outline-offset:2px}.awesome-carousel-indicators--dark .awesome-carousel-indicator{background:var(--awesome-carousel-indicator-inactive-dark)}.awesome-carousel-indicators--dark .awesome-carousel-indicator.active{background:var(--awesome-carousel-indicator-active-dark);box-shadow:0 0 10px var(--awesome-carousel-indicator-active-dark)}.awesome-carousel-indicators--light .awesome-carousel-indicator{background:#7c3aed33}.awesome-carousel-indicators--light .awesome-carousel-indicator.active{background:var(--awesome-carousel-violet);box-shadow:0 0 10px #7c3aed80}.awesome-carousel-indicators--neon .awesome-carousel-indicator{background:#f0f3}.awesome-carousel-indicators--neon .awesome-carousel-indicator.active{background:#f0f;box-shadow:0 0 10px #f0f}.awesome-carousel-indicators--glass .awesome-carousel-indicator{background:#ffffff4d}.awesome-carousel-indicators--glass .awesome-carousel-indicator.active{background:#fff;box-shadow:0 0 10px #fff9}.awesome-carousel-fade-enter{animation:fadeUp .3s ease-out}.awesome-carousel-card-entrance{animation:cardEntrance .4s cubic-bezier(.34,1.56,.64,1)}.awesome-carousel-slide-in{animation:slideIn .3s ease-out}@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}.awesome-carousel-card--transition{transition:none}}@media(max-width:768px){.awesome-carousel-card{width:180px;height:240px}.awesome-carousel-card__title{font-size:13px}.awesome-carousel-card__description{font-size:11px}.awesome-carousel-nav{padding:15px;gap:8px}.awesome-carousel-nav__button{padding:6px 12px;font-size:12px}.awesome-carousel-indicators{gap:6px;padding:12px}.awesome-carousel-indicator{width:6px;height:6px}}@media(max-width:480px){.awesome-carousel-card{width:150px;height:200px}.awesome-carousel-card__image-area{flex:0 0 60%}.awesome-carousel-card__text-area{padding:12px 10px;gap:4px}.awesome-carousel-card__title{font-size:12px}.awesome-carousel-card__description{font-size:10px}.awesome-carousel-card__tag{font-size:9px;padding:3px 6px}}.awesome-carousel-a11y-skip{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}.awesome-carousel-a11y-skip:focus{position:static;width:auto;height:auto;padding:10px;background:var(--awesome-carousel-cyan);color:var(--awesome-carousel-dark-bg);outline:2px solid var(--awesome-carousel-cyan)}@media(prefers-contrast:more){.awesome-carousel-card__content--dark{border-color:var(--awesome-carousel-indicator-active-dark)}.awesome-carousel-card__content--light{border-color:var(--awesome-carousel-violet)}.awesome-carousel-indicator{border:1px solid currentColor}}@media(forced-colors:active){.awesome-carousel-card__content,.awesome-carousel-nav__button,.awesome-carousel-indicator{border:1px solid}}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "awesome-coverflow-carousel",
3
+ "version": "0.1.3",
4
+ "description": "A beautiful, interactive 3D Coverflowcarousel component for React with smooth animations, multiple themes, and flexible data handling",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.umd.cjs"
17
+ },
18
+ "./dist/style.css": "./dist/style.css"
19
+ },
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "tsc -b && vite build",
23
+ "preview": "vite preview",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "keywords": [
27
+ "react",
28
+ "carousel",
29
+ "coverflow",
30
+ "3d",
31
+ "ring",
32
+ "component",
33
+ "interactive",
34
+ "animation",
35
+ "theme",
36
+ "ui"
37
+ ],
38
+ "author": "Pravinkumar Dabade",
39
+ "license": "MIT",
40
+ "peerDependenciesMeta": {
41
+ "react": {
42
+ "optional": false
43
+ },
44
+ "react-dom": {
45
+ "optional": false
46
+ }
47
+ },
48
+ "dependencies": {
49
+ "react": "^19.0.0",
50
+ "react-dom": "^19.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/react": "^19.0.0",
54
+ "@types/react-dom": "^19.0.0",
55
+ "@vitejs/plugin-react": "^4.3.4",
56
+ "typescript": "~5.6.2",
57
+ "vite": "^6.0.5"
58
+ },
59
+ "engines": {
60
+ "node": ">=14.0.0",
61
+ "npm": ">=6.0.0"
62
+ }
63
+ }