vevet 5.0.10 → 5.0.11

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 (49) hide show
  1. package/README.md +2 -0
  2. package/lib/cdn/vevet.iife.min.js +5 -5
  3. package/lib/cjs/components/Snap/Swipe/index.js +47 -6
  4. package/lib/cjs/components/Snap/Swipe/index.js.map +1 -1
  5. package/lib/cjs/components/Snap/Wheel/index.js +33 -16
  6. package/lib/cjs/components/Snap/Wheel/index.js.map +1 -1
  7. package/lib/cjs/components/Snap/index.js +31 -9
  8. package/lib/cjs/components/Snap/index.js.map +1 -1
  9. package/lib/cjs/components/Swipe/index.js +89 -46
  10. package/lib/cjs/components/Swipe/index.js.map +1 -1
  11. package/lib/cjs/manifest.json +1 -1
  12. package/lib/cjs/utils/math/clamp.js +3 -1
  13. package/lib/cjs/utils/math/clamp.js.map +1 -1
  14. package/lib/esm/components/Snap/Swipe/index.js +31 -6
  15. package/lib/esm/components/Snap/Swipe/index.js.map +1 -1
  16. package/lib/esm/components/Snap/Wheel/index.js +33 -16
  17. package/lib/esm/components/Snap/Wheel/index.js.map +1 -1
  18. package/lib/esm/components/Snap/index.js +29 -7
  19. package/lib/esm/components/Snap/index.js.map +1 -1
  20. package/lib/esm/components/Swipe/index.js +85 -42
  21. package/lib/esm/components/Swipe/index.js.map +1 -1
  22. package/lib/esm/manifest.json +1 -1
  23. package/lib/esm/utils/math/clamp.js +3 -1
  24. package/lib/esm/utils/math/clamp.js.map +1 -1
  25. package/lib/types/components/Snap/Swipe/index.d.ts +2 -0
  26. package/lib/types/components/Snap/Swipe/index.d.ts.map +1 -1
  27. package/lib/types/components/Snap/Swipe/types.d.ts +10 -0
  28. package/lib/types/components/Snap/Swipe/types.d.ts.map +1 -1
  29. package/lib/types/components/Snap/Wheel/index.d.ts +1 -1
  30. package/lib/types/components/Snap/Wheel/index.d.ts.map +1 -1
  31. package/lib/types/components/Snap/Wheel/types.d.ts +8 -2
  32. package/lib/types/components/Snap/Wheel/types.d.ts.map +1 -1
  33. package/lib/types/components/Snap/index.d.ts +1 -1
  34. package/lib/types/components/Snap/index.d.ts.map +1 -1
  35. package/lib/types/components/Swipe/index.d.ts +2 -6
  36. package/lib/types/components/Swipe/index.d.ts.map +1 -1
  37. package/lib/types/components/Swipe/types.d.ts +7 -2
  38. package/lib/types/components/Swipe/types.d.ts.map +1 -1
  39. package/lib/types/utils/math/clamp.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/components/Snap/Swipe/index.ts +49 -8
  42. package/src/components/Snap/Swipe/types.ts +12 -0
  43. package/src/components/Snap/Wheel/index.ts +37 -18
  44. package/src/components/Snap/Wheel/types.ts +9 -2
  45. package/src/components/Snap/index.ts +31 -5
  46. package/src/components/Swipe/index.ts +106 -56
  47. package/src/components/Swipe/types.ts +8 -2
  48. package/src/manifest.json +1 -1
  49. package/src/utils/math/clamp.ts +4 -1
@@ -20,6 +20,7 @@ import {
20
20
  lerp,
21
21
  toPixels,
22
22
  closest,
23
+ clamp,
23
24
  } from '@/utils';
24
25
  import { SnapSlide } from './Slide';
25
26
  import { SnapWheel } from './Wheel';
@@ -85,11 +86,14 @@ export class Snap<
85
86
  swipeLerp: initVevet().mobile ? 1 : 0.6,
86
87
  swipeThreshold: 5,
87
88
  swipeMinTime: 0,
89
+ swipeInertiaDuration: (distance) => clamp(distance, 500, 2000),
90
+ swipeInertiaRatio: 0.3,
88
91
  wheel: false,
89
92
  wheelSpeed: 1,
90
93
  wheelAxis: 'auto',
91
94
  followWheel: true,
92
95
  wheelThrottle: 'auto',
96
+ wheelNoFollowThreshold: 100,
93
97
  stickOnWheelEnd: true,
