react-3d-carousel-fullcontrol 1.1.0 → 1.2.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/Carousel.jsx +9 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-3d-carousel-fullcontrol",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A highly customizable 3D carousel component for React with full axis rotation control",
5
5
  "main": "src/Carousel.jsx",
6
6
  "keywords": [
package/src/Carousel.jsx CHANGED
@@ -174,7 +174,7 @@ const CarouselCard = memo(function CarouselCard({
174
174
  style={{
175
175
  width: "100%",
176
176
  height: "100%",
177
- borderRadius: "0px",
177
+ borderRadius: "12px",
178
178
  overflow: "hidden",
179
179
  position: "relative",
180
180
  cursor: "pointer",
@@ -194,7 +194,7 @@ const CarouselCard = memo(function CarouselCard({
194
194
  height: "100%",
195
195
  objectFit: "cover",
196
196
  display: "block",
197
- borderRadius: "0px",
197
+ borderRadius: "12px",
198
198
  filter: hovered
199
199
  ? "brightness(1.2) saturate(1.3) contrast(1.1)"
200
200
  : `brightness(${0.65 + frontness * 0.3}) saturate(1.05)`,
@@ -261,7 +261,7 @@ const CarouselCard = memo(function CarouselCard({
261
261
  right: "5%",
262
262
  height: "80px",
263
263
  background: `url(${image.src}) center/cover no-repeat`,
264
- borderRadius: "0px",
264
+ borderRadius: "12px",
265
265
  transform: "scaleY(-1)",
266
266
  opacity: 0.12 + frontness * 0.08,
267
267
  maskImage: "linear-gradient(to bottom, rgba(0,0,0,0.6) 0%, transparent 100%)",
@@ -276,28 +276,6 @@ const CarouselCard = memo(function CarouselCard({
276
276
 
277
277
  // ─── Main reusable carousel component ────────────────────────────────────────
278
278
 
279
- /**
280
- * 3D Carousel with cylinder-style rotation and full axis control
281
- * Cards arranged in a circle and the entire cylinder rotates
282
- *
283
- * @param {Object} props
284
- * @param {Array<{src: string, label?: string}>} props.images
285
- * @param {Object} [props.defaultRotation] - Default rotation { x: -20, y: 10, z: 20 }
286
- * @param {boolean} [props.controlled=false] - Return to default position on release
287
- * @param {function} [props.onRotationChange] - Callback with current rotation
288
- * @param {number} [props.autoRotateSpeed=0.3] - Auto rotation speed (degrees per frame)
289
- * @param {Object} [props.autoRotateAxes] - Which axes to auto-rotate { x: false, y: true, z: false }
290
- * @param {boolean} [props.pauseOnDrag=true] - Pause auto-rotation while dragging
291
- * @param {number} [props.cardWidth=220]
292
- * @param {number} [props.cardHeight=300]
293
- * @param {number} [props.gap=2]
294
- * @param {number} [props.perspective=2000]
295
- * @param {number} [props.sensitivity=0.4] - Mouse drag sensitivity
296
- * @param {boolean} [props.showDragHint=true]
297
- * @param {boolean} [props.glowEffect=true] - Enable glow effect on hover
298
- * @param {string} [props.className=""]
299
- * @param {Object} [props.style={}]
300
- */
301
279
  function Carousel({
302
280
  images = [],
303
281
  defaultRotation = { x: -20, y: 10, z: 20 },
@@ -312,7 +290,6 @@ function Carousel({
312
290
  perspective = 2000,
313
291
  sensitivity = 0.4,
314
292
  showDragHint = true,
315
- glowEffect = true,
316
293
  className = "",
317
294
  style = {},
318
295
  }) {
@@ -333,7 +310,6 @@ function Carousel({
333
310
  const angleStep = cardCount > 0 ? 360 / cardCount : 0;
334
311
  const radius = cardCount > 0 ? ((cardWidth + gap) * cardCount) / (2 * Math.PI) : 0;
335
312
 
336
- // Sync with defaultRotation prop changes
337
313
  useEffect(() => {
338
314
  if (!isDragging.current) {
339
315
  rotationRef.current = {
@@ -345,7 +321,6 @@ function Carousel({
345
321
  }
346
322
  }, [defaultRotation.x, defaultRotation.y, defaultRotation.z]);
347
323
 
348
- // Animation loop
349
324
  useEffect(() => {
350
325
  if (cardCount === 0) return;
351
326
 
@@ -358,7 +333,6 @@ function Carousel({
358
333
  const isCurrentlyDragging = isDragging.current;
359
334
 
360
335
  if (!isCurrentlyDragging) {
361
- // Apply friction to all velocities
362
336
  velocityRef.current.x *= 0.94;
363
337
  velocityRef.current.y *= 0.94;
364
338
  velocityRef.current.z *= 0.94;
@@ -368,22 +342,19 @@ function Carousel({
368
342
  if (Math.abs(velocityRef.current.z) < 0.001) velocityRef.current.z = 0;
369
343
 
370
344
  if (!controlled) {
371
- // Free mode: apply auto-rotation to all specified axes
345
+ // Auto-rotate on specified axes
372
346
  if (autoRotateAxes.x) rotationRef.current.x += autoRotateSpeed * (delta / 16.67);
373
347
  if (autoRotateAxes.y) rotationRef.current.y += autoRotateSpeed * (delta / 16.67);
374
348
  if (autoRotateAxes.z) rotationRef.current.z += autoRotateSpeed * (delta / 16.67);
375
349
 
376
- // Add momentum
377
350
  rotationRef.current.x += velocityRef.current.x;
378
351
  rotationRef.current.y += velocityRef.current.y;
379
352
  rotationRef.current.z += velocityRef.current.z;
380
353
  } else {
381
- // Controlled mode: apply momentum and return to default
382
354
  rotationRef.current.x += velocityRef.current.x;
383
355
  rotationRef.current.y += velocityRef.current.y;
384
356
  rotationRef.current.z += velocityRef.current.z;
385
357
 
386
- // If velocities are near zero, return to default position
387
358
  if (Math.abs(velocityRef.current.x) < 0.01 &&
388
359
  Math.abs(velocityRef.current.y) < 0.01 &&
389
360
  Math.abs(velocityRef.current.z) < 0.01) {
@@ -416,7 +387,6 @@ function Carousel({
416
387
  };
417
388
  }, [controlled, defaultRotation, autoRotateSpeed, autoRotateAxes, pauseOnDrag, onRotationChange, cardCount]);
418
389
 
419
- // Interaction handlers
420
390
  const handlePointerDown = useCallback((clientX, clientY) => {
421
391
  isDragging.current = true;
422
392
  lastMousePos.current = { x: clientX, y: clientY };
@@ -437,21 +407,20 @@ function Carousel({
437
407
  // Horizontal drag = Y axis rotation (spin the cylinder)
438
408
  rotationRef.current.y += dx * sensitivity;
439
409
 
440
- // Vertical drag = X axis rotation (tilt the cylinder forward/backward)
410
+ // Vertical drag = X axis rotation (tilt the cylinder)
441
411
  rotationRef.current.x -= dy * sensitivity * 0.6;
442
412
 
443
- // Diagonal drag = Z axis rotation (roll/twist the cylinder)
413
+ // Diagonal drag = Z axis rotation (roll)
444
414
  if (Math.abs(dx) > 2 && Math.abs(dy) > 2) {
445
415
  const diagonalComponent = (dx * dy) / Math.sqrt(dx * dx + dy * dy);
446
416
  rotationRef.current.z += diagonalComponent * sensitivity * 0.3;
447
417
  }
448
418
 
449
- // Store velocities for momentum
450
419
  velocityRef.current.y = dx * sensitivity * 0.5;
451
420
  velocityRef.current.x = -dy * sensitivity * 0.3;
452
421
  velocityRef.current.z = (dx * dy / Math.sqrt(dx * dx + dy * dy || 1)) * sensitivity * 0.2;
453
422
 
454
- // Clamp rotations to reasonable ranges
423
+ // Clamp values
455
424
  rotationRef.current.x = Math.max(-75, Math.min(75, rotationRef.current.x));
456
425
  rotationRef.current.z = Math.max(-45, Math.min(45, rotationRef.current.z));
457
426
 
@@ -462,7 +431,6 @@ function Carousel({
462
431
  isDragging.current = false;
463
432
  }, []);
464
433
 
465
- // Mouse events
466
434
  const onMouseDown = useCallback((e) => {
467
435
  e.preventDefault();
468
436
  handlePointerDown(e.clientX, e.clientY);
@@ -476,7 +444,6 @@ function Carousel({
476
444
  handlePointerUp();
477
445
  }, [handlePointerUp]);
478
446
 
479
- // Touch events
480
447
  const onTouchStart = useCallback((e) => {
481
448
  handlePointerDown(e.touches[0].clientX, e.touches[0].clientY);
482
449
  }, [handlePointerDown]);
@@ -489,7 +456,6 @@ function Carousel({
489
456
  handlePointerUp();
490
457
  }, [handlePointerUp]);
491
458
 
492
- // Empty state
493
459
  if (cardCount === 0) {
494
460
  return (
495
461
  <div className={className} style={{ position: "relative", width: "100%", height: "100%", ...style }}>
@@ -537,7 +503,7 @@ function Carousel({
537
503
  onTouchMove={onTouchMove}
538
504
  onTouchEnd={onTouchEnd}
539
505
  >
540
- {/* Outer container - tilts the entire cylinder on X and Z axes */}
506
+ {/* OUTER CONTAINER: Only tilts the view (X and Z rotation) */}
541
507
  <div
542
508
  style={{
543
509
  position: "absolute",
@@ -548,7 +514,7 @@ function Carousel({
548
514
  willChange: "transform",
549
515
  }}
550
516
  >
551
- {/* Inner container - rotates the cards around Y axis (cylinder spin) */}
517
+ {/* INNER CONTAINER: Only spins the cards around Y axis */}
552
518
  <div
553
519
  style={{
554
520
  position: "absolute",
@@ -559,7 +525,6 @@ function Carousel({
559
525
  willChange: "transform",
560
526
  }}
561
527
  >
562
- {/* Render cards in sorted order (back to front) */}
563
528
  {sortedImages.map(({ image, index, zDepth }) => (
564
529
  <CarouselCard
565
530
  key={index}