94
98
  slideSize: 'auto',
95
99
  } as TRequiredProps<MutableProps>;
@@ -331,7 +335,9 @@ export class Snap<
331
335
 
332
336
  // Get lerp factor
333
337
  const lerpFactor =
334
- swipe.isSwiping && props.swipeLerp ? props.swipeLerp : props.lerp;
338
+ (swipe.isSwiping || swipe.hasInertia) && props.swipeLerp
339
+ ? props.swipeLerp
340
+ : props.lerp;
335
341
 
336
342
  // Interpolate track value
337
343
  track.lerp(this._raf.lerpFactor(lerpFactor));
@@ -500,7 +506,7 @@ export class Snap<
500
506
  }
501
507
 
502
508
  /** Go to a definite coordinate */
503
- public toCoord(coordinate: number, duration = this.props.duration) {
509
+ public toCoord(coordinate: number, durationProp = this.props.duration) {
504
510
  if (this.isEmpty) {
505
511
  return false;
506
512
  }
@@ -513,8 +519,14 @@ export class Snap<
513
519
  const end = coordinate;
514
520
  const diff = Math.abs(end - start);
515
521
 
522
+ let duration =
523
+ typeof durationProp === 'number' ? durationProp : durationProp(diff);
524
+ if (diff === 0) {
525
+ duration = 0;
526
+ }
527
+
516
528
  const tm = new Timeline({
517
- duration: typeof duration === 'number' ? duration : duration(diff),
529
+ duration,
518
530
  easing: props.easing,
519
531
  });
520
532
 
@@ -573,16 +585,30 @@ export class Snap<
573
585
 
574
586
  this._targetIndex = index;
575
587
  const slideMagnets = slides[index].magnets;
588
+ let targetStaticMagnet = slideMagnets[0];
589
+
590
+ if (props.centered) {
591
+ if (direction === 'prev') {
592
+ targetStaticMagnet = slideMagnets[2] ?? slideMagnets[0];
593
+ } else if (direction === 'next') {
594
+ targetStaticMagnet = slideMagnets[1] ?? slideMagnets[0];
595
+ }
596
+ } else {
597
+ targetStaticMagnet =
598
+ direction === 'prev'
599
+ ? slideMagnets[slideMagnets.length - 1]
600
+ : targetStaticMagnet;
601
+ }
576
602
 
577
603
  // Use static magnet when not looping
578
604
 
579
605
  if (!props.loop) {
580
- return this.toCoord(slideMagnets[0], duration);
606
+ return this.toCoord(targetStaticMagnet, duration);
581
607
  }
582
608
 
583
609
  // Or calculate closest magnet
584
610
 
585
- const targetMagnet = slideMagnets[0] + loopCount * max;
611
+ const targetMagnet = targetStaticMagnet + loopCount * max;
586
612
  const targetMagnetMin = targetMagnet - max;
587
613
  const targetMagnetMax = targetMagnet + max;
588
614
  const allMagnets = [targetMagnetMin, targetMagnet, targetMagnetMax];
@@ -17,6 +17,9 @@ import { cursorStyles } from './styles';
17
17
 
18
18
  export * from './types';
19
19
 
20
+ const VELOCITIES_COUNT = 4;
21
+ const MIN_VELOCITY_THRESHOLD = 50;
22
+
20
23
  /**
21
24
  * Manages swipe interactions:
22
25
  * - Tracks movement and detects direction
@@ -67,9 +70,10 @@ export class Swipe<
67
70
  preventTouchMove: true,
68
71
  requireCtrlKey: false,
69
72
  inertia: false,
70
- inertiaDuration: (distance) => clamp(distance, 350, 1000),
73
+ inertiaDuration: (distance) => clamp(distance, 500, 2000),
71
74
  inertiaEasing: EaseOutCubic,
72
- inertiaRatio: 0.5,
75
+ velocityModifier: false,
76
+ inertiaRatio: 1,
73
77
  } as TRequiredProps<MutableProps>;
74
78
  }
75
79
 
@@ -439,7 +443,12 @@ export class Swipe<
439
443
  };
440
444
 
441
445
  // update velocity
442
- this._velocities.push({ ...coords.current, timestamp: coords.timestamp });
446
+ if (!this.hasInertia) {
447
+ this._velocities.push({ ...coords.current, timestamp: coords.timestamp });
448
+ if (this._velocities.length > VELOCITIES_COUNT) {
449
+ this._velocities.shift();
450
+ }
451
+ }
443
452
 
444
453
  // trigger callbacks
445
454
  this.callbacks.emit('move', this._coords);
@@ -459,11 +468,6 @@ export class Swipe<
459
468
  // reset
460
469
  this._reset();
461
470
 
462
- // end with inertia
463
- if (this.props.inertia) {
464
- this._endWithInertia();
465
- }
466
-
467
471
  // reset cursor
468
472
  this._cursorStyles.remove();
469
473
 
@@ -493,6 +497,17 @@ export class Swipe<
493
497
 
494
498
  // end callback
495
499
  this.callbacks.emit('end', this._coords);
500
+
501
+ // modifiy last velocity time
502
+ if (this._velocities.length > 0) {
503
+ this._velocities[this._velocities.length - 1].timestamp =
504
+ performance.now();
505
+ }
506
+
507
+ // end with inertia
508
+ if (this.props.inertia) {
509
+ this._endWithInertia();
510
+ }
496
511
  }
497
512
 
498
513
  /** Reset swipe states */
@@ -501,21 +516,90 @@ export class Swipe<
501
516
  this._isSwiping = false;
502
517
  }
503
518
 
519
+ /** Returns current velocity */
520
+ protected get velocity(): ISwipeMatrix {
521
+ const samples = this._velocities;
522
+
523
+ if (samples.length < 2) {
524
+ return { x: 0, y: 0, angle: 0 };
525
+ }
526
+
527
+ let totalWeight = 0;
528
+ let wvx = 0;
529
+ let wvy = 0;
530
+ let wva = 0;
531
+
532
+ for (let i = 1; i < samples.length; i += 1) {
533
+ const current = samples[i];
534
+ const previous = samples[i - 1];
535
+
536
+ const deltaX = current.x - previous.x;
537
+ const deltaY = current.y - previous.y;
538
+
539
+ let angleDiff = current.angle - previous.angle;
540
+ if (angleDiff > 180) angleDiff -= 360;
541
+ if (angleDiff < -180) angleDiff += 360;
542
+
543
+ const deltatTime = current.timestamp - previous.timestamp;
544
+
545
+ const sx = (deltaX / deltatTime) * 1000;
546
+ const sy = (deltaY / deltatTime) * 1000;
547
+ const sa = (angleDiff / deltatTime) * 1000;
548
+
549
+ const weight = 1 / Math.exp(-deltatTime * 0.1);
550
+ wvx += sx * weight;
551
+ wvy += sy * weight;
552
+ wva += sa * weight;
553
+ totalWeight += weight;
554
+ }
555
+
556
+ if (totalWeight > 0) {
557
+ return {
558
+ x: wvx / totalWeight,
559
+ y: wvy / totalWeight,
560
+ angle: wva / totalWeight,
561
+ };
562
+ }
563
+
564
+ return { x: 0, y: 0, angle: 0 };
565
+ }
566
+
504
567
  /** Apply inertia-based movement */
505
568
  protected _endWithInertia() {
506
- const { velocity } = this;
507
- if (!velocity) {
569
+ const { inertiaDuration, inertiaEasing, velocityModifier, inertiaRatio } =
570
+ this.props;
571
+
572
+ const sourceVelocity = {
573
+ x: this.velocity.x * inertiaRatio,
574
+ y: this.velocity.y * inertiaRatio,
575
+ angle: this.velocity.angle * inertiaRatio,
576
+ };
577
+
578
+ const velocity = velocityModifier
579
+ ? velocityModifier(sourceVelocity)
580
+ : sourceVelocity;
581
+
582
+ const { x: velocityX, y: velocityY, angle: velocityA } = velocity;
583
+ const distance = Math.sqrt(velocityX ** 2 + velocityY ** 2);
584
+
585
+ // Check if we have sufficient velocity
586
+ if (distance < MIN_VELOCITY_THRESHOLD) {
508
587
  return;
509
588
  }
510
589
 
511
- const { inertiaDuration, inertiaEasing } = this.props;
512
- const { x: xDistance, y: yDistance, angle: angleDistance } = velocity;
513
-
514
- const distance = Math.max(Math.abs(xDistance), Math.abs(yDistance));
590
+ // Calculate animation duration
515
591
  const duration = inertiaDuration(distance);
516
592
 
593
+ // Check if the animation duration is positive
594
+ if (duration <= 0) {
595
+ return;
596
+ }
597
+
598
+ // Calculate the start and add matrices
517
599
  const startMatrix = { ...this.coords.current };
600
+ const addMatrix = { x: 0, y: 0, angle: 0 };
518
601
 
602
+ // Start the inertia animation
519
603
  this._inertia = new Timeline({ duration, easing: inertiaEasing });
520
604
 
521
605
  this._inertia.on('start', () => {
@@ -523,10 +607,15 @@ export class Swipe<
523
607
  });
524
608
 
525
609
  this._inertia.on('update', ({ eased }) => {
610
+ addMatrix.x = velocityX * eased;
611
+ addMatrix.y = velocityY * eased;
612
+ addMatrix.angle = velocityA * eased;
613
+
614
+ // Apply the calculated position
526
615
  this._move({
527
- x: startMatrix.x + xDistance * eased,
528
- y: startMatrix.y + yDistance * eased,
529
- angle: startMatrix.angle + angleDistance * eased,
616
+ x: startMatrix.x + addMatrix.x,
617
+ y: startMatrix.y + addMatrix.y,
618
+ angle: startMatrix.angle + addMatrix.angle,
530
619
  });
531
620
 
532
621
  this.callbacks.emit('inertia', undefined);
@@ -549,45 +638,6 @@ export class Swipe<
549
638
  this._inertia = undefined;
550
639
  }
551
640
 
552
- /** Returns current velocity */
553
- protected get velocity() {
554
- if (this._velocities.length < 2) {
555
- return undefined;
556
- }
557
-
558
- const ratio = 1000 * this.props.inertiaRatio;
559
- const minimumVelocity = 0.02;
560
-
561
- const current = this._velocities.pop()!;
562
- const last = this._velocities.pop()!;
563
-
564
- const now = performance.now();
565
- const timeDiff = current.timestamp - last.timestamp;
566
-
567
- const velocityX = (current.x - last.x) / timeDiff / 2;
568
- const velocityY = (current.y - last.y) / timeDiff / 2;
569
- const velocityAngle = (current.angle - last.angle) / timeDiff / 2;
570
-
571
- const hasXVelocity = Math.abs(velocityX) > minimumVelocity;
572
- const hasYVelocity = Math.abs(velocityY) > minimumVelocity;
573
- const hasAngleVelocity = Math.abs(velocityAngle) > minimumVelocity;
574
-
575
- const hasVelocityByTime = timeDiff < 150 && now - current.timestamp < 300;
576
-
577
- const hasVelocity =
578
- (hasXVelocity || hasYVelocity || hasAngleVelocity) && hasVelocityByTime;
579
-
580
- if (!hasVelocity) {
581
- return undefined;
582
- }
583
-
584
- return {
585
- x: hasXVelocity ? velocityX * ratio : 0,
586
- y: hasYVelocity ? velocityY * ratio : 0,
587
- angle: hasAngleVelocity ? velocityAngle * ratio : 0,
588
- };
589
- }
590
-
591
641
  /** Start coordinate */
592
642
  get start() {
593
643
  return this._coords.start;
@@ -117,7 +117,7 @@ export interface ISwipeMutableProps extends IModuleMutableProps {
117
117
 
118
118
  /**
119
119
  * Inertia duration.
120
- * @default `(distance) => clamp(distance, 350, 1000)`
120
+ * @default `(distance) => clamp(distance, 500, 2000)`
121
121
  */
122
122
  inertiaDuration?: (distance: number) => number;
123
123
 
@@ -127,9 +127,15 @@ export interface ISwipeMutableProps extends IModuleMutableProps {
127
127
  */
128
128
  inertiaEasing?: TEasingType;
129
129
 
130
+ /**
131
+ * Final velocity modifier.
132
+ * @default false
133
+ */
134
+ velocityModifier?: false | ((velocity: ISwipeMatrix) => ISwipeMatrix);
135
+
130
136
  /**
131
137
  * Inertia strength.
132
- * @default 0.5
138
+ * @default 1
133
139
  */
134
140
  inertiaRatio?: number;
135
141
  }
package/src/manifest.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "5.0.10"
2
+ "version": "5.0.11"
3
3
  }
@@ -16,5 +16,8 @@
16
16
  * clamp(0.5, 0, 1); // 0.5
17
17
  */
18
18
  export function clamp(value: number, min = 0, max = 1) {
19
- return Math.max(min, Math.min(value, max));
19
+ const realMin = Math.min(min, max);
20
+ const realMax = Math.max(min, max);
21
+
22
+ return Math.max(realMin, Math.min(value, realMax));
20
23
  }