swipeon-react 1.0.1 → 1.0.4

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 CHANGED
@@ -6,6 +6,16 @@
6
6
 
7
7
  A high-performance, zero-dependency React swipe card library with smooth animations and multi-directional swipe support. Perfect for building Tinder-like interfaces, interactive card stacks, and gesture-based UI components.
8
8
 
9
+ ## 🎬 Demo
10
+
11
+ <p align="center">
12
+ <a href="assets/tinder-swipe-example.mp4">
13
+ <img src="https://img.shields.io/badge/▶_Watch_Demo_Video-FF0000?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Watch Demo Video" />
14
+ </a>
15
+ </p>
16
+
17
+ > 📹 **[Watch Demo Video](assets/tinder-swipe-example.mp4)** - Tinder-style profile cards with 4-direction swipes, custom overlay labels (LIKE/NOPE), and smooth 60fps animations.
18
+
9
19
  ## ✨ Features
10
20
 
11
21
  - 🚀 **High Performance**: Optimized with `requestAnimationFrame` and hardware-accelerated transforms
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`react`);c=s(c);const l=(e,t)=>t===0?0:Math.abs(e/t),u=(e,t,n=50)=>{let r=Math.abs(e),i=Math.abs(t);return r<n&&i<n?null:r>i?e>0?`right`:`left`:t>0?`down`:`up`},d=(e,t=15,n=300)=>{let r=e/n*t;return Math.max(-t,Math.min(t,r))},f=(e,t,n=100)=>{let r=1-Math.sqrt(e*e+t*t)/(n*3);return Math.max(.5,Math.min(1,r))},p=e=>`touches`in e&&e.touches&&e.touches.length>0?{x:e.touches[0].clientX,y:e.touches[0].clientY}:`clientX`in e&&`clientY`in e?{x:e.clientX,y:e.clientY}:{x:0,y:0},m={threshold:100,velocityThreshold:.5,maxRotation:15,exitDuration:300,returnDuration:200,enableRotation:!0,preventSwipe:[]},h=(e={},t={})=>{let{threshold:n,velocityThreshold:r,maxRotation:i,exitDuration:a,returnDuration:o,enableRotation:s,preventSwipe:h}=(0,c.useMemo)(()=>({...m,...t}),[t.threshold,t.velocityThreshold,t.maxRotation,t.exitDuration,t.returnDuration,t.enableRotation,JSON.stringify(t.preventSwipe)]),g=(0,c.useRef)(null),_=(0,c.useRef)(null),v=(0,c.useRef)(new Set),y=(0,c.useRef)(e);y.current=e;let b=(0,c.useRef)(`translate3d(0px, 0px, 0px) rotate(0deg)`),x=(0,c.useRef)(1),S=(0,c.useRef)(`none`),[C,w]=(0,c.useState)({transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1,transition:`none`}),[T,E]=(0,c.useState)({isDragging:!1,startX:0,startY:0,currentX:0,currentY:0,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:0}),D=(0,c.useCallback)(e=>{w(t=>{let n={...t,...e};return t.transform===n.transform&&t.opacity===n.opacity&&t.transition===n.transition?t:n})},[]),O=(0,c.useCallback)((e,t)=>{let n=setTimeout(()=>{v.current.delete(n),e()},t);return v.current.add(n),n},[]),k=(0,c.useCallback)(e=>{let t=p(e),n=Date.now();E({isDragging:!0,startX:t.x,startY:t.y,currentX:t.x,currentY:t.y,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:n}),S.current=`none`,D({transition:`none`}),y.current.onSwipeStart?.()},[D]),A=(0,c.useRef)(T);A.current=T;let j=(0,c.useCallback)(e=>{let t=A.current;if(!t.isDragging)return;let r=p(e),a=r.x-t.startX,o=r.y-t.startY;h.includes(`left`)&&a<0&&(a=0),h.includes(`right`)&&a>0&&(a=0),h.includes(`up`)&&o<0&&(o=0),h.includes(`down`)&&o>0&&(o=0),E(e=>({...e,currentX:r.x,currentY:r.y,deltaX:a,deltaY:o})),_.current&&cancelAnimationFrame(_.current),_.current=requestAnimationFrame(()=>{let e=s?d(a,i):0,t=f(a,o,n),r=`translate3d(${a}px, ${o}px, 0px) rotate(${e}deg)`;b.current=r,x.current=t,D({transform:r,opacity:t})})},[s,i,n,h,D]),M=(0,c.useCallback)(()=>{let e=A.current;if(!e.isDragging)return;let{deltaX:t,deltaY:c,startTime:f}=e,p=Date.now()-f,m=Math.sqrt(t*t+c*c),g=l(m,p),_=u(t,c,n/2),v=m>=n||g>=r,b=_&&h.includes(_);if(v&&_&&!b){let e=`transform ${a}ms ease-out, opacity ${a}ms ease-out`,n=t*2;D({transition:e,transform:`translate3d(${n}px, ${c*2}px, 0px) rotate(${s?d(n,i*2):0}deg)`,opacity:0}),O(()=>{switch(_){case`left`:y.current.onSwipeLeft?.();break;case`right`:y.current.onSwipeRight?.();break;case`up`:y.current.onSwipeUp?.();break;case`down`:y.current.onSwipeDown?.();break}y.current.onSwipeEnd?.(),O(()=>{D({transition:`none`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1})},50)},a)}else D({transition:`transform ${o}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${o}ms ease-out`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1}),y.current.onSwipeEnd?.();E(e=>({...e,isDragging:!1}))},[n,r,a,o,s,i,h,D,O]),N=(0,c.useRef)({handleSwipeStart:k,handleSwipeMove:j,handleSwipeEnd:M});return N.current={handleSwipeStart:k,handleSwipeMove:j,handleSwipeEnd:M},(0,c.useEffect)(()=>{let e=g.current;if(!e)return;let t=e=>{N.current.handleSwipeStart(e)};return e.addEventListener(`pointerdown`,t),()=>{e.removeEventListener(`pointerdown`,t)}},[]),(0,c.useEffect)(()=>{if(!T.isDragging)return;let e=e=>{N.current.handleSwipeMove(e)},t=()=>{N.current.handleSwipeEnd()};return document.addEventListener(`pointermove`,e),document.addEventListener(`pointerup`,t),document.addEventListener(`pointercancel`,t),()=>{document.removeEventListener(`pointermove`,e),document.removeEventListener(`pointerup`,t),document.removeEventListener(`pointercancel`,t)}},[T.isDragging]),(0,c.useEffect)(()=>()=>{_.current&&cancelAnimationFrame(_.current),v.current.forEach(e=>clearTimeout(e)),v.current.clear()},[]),{ref:g,transform:C.transform,opacity:C.opacity,transition:C.transition,isDragging:T.isDragging,deltaX:T.deltaX,deltaY:T.deltaY}},g={fontSize:`2rem`,fontWeight:`bold`,color:`#fff`,textTransform:`uppercase`,letterSpacing:`2px`,textShadow:`0 2px 8px rgba(0, 0, 0, 0.3)`},_={right:{backgroundColor:`rgba(34, 197, 94, 0.6)`,label:`✓ Accept`,labelStyle:g},left:{backgroundColor:`rgba(239, 68, 68, 0.6)`,label:`✗ Reject`,labelStyle:g},up:{backgroundColor:`rgba(59, 130, 246, 0.6)`,label:`⭐ Super`,labelStyle:g},down:{backgroundColor:`rgba(168, 85, 247, 0.6)`,label:`⏭ Skip`,labelStyle:g}},v=[],y=({children:e,className:t=``,style:n,onSwipeLeft:r,onSwipeRight:i,onSwipeUp:a,onSwipeDown:o,onSwipeStart:s,onSwipeEnd:l,threshold:u=100,velocityThreshold:d=.5,maxRotation:f=15,exitDuration:p=300,returnDuration:m=200,enableRotation:g=!0,preventSwipe:y=v,swipeStyles:b,showOverlay:x=!0})=>{let{ref:S,transform:C,opacity:w,transition:T,isDragging:E,deltaX:D,deltaY:O}=h((0,c.useMemo)(()=>({onSwipeLeft:r,onSwipeRight:i,onSwipeUp:a,onSwipeDown:o,onSwipeStart:s,onSwipeEnd:l}),[r,i,a,o,s,l]),(0,c.useMemo)(()=>({threshold:u,velocityThreshold:d,maxRotation:f,exitDuration:p,returnDuration:m,enableRotation:g,preventSwipe:y}),[u,d,f,p,m,g,y])),k=(0,c.useMemo)(()=>({right:{..._.right,...b?.right,labelStyle:{..._.right.labelStyle,...b?.right?.labelStyle}},left:{..._.left,...b?.left,labelStyle:{..._.left.labelStyle,...b?.left?.labelStyle}},up:{..._.up,...b?.up,labelStyle:{..._.up.labelStyle,...b?.up?.labelStyle}},down:{..._.down,...b?.down,labelStyle:{..._.down.labelStyle,...b?.down?.labelStyle}}}),[b?.right,b?.left,b?.up,b?.down]),A=Math.abs(D),j=Math.abs(O),M=A>=j,N=M?A:j,P=Math.min(N/u,1),F=M&&D>20,I=M&&D<-20,L=!M&&O<-20,R=!M&&O>20,z=P>=.15,B=x&&E&&N>10,V=(0,c.useMemo)(()=>F?`right`:I?`left`:L?`up`:R?`down`:null,[F,I,L,R]),H=V?k[V]:null,U=H?.backgroundColor??`transparent`,W=H?{label:H.label,labelStyle:H.labelStyle}:null,G=(0,c.useMemo)(()=>({...n,transform:C,opacity:w,transition:T,touchAction:`none`,userSelect:`none`,WebkitUserSelect:`none`,cursor:E?`grabbing`:`grab`,willChange:E?`transform, opacity`:`auto`,position:`absolute`}),[n,C,w,T,E]),K=(0,c.useMemo)(()=>({position:`absolute`,top:0,left:0,right:0,bottom:0,display:`flex`,alignItems:`center`,justifyContent:`center`,borderRadius:`inherit`,pointerEvents:`none`,zIndex:10,opacity:B?P:0,transition:E?`none`:`opacity 200ms ease-out`,backgroundColor:B?U:`transparent`}),[B,P,E,U]),q=(0,c.useMemo)(()=>({...W?.labelStyle,transform:`scale(${.8+P*.4})`,opacity:P}),[W?.labelStyle,P]);return c.default.createElement(`div`,{ref:S,className:`swipeon-card ${t}`,style:G},e,c.default.createElement(`div`,{style:K},B&&z&&W?.label&&c.default.createElement(`span`,{style:q},W.label)))},b=(0,c.memo)(y);exports.SwipeCard=b,exports.useSwipe=h;
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`react`);c=s(c);const l=(e,t)=>t===0?0:Math.abs(e/t),u=(e,t,n=50)=>{let r=Math.abs(e),i=Math.abs(t);return r<n&&i<n?null:r>i?e>0?`right`:`left`:t>0?`down`:`up`},d=(e,t=15,n=300)=>{let r=e/n*t;return Math.max(-t,Math.min(t,r))},f=(e,t,n=100)=>{let r=1-Math.sqrt(e*e+t*t)/(n*3);return Math.max(.5,Math.min(1,r))},p=e=>`touches`in e&&e.touches&&e.touches.length>0?{x:e.touches[0].clientX,y:e.touches[0].clientY}:`clientX`in e&&`clientY`in e?{x:e.clientX,y:e.clientY}:{x:0,y:0},m={threshold:100,velocityThreshold:.5,maxRotation:15,exitDuration:300,returnDuration:200,enableRotation:!0,preventSwipe:[],fadeOnSwipe:!0},h=(e={},t={})=>{let{threshold:n,velocityThreshold:r,maxRotation:i,exitDuration:a,returnDuration:o,enableRotation:s,preventSwipe:h,fadeOnSwipe:g}=(0,c.useMemo)(()=>({...m,...t}),[t.threshold,t.velocityThreshold,t.maxRotation,t.exitDuration,t.returnDuration,t.enableRotation,t.fadeOnSwipe,JSON.stringify(t.preventSwipe)]),_=(0,c.useRef)(null),v=(0,c.useRef)(null),y=(0,c.useRef)(new Set),b=(0,c.useRef)(e);b.current=e;let x=(0,c.useRef)(`translate3d(0px, 0px, 0px) rotate(0deg)`),S=(0,c.useRef)(1),C=(0,c.useRef)(`none`),[w,T]=(0,c.useState)({transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1,transition:`none`}),[E,D]=(0,c.useState)({isDragging:!1,startX:0,startY:0,currentX:0,currentY:0,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:0}),O=(0,c.useCallback)(e=>{T(t=>{let n={...t,...e};return t.transform===n.transform&&t.opacity===n.opacity&&t.transition===n.transition?t:n})},[]),k=(0,c.useCallback)((e,t)=>{let n=setTimeout(()=>{y.current.delete(n),e()},t);return y.current.add(n),n},[]),A=(0,c.useCallback)(e=>{let t=p(e),n=Date.now();D({isDragging:!0,startX:t.x,startY:t.y,currentX:t.x,currentY:t.y,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:n}),C.current=`none`,O({transition:`none`}),b.current.onSwipeStart?.()},[O]),j=(0,c.useRef)(E);j.current=E;let M=(0,c.useCallback)(e=>{let t=j.current;if(!t.isDragging)return;let r=p(e),a=r.x-t.startX,o=r.y-t.startY;h.includes(`left`)&&a<0&&(a=0),h.includes(`right`)&&a>0&&(a=0),h.includes(`up`)&&o<0&&(o=0),h.includes(`down`)&&o>0&&(o=0),D(e=>({...e,currentX:r.x,currentY:r.y,deltaX:a,deltaY:o})),v.current&&cancelAnimationFrame(v.current),v.current=requestAnimationFrame(()=>{let e=s?d(a,i):0,t=g?f(a,o,n):1,r=`translate3d(${a}px, ${o}px, 0px) rotate(${e}deg)`;x.current=r,S.current=t,O({transform:r,opacity:t})})},[s,i,n,h,g,O]),N=(0,c.useCallback)(()=>{let e=j.current;if(!e.isDragging)return;let{deltaX:t,deltaY:c,startTime:f}=e,p=Date.now()-f,m=Math.sqrt(t*t+c*c),g=l(m,p),_=u(t,c,n/2),v=m>=n||g>=r,y=_&&h.includes(_);if(v&&_&&!y){let e=`transform ${a}ms ease-out, opacity ${a}ms ease-out`,n=t*2;O({transition:e,transform:`translate3d(${n}px, ${c*2}px, 0px) rotate(${s?d(n,i*2):0}deg)`,opacity:0}),k(()=>{switch(_){case`left`:b.current.onSwipeLeft?.();break;case`right`:b.current.onSwipeRight?.();break;case`up`:b.current.onSwipeUp?.();break;case`down`:b.current.onSwipeDown?.();break}b.current.onSwipeEnd?.(),k(()=>{O({transition:`none`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1})},50)},a)}else O({transition:`transform ${o}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${o}ms ease-out`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1}),b.current.onSwipeEnd?.();D(e=>({...e,isDragging:!1}))},[n,r,a,o,s,i,h,O,k]),P=(0,c.useRef)({handleSwipeStart:A,handleSwipeMove:M,handleSwipeEnd:N});return P.current={handleSwipeStart:A,handleSwipeMove:M,handleSwipeEnd:N},(0,c.useEffect)(()=>{let e=_.current;if(!e)return;let t=e=>{P.current.handleSwipeStart(e)};return e.addEventListener(`pointerdown`,t),()=>{e.removeEventListener(`pointerdown`,t)}},[]),(0,c.useEffect)(()=>{if(!E.isDragging)return;let e=e=>{P.current.handleSwipeMove(e)},t=()=>{P.current.handleSwipeEnd()};return document.addEventListener(`pointermove`,e),document.addEventListener(`pointerup`,t),document.addEventListener(`pointercancel`,t),()=>{document.removeEventListener(`pointermove`,e),document.removeEventListener(`pointerup`,t),document.removeEventListener(`pointercancel`,t)}},[E.isDragging]),(0,c.useEffect)(()=>()=>{v.current&&cancelAnimationFrame(v.current),y.current.forEach(e=>clearTimeout(e)),y.current.clear()},[]),{ref:_,transform:w.transform,opacity:w.opacity,transition:w.transition,isDragging:E.isDragging,deltaX:E.deltaX,deltaY:E.deltaY}},g={fontSize:`2rem`,fontWeight:`bold`,color:`#fff`,letterSpacing:`2px`,textShadow:`0 2px 8px rgba(0, 0, 0, 0.3)`},_={right:{backgroundColor:`transparent`,label:`✓ Accept`,labelStyle:g},left:{backgroundColor:`transparent`,label:`✗ Reject`,labelStyle:g},up:{backgroundColor:`transparent`,label:`⭐ Super`,labelStyle:g},down:{backgroundColor:`transparent`,label:`⏭ Skip`,labelStyle:g}},v=[],y=({children:e,className:t=``,style:n,onSwipeLeft:r,onSwipeRight:i,onSwipeUp:a,onSwipeDown:o,onSwipeStart:s,onSwipeEnd:l,threshold:u=100,velocityThreshold:d=.5,maxRotation:f=15,exitDuration:p=300,returnDuration:m=200,enableRotation:g=!0,preventSwipe:y=v,fadeOnSwipe:b=!0,swipeStyles:x,showOverlay:S=!0})=>{let{ref:C,transform:w,opacity:T,transition:E,isDragging:D,deltaX:O,deltaY:k}=h((0,c.useMemo)(()=>({onSwipeLeft:r,onSwipeRight:i,onSwipeUp:a,onSwipeDown:o,onSwipeStart:s,onSwipeEnd:l}),[r,i,a,o,s,l]),(0,c.useMemo)(()=>({threshold:u,velocityThreshold:d,maxRotation:f,exitDuration:p,returnDuration:m,enableRotation:g,preventSwipe:y,fadeOnSwipe:b}),[u,d,f,p,m,g,y,b])),A=(0,c.useMemo)(()=>({right:{..._.right,...x?.right,labelStyle:{..._.right.labelStyle,...x?.right?.labelStyle}},left:{..._.left,...x?.left,labelStyle:{..._.left.labelStyle,...x?.left?.labelStyle}},up:{..._.up,...x?.up,labelStyle:{..._.up.labelStyle,...x?.up?.labelStyle}},down:{..._.down,...x?.down,labelStyle:{..._.down.labelStyle,...x?.down?.labelStyle}}}),[x?.right,x?.left,x?.up,x?.down]),j=Math.abs(O),M=Math.abs(k),N=j>=M,P=N?j:M,F=Math.min(P/u,1),I=N&&O>20,L=N&&O<-20,R=!N&&k<-20,z=!N&&k>20,B=F>=.15,V=S&&D&&P>10,H=(0,c.useMemo)(()=>I?`right`:L?`left`:R?`up`:z?`down`:null,[I,L,R,z]),U=H?A[H]:null,W=U?.backgroundColor??`inherit`,G=U?{label:U.label,labelStyle:U.labelStyle}:null,K=(0,c.useMemo)(()=>({...n,transform:w,opacity:T,transition:E,touchAction:`none`,userSelect:`none`,WebkitUserSelect:`none`,cursor:D?`grabbing`:`grab`,willChange:D?`transform, opacity`:`auto`,position:`absolute`}),[n,w,T,E,D]),q=(0,c.useMemo)(()=>({position:`absolute`,top:0,left:0,right:0,bottom:0,display:`flex`,alignItems:`center`,justifyContent:`center`,borderRadius:`inherit`,pointerEvents:`none`,zIndex:10,opacity:V?F:0,transition:D?`none`:`opacity 200ms ease-out`,backgroundColor:V?W:`inherit`}),[V,F,D,W]),J=(0,c.useMemo)(()=>({...G?.labelStyle,transform:`scale(${.8+F*.4})`,opacity:F}),[G?.labelStyle,F]);return c.default.createElement(`div`,{ref:C,className:`swipeon-card ${t}`,style:K},e,c.default.createElement(`div`,{style:q},V&&B&&G?.label&&c.default.createElement(`span`,{style:J},G.label)))},b=(0,c.memo)(y);exports.SwipeCard=b,exports.useSwipe=h;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["DEFAULT_CONFIG: Required<SwipeConfig>","DEFAULT_LABEL_STYLE: CSSProperties","EMPTY_PREVENT_SWIPE: readonly string[]","SwipeCardInner: React.FC<SwipeCardProps>","cardStyle: CSSProperties","overlayStyle: CSSProperties","computedLabelStyle: CSSProperties"],"sources":["../src/utils/helpers.ts","../src/hooks/useSwipe.ts","../src/components/SwipeCard.tsx"],"sourcesContent":["import { SwipeDirection } from '../types';\n\n/**\n * Calculate the distance between two points\n */\nexport const getDistance = (x1: number, y1: number, x2: number, y2: number): number => {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return Math.sqrt(dx * dx + dy * dy);\n};\n\n/**\n * Calculate velocity based on distance and time\n */\nexport const calculateVelocity = (distance: number, time: number): number => {\n if (time === 0) return 0;\n return Math.abs(distance / time);\n};\n\n/**\n * Determine the swipe direction based on deltas\n */\nexport const getSwipeDirection = (\n deltaX: number,\n deltaY: number,\n threshold: number = 50\n): SwipeDirection | null => {\n const absDeltaX = Math.abs(deltaX);\n const absDeltaY = Math.abs(deltaY);\n\n // Need minimum movement\n if (absDeltaX < threshold && absDeltaY < threshold) {\n return null;\n }\n\n // Determine primary direction\n if (absDeltaX > absDeltaY) {\n return deltaX > 0 ? 'right' : 'left';\n } else {\n return deltaY > 0 ? 'down' : 'up';\n }\n};\n\n/**\n * Calculate rotation angle based on horizontal movement\n */\nexport const calculateRotation = (\n deltaX: number,\n maxRotation: number = 15,\n containerWidth: number = 300\n): number => {\n const rotation = (deltaX / containerWidth) * maxRotation;\n return Math.max(-maxRotation, Math.min(maxRotation, rotation));\n};\n\n/**\n * Calculate opacity based on drag distance\n */\nexport const calculateOpacity = (\n deltaX: number,\n deltaY: number,\n threshold: number = 100\n): number => {\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const opacity = 1 - distance / (threshold * 3);\n return Math.max(0.5, Math.min(1, opacity));\n};\n\n/**\n * Clamp a value between min and max\n */\nexport const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value));\n};\n\n/**\n * Get touch/pointer coordinates from event\n */\nexport const getEventCoordinates = (\n event: TouchEvent | PointerEvent | MouseEvent | any\n): { x: number; y: number } => {\n if ('touches' in event && event.touches && event.touches.length > 0) {\n return {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n };\n }\n \n if ('clientX' in event && 'clientY' in event) {\n return {\n x: event.clientX,\n y: event.clientY,\n };\n }\n \n return { x: 0, y: 0 };\n};\n\n","import { useRef, useState, useCallback, useEffect, useMemo } from 'react';\nimport { SwipeConfig, SwipeCallbacks, GestureState, UseSwipeReturn } from '../types';\nimport {\n getSwipeDirection,\n calculateRotation,\n calculateOpacity,\n calculateVelocity,\n getEventCoordinates,\n} from '../utils/helpers';\n\nconst DEFAULT_CONFIG: Required<SwipeConfig> = {\n threshold: 100,\n velocityThreshold: 0.5,\n maxRotation: 15,\n exitDuration: 300,\n returnDuration: 200,\n enableRotation: true,\n preventSwipe: [],\n};\n\nexport const useSwipe = (\n callbacks: SwipeCallbacks = {},\n config: SwipeConfig = {}\n): UseSwipeReturn => {\n // Memoize config to prevent unnecessary recalculations\n const mergedConfig = useMemo(() => ({ ...DEFAULT_CONFIG, ...config }), [\n config.threshold,\n config.velocityThreshold,\n config.maxRotation,\n config.exitDuration,\n config.returnDuration,\n config.enableRotation,\n // Use JSON for array comparison (preventSwipe is typically small)\n JSON.stringify(config.preventSwipe),\n ]);\n\n const {\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n } = mergedConfig;\n\n const ref = useRef<HTMLDivElement>(null);\n const animationFrameRef = useRef<number | null>(null);\n const timeoutRefs = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n \n // Store callbacks in ref to avoid dependency issues\n const callbacksRef = useRef(callbacks);\n callbacksRef.current = callbacks;\n\n // Use refs for animation values that don't need to trigger re-renders during drag\n const transformRef = useRef('translate3d(0px, 0px, 0px) rotate(0deg)');\n const opacityRef = useRef(1);\n const transitionRef = useRef('none');\n\n // Single state for values that need to trigger re-renders\n const [renderState, setRenderState] = useState({\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n transition: 'none',\n });\n\n const [gestureState, setGestureState] = useState<GestureState>({\n isDragging: false,\n startX: 0,\n startY: 0,\n currentX: 0,\n currentY: 0,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: 0,\n });\n\n // Batch update render state\n const updateRenderState = useCallback((updates: Partial<typeof renderState>) => {\n setRenderState(prev => {\n const newState = { ...prev, ...updates };\n // Only update if values actually changed\n if (\n prev.transform === newState.transform &&\n prev.opacity === newState.opacity &&\n prev.transition === newState.transition\n ) {\n return prev;\n }\n return newState;\n });\n }, []);\n\n // Safe setTimeout that tracks timeouts for cleanup\n const safeTimeout = useCallback((fn: () => void, delay: number) => {\n const id = setTimeout(() => {\n timeoutRefs.current.delete(id);\n fn();\n }, delay);\n timeoutRefs.current.add(id);\n return id;\n }, []);\n\n // Handle swipe start\n const handleSwipeStart = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const coords = getEventCoordinates(event as any);\n const now = Date.now();\n\n setGestureState({\n isDragging: true,\n startX: coords.x,\n startY: coords.y,\n currentX: coords.x,\n currentY: coords.y,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: now,\n });\n\n transitionRef.current = 'none';\n updateRenderState({ transition: 'none' });\n \n callbacksRef.current.onSwipeStart?.();\n },\n [updateRenderState]\n );\n\n // Handle swipe move - use refs to avoid closure issues\n const gestureStateRef = useRef(gestureState);\n gestureStateRef.current = gestureState;\n\n const handleSwipeMove = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const coords = getEventCoordinates(event as any);\n let deltaX = coords.x - state.startX;\n let deltaY = coords.y - state.startY;\n\n // Constrain movement based on preventSwipe directions\n if (preventSwipe.includes('left') && deltaX < 0) deltaX = 0;\n if (preventSwipe.includes('right') && deltaX > 0) deltaX = 0;\n if (preventSwipe.includes('up') && deltaY < 0) deltaY = 0;\n if (preventSwipe.includes('down') && deltaY > 0) deltaY = 0;\n\n // Update gesture state\n setGestureState(prev => ({\n ...prev,\n currentX: coords.x,\n currentY: coords.y,\n deltaX,\n deltaY,\n }));\n\n // Use RAF for smooth updates - cancel previous frame\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n\n animationFrameRef.current = requestAnimationFrame(() => {\n const rotation = enableRotation ? calculateRotation(deltaX, maxRotation) : 0;\n const newOpacity = calculateOpacity(deltaX, deltaY, threshold);\n const newTransform = `translate3d(${deltaX}px, ${deltaY}px, 0px) rotate(${rotation}deg)`;\n\n // Update refs immediately for internal use\n transformRef.current = newTransform;\n opacityRef.current = newOpacity;\n\n // Batch update to React state\n updateRenderState({\n transform: newTransform,\n opacity: newOpacity,\n });\n });\n },\n [enableRotation, maxRotation, threshold, preventSwipe, updateRenderState]\n );\n\n // Handle swipe end\n const handleSwipeEnd = useCallback(() => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const { deltaX, deltaY, startTime } = state;\n const timeDelta = Date.now() - startTime;\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const velocity = calculateVelocity(distance, timeDelta);\n\n const direction = getSwipeDirection(deltaX, deltaY, threshold / 2);\n const shouldSwipe = distance >= threshold || velocity >= velocityThreshold;\n\n // Check if direction is prevented\n const isDirectionPrevented = direction && preventSwipe.includes(direction);\n\n if (shouldSwipe && direction && !isDirectionPrevented) {\n // Execute swipe\n const exitTransition = `transform ${exitDuration}ms ease-out, opacity ${exitDuration}ms ease-out`;\n \n // Calculate exit position (move far enough off screen)\n const multiplier = 2;\n const exitX = deltaX * multiplier;\n const exitY = deltaY * multiplier;\n const rotation = enableRotation ? calculateRotation(exitX, maxRotation * 2) : 0;\n const exitTransform = `translate3d(${exitX}px, ${exitY}px, 0px) rotate(${rotation}deg)`;\n\n updateRenderState({\n transition: exitTransition,\n transform: exitTransform,\n opacity: 0,\n });\n\n // Trigger callback after animation\n safeTimeout(() => {\n switch (direction) {\n case 'left':\n callbacksRef.current.onSwipeLeft?.();\n break;\n case 'right':\n callbacksRef.current.onSwipeRight?.();\n break;\n case 'up':\n callbacksRef.current.onSwipeUp?.();\n break;\n case 'down':\n callbacksRef.current.onSwipeDown?.();\n break;\n }\n \n callbacksRef.current.onSwipeEnd?.();\n\n // Reset after callback\n safeTimeout(() => {\n updateRenderState({\n transition: 'none',\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n }, 50);\n }, exitDuration);\n } else {\n // Spring back\n const returnTransition = `transform ${returnDuration}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${returnDuration}ms ease-out`;\n \n updateRenderState({\n transition: returnTransition,\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n\n callbacksRef.current.onSwipeEnd?.();\n }\n\n setGestureState(prev => ({ ...prev, isDragging: false }));\n }, [\n threshold,\n velocityThreshold,\n exitDuration,\n returnDuration,\n enableRotation,\n maxRotation,\n preventSwipe,\n updateRenderState,\n safeTimeout,\n ]);\n\n // Stable event handler refs to avoid re-attaching listeners\n const handlersRef = useRef({\n handleSwipeStart,\n handleSwipeMove,\n handleSwipeEnd,\n });\n handlersRef.current = { handleSwipeStart, handleSwipeMove, handleSwipeEnd };\n\n // Attach event listeners with stable references\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const onPointerDown = (e: PointerEvent) => {\n handlersRef.current.handleSwipeStart(e);\n };\n\n element.addEventListener('pointerdown', onPointerDown);\n\n return () => {\n element.removeEventListener('pointerdown', onPointerDown);\n };\n }, []); // Empty deps - handlers are accessed via ref\n\n // Attach document listeners when dragging\n useEffect(() => {\n if (!gestureState.isDragging) return;\n\n const onPointerMove = (e: PointerEvent) => {\n handlersRef.current.handleSwipeMove(e);\n };\n\n const onPointerUp = () => {\n handlersRef.current.handleSwipeEnd();\n };\n\n document.addEventListener('pointermove', onPointerMove);\n document.addEventListener('pointerup', onPointerUp);\n document.addEventListener('pointercancel', onPointerUp);\n\n return () => {\n document.removeEventListener('pointermove', onPointerMove);\n document.removeEventListener('pointerup', onPointerUp);\n document.removeEventListener('pointercancel', onPointerUp);\n };\n }, [gestureState.isDragging]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n // Clear all pending timeouts\n timeoutRefs.current.forEach(id => clearTimeout(id));\n timeoutRefs.current.clear();\n };\n }, []);\n\n return {\n ref,\n transform: renderState.transform,\n opacity: renderState.opacity,\n transition: renderState.transition,\n isDragging: gestureState.isDragging,\n deltaX: gestureState.deltaX,\n deltaY: gestureState.deltaY,\n };\n};\n","import React, { CSSProperties, useMemo, memo } from 'react';\nimport { useSwipe } from '../hooks/useSwipe';\nimport { SwipeCardProps, SwipeCallbacks, SwipeConfig } from '../types';\n\n/**\n * SwipeCard Component\n * \n * A performant swipeable card component with smooth animations.\n * Supports swipe in all four directions: left, right, up, and down.\n * \n * @example\n * ```tsx\n * <SwipeCard\n * onSwipeLeft={() => console.log('Swiped left')}\n * onSwipeRight={() => console.log('Swiped right')}\n * threshold={100}\n * swipeStyles={{\n * right: { \n * backgroundColor: 'rgba(34, 197, 94, 0.6)', \n * label: '👍 Like',\n * labelStyle: { position: 'absolute', top: 20, right: 20 }\n * },\n * left: { \n * backgroundColor: 'rgba(239, 68, 68, 0.6)', \n * label: '👎 Nope',\n * labelStyle: { position: 'absolute', top: 20, left: 20 }\n * },\n * }}\n * >\n * <div>Your content here</div>\n * </SwipeCard>\n * ```\n */\n\n// Default label style - constant, no need to recreate\nconst DEFAULT_LABEL_STYLE: CSSProperties = {\n fontSize: '2rem',\n fontWeight: 'bold',\n color: '#fff',\n textTransform: 'uppercase',\n letterSpacing: '2px',\n textShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n};\n\n// Default styles for each direction - constant\nconst DEFAULT_SWIPE_STYLES = {\n right: { backgroundColor: 'rgba(34, 197, 94, 0.6)', label: '✓ Accept', labelStyle: DEFAULT_LABEL_STYLE },\n left: { backgroundColor: 'rgba(239, 68, 68, 0.6)', label: '✗ Reject', labelStyle: DEFAULT_LABEL_STYLE },\n up: { backgroundColor: 'rgba(59, 130, 246, 0.6)', label: '⭐ Super', labelStyle: DEFAULT_LABEL_STYLE },\n down: { backgroundColor: 'rgba(168, 85, 247, 0.6)', label: '⏭ Skip', labelStyle: DEFAULT_LABEL_STYLE },\n} as const;\n\n// Empty array constant to prevent recreating on each render\nconst EMPTY_PREVENT_SWIPE: readonly string[] = [];\n\nconst SwipeCardInner: React.FC<SwipeCardProps> = ({\n children,\n className = '',\n style,\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n threshold = 100,\n velocityThreshold = 0.5,\n maxRotation = 15,\n exitDuration = 300,\n returnDuration = 200,\n enableRotation = true,\n preventSwipe = EMPTY_PREVENT_SWIPE as any,\n swipeStyles,\n showOverlay: showOverlayProp = true,\n}) => {\n // Memoize callbacks object to prevent unnecessary hook updates\n const callbacks: SwipeCallbacks = useMemo(() => ({\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n }), [onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown, onSwipeStart, onSwipeEnd]);\n\n // Memoize config object\n const config: SwipeConfig = useMemo(() => ({\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n }), [threshold, velocityThreshold, maxRotation, exitDuration, returnDuration, enableRotation, preventSwipe]);\n\n const { ref, transform, opacity, transition, isDragging, deltaX, deltaY } = useSwipe(callbacks, config);\n\n // Memoize merged swipe styles\n const mergedSwipeStyles = useMemo(() => ({\n right: { \n ...DEFAULT_SWIPE_STYLES.right, \n ...swipeStyles?.right,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.right.labelStyle, ...swipeStyles?.right?.labelStyle }\n },\n left: { \n ...DEFAULT_SWIPE_STYLES.left, \n ...swipeStyles?.left,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.left.labelStyle, ...swipeStyles?.left?.labelStyle }\n },\n up: { \n ...DEFAULT_SWIPE_STYLES.up, \n ...swipeStyles?.up,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.up.labelStyle, ...swipeStyles?.up?.labelStyle }\n },\n down: { \n ...DEFAULT_SWIPE_STYLES.down, \n ...swipeStyles?.down,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.down.labelStyle, ...swipeStyles?.down?.labelStyle }\n },\n }), [\n swipeStyles?.right, \n swipeStyles?.left, \n swipeStyles?.up, \n swipeStyles?.down,\n ]);\n\n // Calculate swipe state - these are cheap, no need to memoize\n const absX = Math.abs(deltaX);\n const absY = Math.abs(deltaY);\n const isPrimaryHorizontal = absX >= absY;\n const swipeDistance = isPrimaryHorizontal ? absX : absY;\n const swipeProgress = Math.min(swipeDistance / threshold, 1);\n \n const isSwipingRight = isPrimaryHorizontal && deltaX > 20;\n const isSwipingLeft = isPrimaryHorizontal && deltaX < -20;\n const isSwipingUp = !isPrimaryHorizontal && deltaY < -20;\n const isSwipingDown = !isPrimaryHorizontal && deltaY > 20;\n \n const isActionInProgress = swipeProgress >= 0.15;\n const showOverlay = showOverlayProp && isDragging && swipeDistance > 10;\n\n // Calculate current direction info - single calculation\n const currentDirection = useMemo(() => {\n if (isSwipingRight) return 'right' as const;\n if (isSwipingLeft) return 'left' as const;\n if (isSwipingUp) return 'up' as const;\n if (isSwipingDown) return 'down' as const;\n return null;\n }, [isSwipingRight, isSwipingLeft, isSwipingUp, isSwipingDown]);\n\n const currentStyle = currentDirection ? mergedSwipeStyles[currentDirection] : null;\n const backgroundColor = currentStyle?.backgroundColor ?? 'transparent';\n const labelConfig = currentStyle ? { label: currentStyle.label, labelStyle: currentStyle.labelStyle } : null;\n\n // Memoize card style - only recalculate when values change\n const cardStyle: CSSProperties = useMemo(() => ({\n ...style,\n transform,\n opacity,\n transition,\n touchAction: 'none',\n userSelect: 'none',\n WebkitUserSelect: 'none',\n cursor: isDragging ? 'grabbing' : 'grab',\n willChange: isDragging ? 'transform, opacity' : 'auto',\n position: 'absolute',\n }), [style, transform, opacity, transition, isDragging]);\n\n // Memoize overlay style\n const overlayStyle: CSSProperties = useMemo(() => ({\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'inherit',\n pointerEvents: 'none',\n zIndex: 10,\n opacity: showOverlay ? swipeProgress : 0,\n transition: isDragging ? 'none' : 'opacity 200ms ease-out',\n backgroundColor: showOverlay ? backgroundColor : 'transparent',\n }), [showOverlay, swipeProgress, isDragging, backgroundColor]);\n\n // Memoize computed label style\n const computedLabelStyle: CSSProperties = useMemo(() => ({\n ...labelConfig?.labelStyle,\n transform: `scale(${0.8 + swipeProgress * 0.4})`,\n opacity: swipeProgress,\n }), [labelConfig?.labelStyle, swipeProgress]);\n\n return (\n <div\n ref={ref}\n className={`swipeon-card ${className}`}\n style={cardStyle}\n >\n {children}\n <div style={overlayStyle}>\n {showOverlay && isActionInProgress && labelConfig?.label && (\n <span style={computedLabelStyle}>\n {labelConfig.label}\n </span>\n )}\n </div>\n </div>\n );\n};\n\n// Memoize the entire component to prevent unnecessary re-renders from parent\nexport const SwipeCard = memo(SwipeCardInner);\n\nexport default SwipeCard;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["DEFAULT_CONFIG: Required<SwipeConfig>","DEFAULT_LABEL_STYLE: CSSProperties","EMPTY_PREVENT_SWIPE: readonly string[]","SwipeCardInner: React.FC<SwipeCardProps>","cardStyle: CSSProperties","overlayStyle: CSSProperties","computedLabelStyle: CSSProperties"],"sources":["../src/utils/helpers.ts","../src/hooks/useSwipe.ts","../src/components/SwipeCard.tsx"],"sourcesContent":["import { SwipeDirection } from '../types';\n\n/**\n * Calculate the distance between two points\n */\nexport const getDistance = (x1: number, y1: number, x2: number, y2: number): number => {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return Math.sqrt(dx * dx + dy * dy);\n};\n\n/**\n * Calculate velocity based on distance and time\n */\nexport const calculateVelocity = (distance: number, time: number): number => {\n if (time === 0) return 0;\n return Math.abs(distance / time);\n};\n\n/**\n * Determine the swipe direction based on deltas\n */\nexport const getSwipeDirection = (\n deltaX: number,\n deltaY: number,\n threshold: number = 50\n): SwipeDirection | null => {\n const absDeltaX = Math.abs(deltaX);\n const absDeltaY = Math.abs(deltaY);\n\n // Need minimum movement\n if (absDeltaX < threshold && absDeltaY < threshold) {\n return null;\n }\n\n // Determine primary direction\n if (absDeltaX > absDeltaY) {\n return deltaX > 0 ? 'right' : 'left';\n } else {\n return deltaY > 0 ? 'down' : 'up';\n }\n};\n\n/**\n * Calculate rotation angle based on horizontal movement\n */\nexport const calculateRotation = (\n deltaX: number,\n maxRotation: number = 15,\n containerWidth: number = 300\n): number => {\n const rotation = (deltaX / containerWidth) * maxRotation;\n return Math.max(-maxRotation, Math.min(maxRotation, rotation));\n};\n\n/**\n * Calculate opacity based on drag distance\n */\nexport const calculateOpacity = (\n deltaX: number,\n deltaY: number,\n threshold: number = 100\n): number => {\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const opacity = 1 - distance / (threshold * 3);\n return Math.max(0.5, Math.min(1, opacity));\n};\n\n/**\n * Clamp a value between min and max\n */\nexport const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value));\n};\n\n/**\n * Get touch/pointer coordinates from event\n */\nexport const getEventCoordinates = (\n event: TouchEvent | PointerEvent | MouseEvent | any\n): { x: number; y: number } => {\n if ('touches' in event && event.touches && event.touches.length > 0) {\n return {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n };\n }\n \n if ('clientX' in event && 'clientY' in event) {\n return {\n x: event.clientX,\n y: event.clientY,\n };\n }\n \n return { x: 0, y: 0 };\n};\n\n","import { useRef, useState, useCallback, useEffect, useMemo } from 'react';\nimport { SwipeConfig, SwipeCallbacks, GestureState, UseSwipeReturn } from '../types';\nimport {\n getSwipeDirection,\n calculateRotation,\n calculateOpacity,\n calculateVelocity,\n getEventCoordinates,\n} from '../utils/helpers';\n\nconst DEFAULT_CONFIG: Required<SwipeConfig> = {\n threshold: 100,\n velocityThreshold: 0.5,\n maxRotation: 15,\n exitDuration: 300,\n returnDuration: 200,\n enableRotation: true,\n preventSwipe: [],\n fadeOnSwipe: true,\n};\n\nexport const useSwipe = (\n callbacks: SwipeCallbacks = {},\n config: SwipeConfig = {}\n): UseSwipeReturn => {\n // Memoize config to prevent unnecessary recalculations\n const mergedConfig = useMemo(() => ({ ...DEFAULT_CONFIG, ...config }), [\n config.threshold,\n config.velocityThreshold,\n config.maxRotation,\n config.exitDuration,\n config.returnDuration,\n config.enableRotation,\n config.fadeOnSwipe,\n // Use JSON for array comparison (preventSwipe is typically small)\n JSON.stringify(config.preventSwipe),\n ]);\n\n const {\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n fadeOnSwipe,\n } = mergedConfig;\n\n const ref = useRef<HTMLDivElement>(null);\n const animationFrameRef = useRef<number | null>(null);\n const timeoutRefs = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n \n // Store callbacks in ref to avoid dependency issues\n const callbacksRef = useRef(callbacks);\n callbacksRef.current = callbacks;\n\n // Use refs for animation values that don't need to trigger re-renders during drag\n const transformRef = useRef('translate3d(0px, 0px, 0px) rotate(0deg)');\n const opacityRef = useRef(1);\n const transitionRef = useRef('none');\n\n // Single state for values that need to trigger re-renders\n const [renderState, setRenderState] = useState({\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n transition: 'none',\n });\n\n const [gestureState, setGestureState] = useState<GestureState>({\n isDragging: false,\n startX: 0,\n startY: 0,\n currentX: 0,\n currentY: 0,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: 0,\n });\n\n // Batch update render state\n const updateRenderState = useCallback((updates: Partial<typeof renderState>) => {\n setRenderState(prev => {\n const newState = { ...prev, ...updates };\n // Only update if values actually changed\n if (\n prev.transform === newState.transform &&\n prev.opacity === newState.opacity &&\n prev.transition === newState.transition\n ) {\n return prev;\n }\n return newState;\n });\n }, []);\n\n // Safe setTimeout that tracks timeouts for cleanup\n const safeTimeout = useCallback((fn: () => void, delay: number) => {\n const id = setTimeout(() => {\n timeoutRefs.current.delete(id);\n fn();\n }, delay);\n timeoutRefs.current.add(id);\n return id;\n }, []);\n\n // Handle swipe start\n const handleSwipeStart = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const coords = getEventCoordinates(event as any);\n const now = Date.now();\n\n setGestureState({\n isDragging: true,\n startX: coords.x,\n startY: coords.y,\n currentX: coords.x,\n currentY: coords.y,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: now,\n });\n\n transitionRef.current = 'none';\n updateRenderState({ transition: 'none' });\n \n callbacksRef.current.onSwipeStart?.();\n },\n [updateRenderState]\n );\n\n // Handle swipe move - use refs to avoid closure issues\n const gestureStateRef = useRef(gestureState);\n gestureStateRef.current = gestureState;\n\n const handleSwipeMove = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const coords = getEventCoordinates(event as any);\n let deltaX = coords.x - state.startX;\n let deltaY = coords.y - state.startY;\n\n // Constrain movement based on preventSwipe directions\n if (preventSwipe.includes('left') && deltaX < 0) deltaX = 0;\n if (preventSwipe.includes('right') && deltaX > 0) deltaX = 0;\n if (preventSwipe.includes('up') && deltaY < 0) deltaY = 0;\n if (preventSwipe.includes('down') && deltaY > 0) deltaY = 0;\n\n // Update gesture state\n setGestureState(prev => ({\n ...prev,\n currentX: coords.x,\n currentY: coords.y,\n deltaX,\n deltaY,\n }));\n\n // Use RAF for smooth updates - cancel previous frame\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n\n animationFrameRef.current = requestAnimationFrame(() => {\n const rotation = enableRotation ? calculateRotation(deltaX, maxRotation) : 0;\n const newOpacity = fadeOnSwipe ? calculateOpacity(deltaX, deltaY, threshold) : 1;\n const newTransform = `translate3d(${deltaX}px, ${deltaY}px, 0px) rotate(${rotation}deg)`;\n\n // Update refs immediately for internal use\n transformRef.current = newTransform;\n opacityRef.current = newOpacity;\n\n // Batch update to React state\n updateRenderState({\n transform: newTransform,\n opacity: newOpacity,\n });\n });\n },\n [enableRotation, maxRotation, threshold, preventSwipe, fadeOnSwipe, updateRenderState]\n );\n\n // Handle swipe end\n const handleSwipeEnd = useCallback(() => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const { deltaX, deltaY, startTime } = state;\n const timeDelta = Date.now() - startTime;\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const velocity = calculateVelocity(distance, timeDelta);\n\n const direction = getSwipeDirection(deltaX, deltaY, threshold / 2);\n const shouldSwipe = distance >= threshold || velocity >= velocityThreshold;\n\n // Check if direction is prevented\n const isDirectionPrevented = direction && preventSwipe.includes(direction);\n\n if (shouldSwipe && direction && !isDirectionPrevented) {\n // Execute swipe\n const exitTransition = `transform ${exitDuration}ms ease-out, opacity ${exitDuration}ms ease-out`;\n \n // Calculate exit position (move far enough off screen)\n const multiplier = 2;\n const exitX = deltaX * multiplier;\n const exitY = deltaY * multiplier;\n const rotation = enableRotation ? calculateRotation(exitX, maxRotation * 2) : 0;\n const exitTransform = `translate3d(${exitX}px, ${exitY}px, 0px) rotate(${rotation}deg)`;\n\n updateRenderState({\n transition: exitTransition,\n transform: exitTransform,\n opacity: 0,\n });\n\n // Trigger callback after animation\n safeTimeout(() => {\n switch (direction) {\n case 'left':\n callbacksRef.current.onSwipeLeft?.();\n break;\n case 'right':\n callbacksRef.current.onSwipeRight?.();\n break;\n case 'up':\n callbacksRef.current.onSwipeUp?.();\n break;\n case 'down':\n callbacksRef.current.onSwipeDown?.();\n break;\n }\n \n callbacksRef.current.onSwipeEnd?.();\n\n // Reset after callback\n safeTimeout(() => {\n updateRenderState({\n transition: 'none',\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n }, 50);\n }, exitDuration);\n } else {\n // Spring back\n const returnTransition = `transform ${returnDuration}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${returnDuration}ms ease-out`;\n \n updateRenderState({\n transition: returnTransition,\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n\n callbacksRef.current.onSwipeEnd?.();\n }\n\n setGestureState(prev => ({ ...prev, isDragging: false }));\n }, [\n threshold,\n velocityThreshold,\n exitDuration,\n returnDuration,\n enableRotation,\n maxRotation,\n preventSwipe,\n updateRenderState,\n safeTimeout,\n ]);\n\n // Stable event handler refs to avoid re-attaching listeners\n const handlersRef = useRef({\n handleSwipeStart,\n handleSwipeMove,\n handleSwipeEnd,\n });\n handlersRef.current = { handleSwipeStart, handleSwipeMove, handleSwipeEnd };\n\n // Attach event listeners with stable references\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const onPointerDown = (e: PointerEvent) => {\n handlersRef.current.handleSwipeStart(e);\n };\n\n element.addEventListener('pointerdown', onPointerDown);\n\n return () => {\n element.removeEventListener('pointerdown', onPointerDown);\n };\n }, []); // Empty deps - handlers are accessed via ref\n\n // Attach document listeners when dragging\n useEffect(() => {\n if (!gestureState.isDragging) return;\n\n const onPointerMove = (e: PointerEvent) => {\n handlersRef.current.handleSwipeMove(e);\n };\n\n const onPointerUp = () => {\n handlersRef.current.handleSwipeEnd();\n };\n\n document.addEventListener('pointermove', onPointerMove);\n document.addEventListener('pointerup', onPointerUp);\n document.addEventListener('pointercancel', onPointerUp);\n\n return () => {\n document.removeEventListener('pointermove', onPointerMove);\n document.removeEventListener('pointerup', onPointerUp);\n document.removeEventListener('pointercancel', onPointerUp);\n };\n }, [gestureState.isDragging]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n // Clear all pending timeouts\n timeoutRefs.current.forEach(id => clearTimeout(id));\n timeoutRefs.current.clear();\n };\n }, []);\n\n return {\n ref,\n transform: renderState.transform,\n opacity: renderState.opacity,\n transition: renderState.transition,\n isDragging: gestureState.isDragging,\n deltaX: gestureState.deltaX,\n deltaY: gestureState.deltaY,\n };\n};\n","import React, { CSSProperties, useMemo, memo } from 'react';\nimport { useSwipe } from '../hooks/useSwipe';\nimport { SwipeCardProps, SwipeCallbacks, SwipeConfig } from '../types';\n\n/**\n * SwipeCard Component\n * \n * A performant swipeable card component with smooth animations.\n * Supports swipe in all four directions: left, right, up, and down.\n * \n * @example\n * ```tsx\n * <SwipeCard\n * onSwipeLeft={() => console.log('Swiped left')}\n * onSwipeRight={() => console.log('Swiped right')}\n * threshold={100}\n * swipeStyles={{\n * // backgroundColor is optional - transparent by default (card content stays visible)\n * right: { \n * backgroundColor: 'rgba(34, 197, 94, 0.6)', // green overlay\n * label: '👍 Like',\n * labelStyle: { position: 'absolute', top: 20, right: 20 }\n * },\n * left: { \n * backgroundColor: 'rgba(239, 68, 68, 0.6)', // red overlay\n * label: '👎 Nope',\n * labelStyle: { position: 'absolute', top: 20, left: 20 }\n * },\n * }}\n * >\n * <div>Your content here</div>\n * </SwipeCard>\n * ```\n */\n\n// Default label style - constant, no need to recreate\nconst DEFAULT_LABEL_STYLE: CSSProperties = {\n fontSize: '2rem',\n fontWeight: 'bold',\n color: '#fff',\n letterSpacing: '2px',\n textShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n};\n\n// Default styles for each direction - constant\n// backgroundColor defaults to transparent so card content remains visible unless explicitly set\nconst DEFAULT_SWIPE_STYLES = {\n right: { backgroundColor: 'transparent', label: '✓ Accept', labelStyle: DEFAULT_LABEL_STYLE },\n left: { backgroundColor: 'transparent', label: '✗ Reject', labelStyle: DEFAULT_LABEL_STYLE },\n up: { backgroundColor: 'transparent', label: '⭐ Super', labelStyle: DEFAULT_LABEL_STYLE },\n down: { backgroundColor: 'transparent', label: '⏭ Skip', labelStyle: DEFAULT_LABEL_STYLE },\n} as const;\n\n// Empty array constant to prevent recreating on each render\nconst EMPTY_PREVENT_SWIPE: readonly string[] = [];\n\nconst SwipeCardInner: React.FC<SwipeCardProps> = ({\n children,\n className = '',\n style,\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n threshold = 100,\n velocityThreshold = 0.5,\n maxRotation = 15,\n exitDuration = 300,\n returnDuration = 200,\n enableRotation = true,\n preventSwipe = EMPTY_PREVENT_SWIPE as any,\n fadeOnSwipe = true,\n swipeStyles,\n showOverlay: showOverlayProp = true,\n}) => {\n // Memoize callbacks object to prevent unnecessary hook updates\n const callbacks: SwipeCallbacks = useMemo(() => ({\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n }), [onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown, onSwipeStart, onSwipeEnd]);\n\n // Memoize config object\n const config: SwipeConfig = useMemo(() => ({\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n fadeOnSwipe,\n }), [threshold, velocityThreshold, maxRotation, exitDuration, returnDuration, enableRotation, preventSwipe, fadeOnSwipe]);\n\n const { ref, transform, opacity, transition, isDragging, deltaX, deltaY } = useSwipe(callbacks, config);\n\n // Memoize merged swipe styles\n const mergedSwipeStyles = useMemo(() => ({\n right: { \n ...DEFAULT_SWIPE_STYLES.right, \n ...swipeStyles?.right,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.right.labelStyle, ...swipeStyles?.right?.labelStyle }\n },\n left: { \n ...DEFAULT_SWIPE_STYLES.left, \n ...swipeStyles?.left,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.left.labelStyle, ...swipeStyles?.left?.labelStyle }\n },\n up: { \n ...DEFAULT_SWIPE_STYLES.up, \n ...swipeStyles?.up,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.up.labelStyle, ...swipeStyles?.up?.labelStyle }\n },\n down: { \n ...DEFAULT_SWIPE_STYLES.down, \n ...swipeStyles?.down,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.down.labelStyle, ...swipeStyles?.down?.labelStyle }\n },\n }), [\n swipeStyles?.right, \n swipeStyles?.left, \n swipeStyles?.up, \n swipeStyles?.down,\n ]);\n\n // Calculate swipe state - these are cheap, no need to memoize\n const absX = Math.abs(deltaX);\n const absY = Math.abs(deltaY);\n const isPrimaryHorizontal = absX >= absY;\n const swipeDistance = isPrimaryHorizontal ? absX : absY;\n const swipeProgress = Math.min(swipeDistance / threshold, 1);\n \n const isSwipingRight = isPrimaryHorizontal && deltaX > 20;\n const isSwipingLeft = isPrimaryHorizontal && deltaX < -20;\n const isSwipingUp = !isPrimaryHorizontal && deltaY < -20;\n const isSwipingDown = !isPrimaryHorizontal && deltaY > 20;\n \n const isActionInProgress = swipeProgress >= 0.15;\n const showOverlay = showOverlayProp && isDragging && swipeDistance > 10;\n\n // Calculate current direction info - single calculation\n const currentDirection = useMemo(() => {\n if (isSwipingRight) return 'right' as const;\n if (isSwipingLeft) return 'left' as const;\n if (isSwipingUp) return 'up' as const;\n if (isSwipingDown) return 'down' as const;\n return null;\n }, [isSwipingRight, isSwipingLeft, isSwipingUp, isSwipingDown]);\n\n const currentStyle = currentDirection ? mergedSwipeStyles[currentDirection] : null;\n const backgroundColor = currentStyle?.backgroundColor ?? 'inherit';\n const labelConfig = currentStyle ? { label: currentStyle.label, labelStyle: currentStyle.labelStyle } : null;\n\n // Memoize card style - only recalculate when values change\n const cardStyle: CSSProperties = useMemo(() => ({\n ...style,\n transform,\n opacity,\n transition,\n touchAction: 'none',\n userSelect: 'none',\n WebkitUserSelect: 'none',\n cursor: isDragging ? 'grabbing' : 'grab',\n willChange: isDragging ? 'transform, opacity' : 'auto',\n position: 'absolute',\n }), [style, transform, opacity, transition, isDragging]);\n\n // Memoize overlay style\n const overlayStyle: CSSProperties = useMemo(() => ({\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'inherit',\n pointerEvents: 'none',\n zIndex: 10,\n opacity: showOverlay ? swipeProgress : 0,\n transition: isDragging ? 'none' : 'opacity 200ms ease-out',\n backgroundColor: showOverlay ? backgroundColor : 'inherit',\n }), [showOverlay, swipeProgress, isDragging, backgroundColor]);\n\n // Memoize computed label style\n const computedLabelStyle: CSSProperties = useMemo(() => ({\n ...labelConfig?.labelStyle,\n transform: `scale(${0.8 + swipeProgress * 0.4})`,\n opacity: swipeProgress,\n }), [labelConfig?.labelStyle, swipeProgress]);\n\n return (\n <div\n ref={ref}\n className={`swipeon-card ${className}`}\n style={cardStyle}\n >\n {children}\n <div style={overlayStyle}>\n {showOverlay && isActionInProgress && labelConfig?.label && (\n <span style={computedLabelStyle}>\n {labelConfig.label}\n </span>\n )}\n </div>\n </div>\n );\n};\n\n// Memoize the entire component to prevent unnecessary re-renders from parent\nexport const SwipeCard = memo(SwipeCardInner);\n\nexport default SwipeCard;\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -35,6 +35,8 @@ interface SwipeConfig {
35
35
  enableRotation?: boolean;
36
36
  /** Array of directions to prevent swiping in */
37
37
  preventSwipe?: SwipeDirection[];
38
+ /** Enable/disable card opacity fade while swiping (default: true) */
39
+ fadeOnSwipe?: boolean;
38
40
  }
39
41
  /**
40
42
  * Style configuration for each swipe direction
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/index.ts","../src/components/SwipeCard.tsx","../src/hooks/useSwipe.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAKiB,KALL,cAAA,GAKmB,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,MAAA;AAY/B;AAoBA;AAYA;AAEU,UA9CO,cAAA,CA8CP;EAED,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEF,YAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEE,SAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAmB,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAMX,YAAA,CAAA,EAAA,GAAA,GAAkB,IAAA;EAUlB,UAAA,CAAA,EAAA,GAAA,GAAe,IAAA;;;;;AAAqC,UAxDpD,WAAA,CAwDoD;EAAkB;EActE,SAAA,CAAA,EAAA,MAAY;EAgBZ;;;;ECyGJ;;;;ECjMA;EACA,cAAA,CAAA,EAAA,OAAA;EACH;EACP,YAAA,CAAA,EFac,cEbd,EAAA;;;;;UFmBc,mBAAA;;;;;;eAMF;;;;;UAME,WAAA;;UAEP;;SAED;;OAEF;;SAEE;;;;;UAMQ,kBAAA;;gBAED;;;;;;;UAQC,cAAA,SAAuB,gBAAgB,aAAa;;YAEzD;;;;UAIF;;;;;;;UAQO,YAAA;;;;;;;;;aASJ;;;;;;UAOI,cAAA;OACV,KAAA,CAAM,UAAU;;;;;;;;;;cCwGV,WAAS,OAAA,CAAA,qBAAA;;;cCjMT,uBACA,yBACH,gBACP"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/index.ts","../src/components/SwipeCard.tsx","../src/hooks/useSwipe.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAKiB,KALL,cAAA,GAKmB,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,MAAA;AAY/B;AAsBA;AAYA;AAEU,UAhDO,cAAA,CAgDP;EAED,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEF,YAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEE,SAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAmB,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAMX,YAAA,CAAA,EAAA,GAAA,GAAkB,IAAA;EAUlB,UAAA,CAAA,EAAA,GAAA,GAAe,IAAA;;;;;AAAqC,UA1DpD,WAAA,CA0DoD;EAAkB;EActE,SAAA,CAAA,EAAA,MAAY;EAgBZ;;;;EC0GJ;;;;ECnMA;EACA,cAAA,CAAA,EAAA,OAAA;EACH;EACP,YAAA,CAAA,EFYc,cEZd,EAAA;EA8TF;;;;;;UF1SgB,mBAAA;;;;;;eAMF;;;;;UAME,WAAA;;UAEP;;SAED;;OAEF;;SAEE;;;;;UAMQ,kBAAA;;gBAED;;;;;;;UAQC,cAAA,SAAuB,gBAAgB,aAAa;;YAEzD;;;;UAIF;;;;;;;UAQO,YAAA;;;;;;;;;aASJ;;;;;;UAOI,cAAA;OACV,KAAA,CAAM,UAAU;;;;;;;;;;cCyGV,WAAS,OAAA,CAAA,qBAAA;;;cCnMT,uBACA,yBACH,gBACP"}
package/dist/index.d.mts CHANGED
@@ -35,6 +35,8 @@ interface SwipeConfig {
35
35
  enableRotation?: boolean;
36
36
  /** Array of directions to prevent swiping in */
37
37
  preventSwipe?: SwipeDirection[];
38
+ /** Enable/disable card opacity fade while swiping (default: true) */
39
+ fadeOnSwipe?: boolean;
38
40
  }
39
41
  /**
40
42
  * Style configuration for each swipe direction
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/components/SwipeCard.tsx","../src/hooks/useSwipe.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAKiB,KALL,cAAA,GAKmB,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,MAAA;AAY/B;AAoBA;AAYA;AAEU,UA9CO,cAAA,CA8CP;EAED,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEF,YAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEE,SAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAmB,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAMX,YAAA,CAAA,EAAA,GAAA,GAAkB,IAAA;EAUlB,UAAA,CAAA,EAAA,GAAA,GAAe,IAAA;;;;;AAAqC,UAxDpD,WAAA,CAwDoD;EAAkB;EActE,SAAA,CAAA,EAAA,MAAY;EAgBZ;;;;ECyGJ;;;;ECjMA;EACA,cAAA,CAAA,EAAA,OAAA;EACH;EACP,YAAA,CAAA,EFac,cEbd,EAAA;;;;;UFmBc,mBAAA;;;;;;eAMF;;;;;UAME,WAAA;;UAEP;;SAED;;OAEF;;SAEE;;;;;UAMQ,kBAAA;;gBAED;;;;;;;UAQC,cAAA,SAAuB,gBAAgB,aAAa;;YAEzD;;;;UAIF;;;;;;;UAQO,YAAA;;;;;;;;;aASJ;;;;;;UAOI,cAAA;OACV,KAAA,CAAM,UAAU;;;;;;;;;;cCwGV,WAAS,OAAA,CAAA,qBAAA;;;cCjMT,uBACA,yBACH,gBACP"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/components/SwipeCard.tsx","../src/hooks/useSwipe.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAKiB,KALL,cAAA,GAKmB,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,MAAA;AAY/B;AAsBA;AAYA;AAEU,UAhDO,cAAA,CAgDP;EAED,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEF,YAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEE,SAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAmB,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAMX,YAAA,CAAA,EAAA,GAAA,GAAkB,IAAA;EAUlB,UAAA,CAAA,EAAA,GAAA,GAAe,IAAA;;;;;AAAqC,UA1DpD,WAAA,CA0DoD;EAAkB;EActE,SAAA,CAAA,EAAA,MAAY;EAgBZ;;;;EC0GJ;;;;ECnMA;EACA,cAAA,CAAA,EAAA,OAAA;EACH;EACP,YAAA,CAAA,EFYc,cEZd,EAAA;EA8TF;;;;;;UF1SgB,mBAAA;;;;;;eAMF;;;;;UAME,WAAA;;UAEP;;SAED;;OAEF;;SAEE;;;;;UAMQ,kBAAA;;gBAED;;;;;;;UAQC,cAAA,SAAuB,gBAAgB,aAAa;;YAEzD;;;;UAIF;;;;;;;UAQO,YAAA;;;;;;;;;aASJ;;;;;;UAOI,cAAA;OACV,KAAA,CAAM,UAAU;;;;;;;;;;cCyGV,WAAS,OAAA,CAAA,qBAAA;;;cCnMT,uBACA,yBACH,gBACP"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import e,{memo as t,useCallback as n,useEffect as r,useMemo as i,useRef as a,useState as o}from"react";const s=(e,t)=>t===0?0:Math.abs(e/t),c=(e,t,n=50)=>{let r=Math.abs(e),i=Math.abs(t);return r<n&&i<n?null:r>i?e>0?`right`:`left`:t>0?`down`:`up`},l=(e,t=15,n=300)=>{let r=e/n*t;return Math.max(-t,Math.min(t,r))},u=(e,t,n=100)=>{let r=1-Math.sqrt(e*e+t*t)/(n*3);return Math.max(.5,Math.min(1,r))},d=e=>`touches`in e&&e.touches&&e.touches.length>0?{x:e.touches[0].clientX,y:e.touches[0].clientY}:`clientX`in e&&`clientY`in e?{x:e.clientX,y:e.clientY}:{x:0,y:0},f={threshold:100,velocityThreshold:.5,maxRotation:15,exitDuration:300,returnDuration:200,enableRotation:!0,preventSwipe:[]},p=(e={},t={})=>{let{threshold:p,velocityThreshold:m,maxRotation:h,exitDuration:g,returnDuration:_,enableRotation:v,preventSwipe:y}=i(()=>({...f,...t}),[t.threshold,t.velocityThreshold,t.maxRotation,t.exitDuration,t.returnDuration,t.enableRotation,JSON.stringify(t.preventSwipe)]),b=a(null),x=a(null),S=a(new Set),C=a(e);C.current=e;let w=a(`translate3d(0px, 0px, 0px) rotate(0deg)`),T=a(1),E=a(`none`),[D,O]=o({transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1,transition:`none`}),[k,A]=o({isDragging:!1,startX:0,startY:0,currentX:0,currentY:0,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:0}),j=n(e=>{O(t=>{let n={...t,...e};return t.transform===n.transform&&t.opacity===n.opacity&&t.transition===n.transition?t:n})},[]),M=n((e,t)=>{let n=setTimeout(()=>{S.current.delete(n),e()},t);return S.current.add(n),n},[]),N=n(e=>{let t=d(e),n=Date.now();A({isDragging:!0,startX:t.x,startY:t.y,currentX:t.x,currentY:t.y,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:n}),E.current=`none`,j({transition:`none`}),C.current.onSwipeStart?.()},[j]),P=a(k);P.current=k;let F=n(e=>{let t=P.current;if(!t.isDragging)return;let n=d(e),r=n.x-t.startX,i=n.y-t.startY;y.includes(`left`)&&r<0&&(r=0),y.includes(`right`)&&r>0&&(r=0),y.includes(`up`)&&i<0&&(i=0),y.includes(`down`)&&i>0&&(i=0),A(e=>({...e,currentX:n.x,currentY:n.y,deltaX:r,deltaY:i})),x.current&&cancelAnimationFrame(x.current),x.current=requestAnimationFrame(()=>{let e=v?l(r,h):0,t=u(r,i,p),n=`translate3d(${r}px, ${i}px, 0px) rotate(${e}deg)`;w.current=n,T.current=t,j({transform:n,opacity:t})})},[v,h,p,y,j]),I=n(()=>{let e=P.current;if(!e.isDragging)return;let{deltaX:t,deltaY:n,startTime:r}=e,i=Date.now()-r,a=Math.sqrt(t*t+n*n),o=s(a,i),u=c(t,n,p/2),d=a>=p||o>=m,f=u&&y.includes(u);if(d&&u&&!f){let e=`transform ${g}ms ease-out, opacity ${g}ms ease-out`,r=t*2;j({transition:e,transform:`translate3d(${r}px, ${n*2}px, 0px) rotate(${v?l(r,h*2):0}deg)`,opacity:0}),M(()=>{switch(u){case`left`:C.current.onSwipeLeft?.();break;case`right`:C.current.onSwipeRight?.();break;case`up`:C.current.onSwipeUp?.();break;case`down`:C.current.onSwipeDown?.();break}C.current.onSwipeEnd?.(),M(()=>{j({transition:`none`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1})},50)},g)}else j({transition:`transform ${_}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${_}ms ease-out`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1}),C.current.onSwipeEnd?.();A(e=>({...e,isDragging:!1}))},[p,m,g,_,v,h,y,j,M]),L=a({handleSwipeStart:N,handleSwipeMove:F,handleSwipeEnd:I});return L.current={handleSwipeStart:N,handleSwipeMove:F,handleSwipeEnd:I},r(()=>{let e=b.current;if(!e)return;let t=e=>{L.current.handleSwipeStart(e)};return e.addEventListener(`pointerdown`,t),()=>{e.removeEventListener(`pointerdown`,t)}},[]),r(()=>{if(!k.isDragging)return;let e=e=>{L.current.handleSwipeMove(e)},t=()=>{L.current.handleSwipeEnd()};return document.addEventListener(`pointermove`,e),document.addEventListener(`pointerup`,t),document.addEventListener(`pointercancel`,t),()=>{document.removeEventListener(`pointermove`,e),document.removeEventListener(`pointerup`,t),document.removeEventListener(`pointercancel`,t)}},[k.isDragging]),r(()=>()=>{x.current&&cancelAnimationFrame(x.current),S.current.forEach(e=>clearTimeout(e)),S.current.clear()},[]),{ref:b,transform:D.transform,opacity:D.opacity,transition:D.transition,isDragging:k.isDragging,deltaX:k.deltaX,deltaY:k.deltaY}},m={fontSize:`2rem`,fontWeight:`bold`,color:`#fff`,textTransform:`uppercase`,letterSpacing:`2px`,textShadow:`0 2px 8px rgba(0, 0, 0, 0.3)`},h={right:{backgroundColor:`rgba(34, 197, 94, 0.6)`,label:`✓ Accept`,labelStyle:m},left:{backgroundColor:`rgba(239, 68, 68, 0.6)`,label:`✗ Reject`,labelStyle:m},up:{backgroundColor:`rgba(59, 130, 246, 0.6)`,label:`⭐ Super`,labelStyle:m},down:{backgroundColor:`rgba(168, 85, 247, 0.6)`,label:`⏭ Skip`,labelStyle:m}},g=[],_=t(({children:t,className:n=``,style:r,onSwipeLeft:a,onSwipeRight:o,onSwipeUp:s,onSwipeDown:c,onSwipeStart:l,onSwipeEnd:u,threshold:d=100,velocityThreshold:f=.5,maxRotation:m=15,exitDuration:_=300,returnDuration:v=200,enableRotation:y=!0,preventSwipe:b=g,swipeStyles:x,showOverlay:S=!0})=>{let{ref:C,transform:w,opacity:T,transition:E,isDragging:D,deltaX:O,deltaY:k}=p(i(()=>({onSwipeLeft:a,onSwipeRight:o,onSwipeUp:s,onSwipeDown:c,onSwipeStart:l,onSwipeEnd:u}),[a,o,s,c,l,u]),i(()=>({threshold:d,velocityThreshold:f,maxRotation:m,exitDuration:_,returnDuration:v,enableRotation:y,preventSwipe:b}),[d,f,m,_,v,y,b])),A=i(()=>({right:{...h.right,...x?.right,labelStyle:{...h.right.labelStyle,...x?.right?.labelStyle}},left:{...h.left,...x?.left,labelStyle:{...h.left.labelStyle,...x?.left?.labelStyle}},up:{...h.up,...x?.up,labelStyle:{...h.up.labelStyle,...x?.up?.labelStyle}},down:{...h.down,...x?.down,labelStyle:{...h.down.labelStyle,...x?.down?.labelStyle}}}),[x?.right,x?.left,x?.up,x?.down]),j=Math.abs(O),M=Math.abs(k),N=j>=M,P=N?j:M,F=Math.min(P/d,1),I=N&&O>20,L=N&&O<-20,R=!N&&k<-20,z=!N&&k>20,B=F>=.15,V=S&&D&&P>10,H=i(()=>I?`right`:L?`left`:R?`up`:z?`down`:null,[I,L,R,z]),U=H?A[H]:null,W=U?.backgroundColor??`transparent`,G=U?{label:U.label,labelStyle:U.labelStyle}:null,K=i(()=>({...r,transform:w,opacity:T,transition:E,touchAction:`none`,userSelect:`none`,WebkitUserSelect:`none`,cursor:D?`grabbing`:`grab`,willChange:D?`transform, opacity`:`auto`,position:`absolute`}),[r,w,T,E,D]),q=i(()=>({position:`absolute`,top:0,left:0,right:0,bottom:0,display:`flex`,alignItems:`center`,justifyContent:`center`,borderRadius:`inherit`,pointerEvents:`none`,zIndex:10,opacity:V?F:0,transition:D?`none`:`opacity 200ms ease-out`,backgroundColor:V?W:`transparent`}),[V,F,D,W]),J=i(()=>({...G?.labelStyle,transform:`scale(${.8+F*.4})`,opacity:F}),[G?.labelStyle,F]);return e.createElement(`div`,{ref:C,className:`swipeon-card ${n}`,style:K},t,e.createElement(`div`,{style:q},V&&B&&G?.label&&e.createElement(`span`,{style:J},G.label)))});export{_ as SwipeCard,p as useSwipe};
1
+ import e,{memo as t,useCallback as n,useEffect as r,useMemo as i,useRef as a,useState as o}from"react";const s=(e,t)=>t===0?0:Math.abs(e/t),c=(e,t,n=50)=>{let r=Math.abs(e),i=Math.abs(t);return r<n&&i<n?null:r>i?e>0?`right`:`left`:t>0?`down`:`up`},l=(e,t=15,n=300)=>{let r=e/n*t;return Math.max(-t,Math.min(t,r))},u=(e,t,n=100)=>{let r=1-Math.sqrt(e*e+t*t)/(n*3);return Math.max(.5,Math.min(1,r))},d=e=>`touches`in e&&e.touches&&e.touches.length>0?{x:e.touches[0].clientX,y:e.touches[0].clientY}:`clientX`in e&&`clientY`in e?{x:e.clientX,y:e.clientY}:{x:0,y:0},f={threshold:100,velocityThreshold:.5,maxRotation:15,exitDuration:300,returnDuration:200,enableRotation:!0,preventSwipe:[],fadeOnSwipe:!0},p=(e={},t={})=>{let{threshold:p,velocityThreshold:m,maxRotation:h,exitDuration:g,returnDuration:_,enableRotation:v,preventSwipe:y,fadeOnSwipe:b}=i(()=>({...f,...t}),[t.threshold,t.velocityThreshold,t.maxRotation,t.exitDuration,t.returnDuration,t.enableRotation,t.fadeOnSwipe,JSON.stringify(t.preventSwipe)]),x=a(null),S=a(null),C=a(new Set),w=a(e);w.current=e;let T=a(`translate3d(0px, 0px, 0px) rotate(0deg)`),E=a(1),D=a(`none`),[O,k]=o({transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1,transition:`none`}),[A,j]=o({isDragging:!1,startX:0,startY:0,currentX:0,currentY:0,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:0}),M=n(e=>{k(t=>{let n={...t,...e};return t.transform===n.transform&&t.opacity===n.opacity&&t.transition===n.transition?t:n})},[]),N=n((e,t)=>{let n=setTimeout(()=>{C.current.delete(n),e()},t);return C.current.add(n),n},[]),P=n(e=>{let t=d(e),n=Date.now();j({isDragging:!0,startX:t.x,startY:t.y,currentX:t.x,currentY:t.y,deltaX:0,deltaY:0,velocity:0,direction:null,startTime:n}),D.current=`none`,M({transition:`none`}),w.current.onSwipeStart?.()},[M]),F=a(A);F.current=A;let I=n(e=>{let t=F.current;if(!t.isDragging)return;let n=d(e),r=n.x-t.startX,i=n.y-t.startY;y.includes(`left`)&&r<0&&(r=0),y.includes(`right`)&&r>0&&(r=0),y.includes(`up`)&&i<0&&(i=0),y.includes(`down`)&&i>0&&(i=0),j(e=>({...e,currentX:n.x,currentY:n.y,deltaX:r,deltaY:i})),S.current&&cancelAnimationFrame(S.current),S.current=requestAnimationFrame(()=>{let e=v?l(r,h):0,t=b?u(r,i,p):1,n=`translate3d(${r}px, ${i}px, 0px) rotate(${e}deg)`;T.current=n,E.current=t,M({transform:n,opacity:t})})},[v,h,p,y,b,M]),L=n(()=>{let e=F.current;if(!e.isDragging)return;let{deltaX:t,deltaY:n,startTime:r}=e,i=Date.now()-r,a=Math.sqrt(t*t+n*n),o=s(a,i),u=c(t,n,p/2),d=a>=p||o>=m,f=u&&y.includes(u);if(d&&u&&!f){let e=`transform ${g}ms ease-out, opacity ${g}ms ease-out`,r=t*2;M({transition:e,transform:`translate3d(${r}px, ${n*2}px, 0px) rotate(${v?l(r,h*2):0}deg)`,opacity:0}),N(()=>{switch(u){case`left`:w.current.onSwipeLeft?.();break;case`right`:w.current.onSwipeRight?.();break;case`up`:w.current.onSwipeUp?.();break;case`down`:w.current.onSwipeDown?.();break}w.current.onSwipeEnd?.(),N(()=>{M({transition:`none`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1})},50)},g)}else M({transition:`transform ${_}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${_}ms ease-out`,transform:`translate3d(0px, 0px, 0px) rotate(0deg)`,opacity:1}),w.current.onSwipeEnd?.();j(e=>({...e,isDragging:!1}))},[p,m,g,_,v,h,y,M,N]),R=a({handleSwipeStart:P,handleSwipeMove:I,handleSwipeEnd:L});return R.current={handleSwipeStart:P,handleSwipeMove:I,handleSwipeEnd:L},r(()=>{let e=x.current;if(!e)return;let t=e=>{R.current.handleSwipeStart(e)};return e.addEventListener(`pointerdown`,t),()=>{e.removeEventListener(`pointerdown`,t)}},[]),r(()=>{if(!A.isDragging)return;let e=e=>{R.current.handleSwipeMove(e)},t=()=>{R.current.handleSwipeEnd()};return document.addEventListener(`pointermove`,e),document.addEventListener(`pointerup`,t),document.addEventListener(`pointercancel`,t),()=>{document.removeEventListener(`pointermove`,e),document.removeEventListener(`pointerup`,t),document.removeEventListener(`pointercancel`,t)}},[A.isDragging]),r(()=>()=>{S.current&&cancelAnimationFrame(S.current),C.current.forEach(e=>clearTimeout(e)),C.current.clear()},[]),{ref:x,transform:O.transform,opacity:O.opacity,transition:O.transition,isDragging:A.isDragging,deltaX:A.deltaX,deltaY:A.deltaY}},m={fontSize:`2rem`,fontWeight:`bold`,color:`#fff`,letterSpacing:`2px`,textShadow:`0 2px 8px rgba(0, 0, 0, 0.3)`},h={right:{backgroundColor:`transparent`,label:`✓ Accept`,labelStyle:m},left:{backgroundColor:`transparent`,label:`✗ Reject`,labelStyle:m},up:{backgroundColor:`transparent`,label:`⭐ Super`,labelStyle:m},down:{backgroundColor:`transparent`,label:`⏭ Skip`,labelStyle:m}},g=[],_=t(({children:t,className:n=``,style:r,onSwipeLeft:a,onSwipeRight:o,onSwipeUp:s,onSwipeDown:c,onSwipeStart:l,onSwipeEnd:u,threshold:d=100,velocityThreshold:f=.5,maxRotation:m=15,exitDuration:_=300,returnDuration:v=200,enableRotation:y=!0,preventSwipe:b=g,fadeOnSwipe:x=!0,swipeStyles:S,showOverlay:C=!0})=>{let{ref:w,transform:T,opacity:E,transition:D,isDragging:O,deltaX:k,deltaY:A}=p(i(()=>({onSwipeLeft:a,onSwipeRight:o,onSwipeUp:s,onSwipeDown:c,onSwipeStart:l,onSwipeEnd:u}),[a,o,s,c,l,u]),i(()=>({threshold:d,velocityThreshold:f,maxRotation:m,exitDuration:_,returnDuration:v,enableRotation:y,preventSwipe:b,fadeOnSwipe:x}),[d,f,m,_,v,y,b,x])),j=i(()=>({right:{...h.right,...S?.right,labelStyle:{...h.right.labelStyle,...S?.right?.labelStyle}},left:{...h.left,...S?.left,labelStyle:{...h.left.labelStyle,...S?.left?.labelStyle}},up:{...h.up,...S?.up,labelStyle:{...h.up.labelStyle,...S?.up?.labelStyle}},down:{...h.down,...S?.down,labelStyle:{...h.down.labelStyle,...S?.down?.labelStyle}}}),[S?.right,S?.left,S?.up,S?.down]),M=Math.abs(k),N=Math.abs(A),P=M>=N,F=P?M:N,I=Math.min(F/d,1),L=P&&k>20,R=P&&k<-20,z=!P&&A<-20,B=!P&&A>20,V=I>=.15,H=C&&O&&F>10,U=i(()=>L?`right`:R?`left`:z?`up`:B?`down`:null,[L,R,z,B]),W=U?j[U]:null,G=W?.backgroundColor??`inherit`,K=W?{label:W.label,labelStyle:W.labelStyle}:null,q=i(()=>({...r,transform:T,opacity:E,transition:D,touchAction:`none`,userSelect:`none`,WebkitUserSelect:`none`,cursor:O?`grabbing`:`grab`,willChange:O?`transform, opacity`:`auto`,position:`absolute`}),[r,T,E,D,O]),J=i(()=>({position:`absolute`,top:0,left:0,right:0,bottom:0,display:`flex`,alignItems:`center`,justifyContent:`center`,borderRadius:`inherit`,pointerEvents:`none`,zIndex:10,opacity:H?I:0,transition:O?`none`:`opacity 200ms ease-out`,backgroundColor:H?G:`inherit`}),[H,I,O,G]),Y=i(()=>({...K?.labelStyle,transform:`scale(${.8+I*.4})`,opacity:I}),[K?.labelStyle,I]);return e.createElement(`div`,{ref:w,className:`swipeon-card ${n}`,style:q},t,e.createElement(`div`,{style:J},H&&V&&K?.label&&e.createElement(`span`,{style:Y},K.label)))});export{_ as SwipeCard,p as useSwipe};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["DEFAULT_CONFIG: Required<SwipeConfig>","DEFAULT_LABEL_STYLE: CSSProperties","EMPTY_PREVENT_SWIPE: readonly string[]","SwipeCardInner: React.FC<SwipeCardProps>","cardStyle: CSSProperties","overlayStyle: CSSProperties","computedLabelStyle: CSSProperties"],"sources":["../src/utils/helpers.ts","../src/hooks/useSwipe.ts","../src/components/SwipeCard.tsx"],"sourcesContent":["import { SwipeDirection } from '../types';\n\n/**\n * Calculate the distance between two points\n */\nexport const getDistance = (x1: number, y1: number, x2: number, y2: number): number => {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return Math.sqrt(dx * dx + dy * dy);\n};\n\n/**\n * Calculate velocity based on distance and time\n */\nexport const calculateVelocity = (distance: number, time: number): number => {\n if (time === 0) return 0;\n return Math.abs(distance / time);\n};\n\n/**\n * Determine the swipe direction based on deltas\n */\nexport const getSwipeDirection = (\n deltaX: number,\n deltaY: number,\n threshold: number = 50\n): SwipeDirection | null => {\n const absDeltaX = Math.abs(deltaX);\n const absDeltaY = Math.abs(deltaY);\n\n // Need minimum movement\n if (absDeltaX < threshold && absDeltaY < threshold) {\n return null;\n }\n\n // Determine primary direction\n if (absDeltaX > absDeltaY) {\n return deltaX > 0 ? 'right' : 'left';\n } else {\n return deltaY > 0 ? 'down' : 'up';\n }\n};\n\n/**\n * Calculate rotation angle based on horizontal movement\n */\nexport const calculateRotation = (\n deltaX: number,\n maxRotation: number = 15,\n containerWidth: number = 300\n): number => {\n const rotation = (deltaX / containerWidth) * maxRotation;\n return Math.max(-maxRotation, Math.min(maxRotation, rotation));\n};\n\n/**\n * Calculate opacity based on drag distance\n */\nexport const calculateOpacity = (\n deltaX: number,\n deltaY: number,\n threshold: number = 100\n): number => {\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const opacity = 1 - distance / (threshold * 3);\n return Math.max(0.5, Math.min(1, opacity));\n};\n\n/**\n * Clamp a value between min and max\n */\nexport const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value));\n};\n\n/**\n * Get touch/pointer coordinates from event\n */\nexport const getEventCoordinates = (\n event: TouchEvent | PointerEvent | MouseEvent | any\n): { x: number; y: number } => {\n if ('touches' in event && event.touches && event.touches.length > 0) {\n return {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n };\n }\n \n if ('clientX' in event && 'clientY' in event) {\n return {\n x: event.clientX,\n y: event.clientY,\n };\n }\n \n return { x: 0, y: 0 };\n};\n\n","import { useRef, useState, useCallback, useEffect, useMemo } from 'react';\nimport { SwipeConfig, SwipeCallbacks, GestureState, UseSwipeReturn } from '../types';\nimport {\n getSwipeDirection,\n calculateRotation,\n calculateOpacity,\n calculateVelocity,\n getEventCoordinates,\n} from '../utils/helpers';\n\nconst DEFAULT_CONFIG: Required<SwipeConfig> = {\n threshold: 100,\n velocityThreshold: 0.5,\n maxRotation: 15,\n exitDuration: 300,\n returnDuration: 200,\n enableRotation: true,\n preventSwipe: [],\n};\n\nexport const useSwipe = (\n callbacks: SwipeCallbacks = {},\n config: SwipeConfig = {}\n): UseSwipeReturn => {\n // Memoize config to prevent unnecessary recalculations\n const mergedConfig = useMemo(() => ({ ...DEFAULT_CONFIG, ...config }), [\n config.threshold,\n config.velocityThreshold,\n config.maxRotation,\n config.exitDuration,\n config.returnDuration,\n config.enableRotation,\n // Use JSON for array comparison (preventSwipe is typically small)\n JSON.stringify(config.preventSwipe),\n ]);\n\n const {\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n } = mergedConfig;\n\n const ref = useRef<HTMLDivElement>(null);\n const animationFrameRef = useRef<number | null>(null);\n const timeoutRefs = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n \n // Store callbacks in ref to avoid dependency issues\n const callbacksRef = useRef(callbacks);\n callbacksRef.current = callbacks;\n\n // Use refs for animation values that don't need to trigger re-renders during drag\n const transformRef = useRef('translate3d(0px, 0px, 0px) rotate(0deg)');\n const opacityRef = useRef(1);\n const transitionRef = useRef('none');\n\n // Single state for values that need to trigger re-renders\n const [renderState, setRenderState] = useState({\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n transition: 'none',\n });\n\n const [gestureState, setGestureState] = useState<GestureState>({\n isDragging: false,\n startX: 0,\n startY: 0,\n currentX: 0,\n currentY: 0,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: 0,\n });\n\n // Batch update render state\n const updateRenderState = useCallback((updates: Partial<typeof renderState>) => {\n setRenderState(prev => {\n const newState = { ...prev, ...updates };\n // Only update if values actually changed\n if (\n prev.transform === newState.transform &&\n prev.opacity === newState.opacity &&\n prev.transition === newState.transition\n ) {\n return prev;\n }\n return newState;\n });\n }, []);\n\n // Safe setTimeout that tracks timeouts for cleanup\n const safeTimeout = useCallback((fn: () => void, delay: number) => {\n const id = setTimeout(() => {\n timeoutRefs.current.delete(id);\n fn();\n }, delay);\n timeoutRefs.current.add(id);\n return id;\n }, []);\n\n // Handle swipe start\n const handleSwipeStart = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const coords = getEventCoordinates(event as any);\n const now = Date.now();\n\n setGestureState({\n isDragging: true,\n startX: coords.x,\n startY: coords.y,\n currentX: coords.x,\n currentY: coords.y,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: now,\n });\n\n transitionRef.current = 'none';\n updateRenderState({ transition: 'none' });\n \n callbacksRef.current.onSwipeStart?.();\n },\n [updateRenderState]\n );\n\n // Handle swipe move - use refs to avoid closure issues\n const gestureStateRef = useRef(gestureState);\n gestureStateRef.current = gestureState;\n\n const handleSwipeMove = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const coords = getEventCoordinates(event as any);\n let deltaX = coords.x - state.startX;\n let deltaY = coords.y - state.startY;\n\n // Constrain movement based on preventSwipe directions\n if (preventSwipe.includes('left') && deltaX < 0) deltaX = 0;\n if (preventSwipe.includes('right') && deltaX > 0) deltaX = 0;\n if (preventSwipe.includes('up') && deltaY < 0) deltaY = 0;\n if (preventSwipe.includes('down') && deltaY > 0) deltaY = 0;\n\n // Update gesture state\n setGestureState(prev => ({\n ...prev,\n currentX: coords.x,\n currentY: coords.y,\n deltaX,\n deltaY,\n }));\n\n // Use RAF for smooth updates - cancel previous frame\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n\n animationFrameRef.current = requestAnimationFrame(() => {\n const rotation = enableRotation ? calculateRotation(deltaX, maxRotation) : 0;\n const newOpacity = calculateOpacity(deltaX, deltaY, threshold);\n const newTransform = `translate3d(${deltaX}px, ${deltaY}px, 0px) rotate(${rotation}deg)`;\n\n // Update refs immediately for internal use\n transformRef.current = newTransform;\n opacityRef.current = newOpacity;\n\n // Batch update to React state\n updateRenderState({\n transform: newTransform,\n opacity: newOpacity,\n });\n });\n },\n [enableRotation, maxRotation, threshold, preventSwipe, updateRenderState]\n );\n\n // Handle swipe end\n const handleSwipeEnd = useCallback(() => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const { deltaX, deltaY, startTime } = state;\n const timeDelta = Date.now() - startTime;\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const velocity = calculateVelocity(distance, timeDelta);\n\n const direction = getSwipeDirection(deltaX, deltaY, threshold / 2);\n const shouldSwipe = distance >= threshold || velocity >= velocityThreshold;\n\n // Check if direction is prevented\n const isDirectionPrevented = direction && preventSwipe.includes(direction);\n\n if (shouldSwipe && direction && !isDirectionPrevented) {\n // Execute swipe\n const exitTransition = `transform ${exitDuration}ms ease-out, opacity ${exitDuration}ms ease-out`;\n \n // Calculate exit position (move far enough off screen)\n const multiplier = 2;\n const exitX = deltaX * multiplier;\n const exitY = deltaY * multiplier;\n const rotation = enableRotation ? calculateRotation(exitX, maxRotation * 2) : 0;\n const exitTransform = `translate3d(${exitX}px, ${exitY}px, 0px) rotate(${rotation}deg)`;\n\n updateRenderState({\n transition: exitTransition,\n transform: exitTransform,\n opacity: 0,\n });\n\n // Trigger callback after animation\n safeTimeout(() => {\n switch (direction) {\n case 'left':\n callbacksRef.current.onSwipeLeft?.();\n break;\n case 'right':\n callbacksRef.current.onSwipeRight?.();\n break;\n case 'up':\n callbacksRef.current.onSwipeUp?.();\n break;\n case 'down':\n callbacksRef.current.onSwipeDown?.();\n break;\n }\n \n callbacksRef.current.onSwipeEnd?.();\n\n // Reset after callback\n safeTimeout(() => {\n updateRenderState({\n transition: 'none',\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n }, 50);\n }, exitDuration);\n } else {\n // Spring back\n const returnTransition = `transform ${returnDuration}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${returnDuration}ms ease-out`;\n \n updateRenderState({\n transition: returnTransition,\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n\n callbacksRef.current.onSwipeEnd?.();\n }\n\n setGestureState(prev => ({ ...prev, isDragging: false }));\n }, [\n threshold,\n velocityThreshold,\n exitDuration,\n returnDuration,\n enableRotation,\n maxRotation,\n preventSwipe,\n updateRenderState,\n safeTimeout,\n ]);\n\n // Stable event handler refs to avoid re-attaching listeners\n const handlersRef = useRef({\n handleSwipeStart,\n handleSwipeMove,\n handleSwipeEnd,\n });\n handlersRef.current = { handleSwipeStart, handleSwipeMove, handleSwipeEnd };\n\n // Attach event listeners with stable references\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const onPointerDown = (e: PointerEvent) => {\n handlersRef.current.handleSwipeStart(e);\n };\n\n element.addEventListener('pointerdown', onPointerDown);\n\n return () => {\n element.removeEventListener('pointerdown', onPointerDown);\n };\n }, []); // Empty deps - handlers are accessed via ref\n\n // Attach document listeners when dragging\n useEffect(() => {\n if (!gestureState.isDragging) return;\n\n const onPointerMove = (e: PointerEvent) => {\n handlersRef.current.handleSwipeMove(e);\n };\n\n const onPointerUp = () => {\n handlersRef.current.handleSwipeEnd();\n };\n\n document.addEventListener('pointermove', onPointerMove);\n document.addEventListener('pointerup', onPointerUp);\n document.addEventListener('pointercancel', onPointerUp);\n\n return () => {\n document.removeEventListener('pointermove', onPointerMove);\n document.removeEventListener('pointerup', onPointerUp);\n document.removeEventListener('pointercancel', onPointerUp);\n };\n }, [gestureState.isDragging]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n // Clear all pending timeouts\n timeoutRefs.current.forEach(id => clearTimeout(id));\n timeoutRefs.current.clear();\n };\n }, []);\n\n return {\n ref,\n transform: renderState.transform,\n opacity: renderState.opacity,\n transition: renderState.transition,\n isDragging: gestureState.isDragging,\n deltaX: gestureState.deltaX,\n deltaY: gestureState.deltaY,\n };\n};\n","import React, { CSSProperties, useMemo, memo } from 'react';\nimport { useSwipe } from '../hooks/useSwipe';\nimport { SwipeCardProps, SwipeCallbacks, SwipeConfig } from '../types';\n\n/**\n * SwipeCard Component\n * \n * A performant swipeable card component with smooth animations.\n * Supports swipe in all four directions: left, right, up, and down.\n * \n * @example\n * ```tsx\n * <SwipeCard\n * onSwipeLeft={() => console.log('Swiped left')}\n * onSwipeRight={() => console.log('Swiped right')}\n * threshold={100}\n * swipeStyles={{\n * right: { \n * backgroundColor: 'rgba(34, 197, 94, 0.6)', \n * label: '👍 Like',\n * labelStyle: { position: 'absolute', top: 20, right: 20 }\n * },\n * left: { \n * backgroundColor: 'rgba(239, 68, 68, 0.6)', \n * label: '👎 Nope',\n * labelStyle: { position: 'absolute', top: 20, left: 20 }\n * },\n * }}\n * >\n * <div>Your content here</div>\n * </SwipeCard>\n * ```\n */\n\n// Default label style - constant, no need to recreate\nconst DEFAULT_LABEL_STYLE: CSSProperties = {\n fontSize: '2rem',\n fontWeight: 'bold',\n color: '#fff',\n textTransform: 'uppercase',\n letterSpacing: '2px',\n textShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n};\n\n// Default styles for each direction - constant\nconst DEFAULT_SWIPE_STYLES = {\n right: { backgroundColor: 'rgba(34, 197, 94, 0.6)', label: '✓ Accept', labelStyle: DEFAULT_LABEL_STYLE },\n left: { backgroundColor: 'rgba(239, 68, 68, 0.6)', label: '✗ Reject', labelStyle: DEFAULT_LABEL_STYLE },\n up: { backgroundColor: 'rgba(59, 130, 246, 0.6)', label: '⭐ Super', labelStyle: DEFAULT_LABEL_STYLE },\n down: { backgroundColor: 'rgba(168, 85, 247, 0.6)', label: '⏭ Skip', labelStyle: DEFAULT_LABEL_STYLE },\n} as const;\n\n// Empty array constant to prevent recreating on each render\nconst EMPTY_PREVENT_SWIPE: readonly string[] = [];\n\nconst SwipeCardInner: React.FC<SwipeCardProps> = ({\n children,\n className = '',\n style,\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n threshold = 100,\n velocityThreshold = 0.5,\n maxRotation = 15,\n exitDuration = 300,\n returnDuration = 200,\n enableRotation = true,\n preventSwipe = EMPTY_PREVENT_SWIPE as any,\n swipeStyles,\n showOverlay: showOverlayProp = true,\n}) => {\n // Memoize callbacks object to prevent unnecessary hook updates\n const callbacks: SwipeCallbacks = useMemo(() => ({\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n }), [onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown, onSwipeStart, onSwipeEnd]);\n\n // Memoize config object\n const config: SwipeConfig = useMemo(() => ({\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n }), [threshold, velocityThreshold, maxRotation, exitDuration, returnDuration, enableRotation, preventSwipe]);\n\n const { ref, transform, opacity, transition, isDragging, deltaX, deltaY } = useSwipe(callbacks, config);\n\n // Memoize merged swipe styles\n const mergedSwipeStyles = useMemo(() => ({\n right: { \n ...DEFAULT_SWIPE_STYLES.right, \n ...swipeStyles?.right,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.right.labelStyle, ...swipeStyles?.right?.labelStyle }\n },\n left: { \n ...DEFAULT_SWIPE_STYLES.left, \n ...swipeStyles?.left,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.left.labelStyle, ...swipeStyles?.left?.labelStyle }\n },\n up: { \n ...DEFAULT_SWIPE_STYLES.up, \n ...swipeStyles?.up,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.up.labelStyle, ...swipeStyles?.up?.labelStyle }\n },\n down: { \n ...DEFAULT_SWIPE_STYLES.down, \n ...swipeStyles?.down,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.down.labelStyle, ...swipeStyles?.down?.labelStyle }\n },\n }), [\n swipeStyles?.right, \n swipeStyles?.left, \n swipeStyles?.up, \n swipeStyles?.down,\n ]);\n\n // Calculate swipe state - these are cheap, no need to memoize\n const absX = Math.abs(deltaX);\n const absY = Math.abs(deltaY);\n const isPrimaryHorizontal = absX >= absY;\n const swipeDistance = isPrimaryHorizontal ? absX : absY;\n const swipeProgress = Math.min(swipeDistance / threshold, 1);\n \n const isSwipingRight = isPrimaryHorizontal && deltaX > 20;\n const isSwipingLeft = isPrimaryHorizontal && deltaX < -20;\n const isSwipingUp = !isPrimaryHorizontal && deltaY < -20;\n const isSwipingDown = !isPrimaryHorizontal && deltaY > 20;\n \n const isActionInProgress = swipeProgress >= 0.15;\n const showOverlay = showOverlayProp && isDragging && swipeDistance > 10;\n\n // Calculate current direction info - single calculation\n const currentDirection = useMemo(() => {\n if (isSwipingRight) return 'right' as const;\n if (isSwipingLeft) return 'left' as const;\n if (isSwipingUp) return 'up' as const;\n if (isSwipingDown) return 'down' as const;\n return null;\n }, [isSwipingRight, isSwipingLeft, isSwipingUp, isSwipingDown]);\n\n const currentStyle = currentDirection ? mergedSwipeStyles[currentDirection] : null;\n const backgroundColor = currentStyle?.backgroundColor ?? 'transparent';\n const labelConfig = currentStyle ? { label: currentStyle.label, labelStyle: currentStyle.labelStyle } : null;\n\n // Memoize card style - only recalculate when values change\n const cardStyle: CSSProperties = useMemo(() => ({\n ...style,\n transform,\n opacity,\n transition,\n touchAction: 'none',\n userSelect: 'none',\n WebkitUserSelect: 'none',\n cursor: isDragging ? 'grabbing' : 'grab',\n willChange: isDragging ? 'transform, opacity' : 'auto',\n position: 'absolute',\n }), [style, transform, opacity, transition, isDragging]);\n\n // Memoize overlay style\n const overlayStyle: CSSProperties = useMemo(() => ({\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'inherit',\n pointerEvents: 'none',\n zIndex: 10,\n opacity: showOverlay ? swipeProgress : 0,\n transition: isDragging ? 'none' : 'opacity 200ms ease-out',\n backgroundColor: showOverlay ? backgroundColor : 'transparent',\n }), [showOverlay, swipeProgress, isDragging, backgroundColor]);\n\n // Memoize computed label style\n const computedLabelStyle: CSSProperties = useMemo(() => ({\n ...labelConfig?.labelStyle,\n transform: `scale(${0.8 + swipeProgress * 0.4})`,\n opacity: swipeProgress,\n }), [labelConfig?.labelStyle, swipeProgress]);\n\n return (\n <div\n ref={ref}\n className={`swipeon-card ${className}`}\n style={cardStyle}\n >\n {children}\n <div style={overlayStyle}>\n {showOverlay && isActionInProgress && labelConfig?.label && (\n <span style={computedLabelStyle}>\n {labelConfig.label}\n </span>\n )}\n </div>\n </div>\n );\n};\n\n// Memoize the entire component to prevent unnecessary re-renders from parent\nexport const SwipeCard = memo(SwipeCardInner);\n\nexport default SwipeCard;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["DEFAULT_CONFIG: Required<SwipeConfig>","DEFAULT_LABEL_STYLE: CSSProperties","EMPTY_PREVENT_SWIPE: readonly string[]","SwipeCardInner: React.FC<SwipeCardProps>","cardStyle: CSSProperties","overlayStyle: CSSProperties","computedLabelStyle: CSSProperties"],"sources":["../src/utils/helpers.ts","../src/hooks/useSwipe.ts","../src/components/SwipeCard.tsx"],"sourcesContent":["import { SwipeDirection } from '../types';\n\n/**\n * Calculate the distance between two points\n */\nexport const getDistance = (x1: number, y1: number, x2: number, y2: number): number => {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return Math.sqrt(dx * dx + dy * dy);\n};\n\n/**\n * Calculate velocity based on distance and time\n */\nexport const calculateVelocity = (distance: number, time: number): number => {\n if (time === 0) return 0;\n return Math.abs(distance / time);\n};\n\n/**\n * Determine the swipe direction based on deltas\n */\nexport const getSwipeDirection = (\n deltaX: number,\n deltaY: number,\n threshold: number = 50\n): SwipeDirection | null => {\n const absDeltaX = Math.abs(deltaX);\n const absDeltaY = Math.abs(deltaY);\n\n // Need minimum movement\n if (absDeltaX < threshold && absDeltaY < threshold) {\n return null;\n }\n\n // Determine primary direction\n if (absDeltaX > absDeltaY) {\n return deltaX > 0 ? 'right' : 'left';\n } else {\n return deltaY > 0 ? 'down' : 'up';\n }\n};\n\n/**\n * Calculate rotation angle based on horizontal movement\n */\nexport const calculateRotation = (\n deltaX: number,\n maxRotation: number = 15,\n containerWidth: number = 300\n): number => {\n const rotation = (deltaX / containerWidth) * maxRotation;\n return Math.max(-maxRotation, Math.min(maxRotation, rotation));\n};\n\n/**\n * Calculate opacity based on drag distance\n */\nexport const calculateOpacity = (\n deltaX: number,\n deltaY: number,\n threshold: number = 100\n): number => {\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const opacity = 1 - distance / (threshold * 3);\n return Math.max(0.5, Math.min(1, opacity));\n};\n\n/**\n * Clamp a value between min and max\n */\nexport const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value));\n};\n\n/**\n * Get touch/pointer coordinates from event\n */\nexport const getEventCoordinates = (\n event: TouchEvent | PointerEvent | MouseEvent | any\n): { x: number; y: number } => {\n if ('touches' in event && event.touches && event.touches.length > 0) {\n return {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n };\n }\n \n if ('clientX' in event && 'clientY' in event) {\n return {\n x: event.clientX,\n y: event.clientY,\n };\n }\n \n return { x: 0, y: 0 };\n};\n\n","import { useRef, useState, useCallback, useEffect, useMemo } from 'react';\nimport { SwipeConfig, SwipeCallbacks, GestureState, UseSwipeReturn } from '../types';\nimport {\n getSwipeDirection,\n calculateRotation,\n calculateOpacity,\n calculateVelocity,\n getEventCoordinates,\n} from '../utils/helpers';\n\nconst DEFAULT_CONFIG: Required<SwipeConfig> = {\n threshold: 100,\n velocityThreshold: 0.5,\n maxRotation: 15,\n exitDuration: 300,\n returnDuration: 200,\n enableRotation: true,\n preventSwipe: [],\n fadeOnSwipe: true,\n};\n\nexport const useSwipe = (\n callbacks: SwipeCallbacks = {},\n config: SwipeConfig = {}\n): UseSwipeReturn => {\n // Memoize config to prevent unnecessary recalculations\n const mergedConfig = useMemo(() => ({ ...DEFAULT_CONFIG, ...config }), [\n config.threshold,\n config.velocityThreshold,\n config.maxRotation,\n config.exitDuration,\n config.returnDuration,\n config.enableRotation,\n config.fadeOnSwipe,\n // Use JSON for array comparison (preventSwipe is typically small)\n JSON.stringify(config.preventSwipe),\n ]);\n\n const {\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n fadeOnSwipe,\n } = mergedConfig;\n\n const ref = useRef<HTMLDivElement>(null);\n const animationFrameRef = useRef<number | null>(null);\n const timeoutRefs = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n \n // Store callbacks in ref to avoid dependency issues\n const callbacksRef = useRef(callbacks);\n callbacksRef.current = callbacks;\n\n // Use refs for animation values that don't need to trigger re-renders during drag\n const transformRef = useRef('translate3d(0px, 0px, 0px) rotate(0deg)');\n const opacityRef = useRef(1);\n const transitionRef = useRef('none');\n\n // Single state for values that need to trigger re-renders\n const [renderState, setRenderState] = useState({\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n transition: 'none',\n });\n\n const [gestureState, setGestureState] = useState<GestureState>({\n isDragging: false,\n startX: 0,\n startY: 0,\n currentX: 0,\n currentY: 0,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: 0,\n });\n\n // Batch update render state\n const updateRenderState = useCallback((updates: Partial<typeof renderState>) => {\n setRenderState(prev => {\n const newState = { ...prev, ...updates };\n // Only update if values actually changed\n if (\n prev.transform === newState.transform &&\n prev.opacity === newState.opacity &&\n prev.transition === newState.transition\n ) {\n return prev;\n }\n return newState;\n });\n }, []);\n\n // Safe setTimeout that tracks timeouts for cleanup\n const safeTimeout = useCallback((fn: () => void, delay: number) => {\n const id = setTimeout(() => {\n timeoutRefs.current.delete(id);\n fn();\n }, delay);\n timeoutRefs.current.add(id);\n return id;\n }, []);\n\n // Handle swipe start\n const handleSwipeStart = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const coords = getEventCoordinates(event as any);\n const now = Date.now();\n\n setGestureState({\n isDragging: true,\n startX: coords.x,\n startY: coords.y,\n currentX: coords.x,\n currentY: coords.y,\n deltaX: 0,\n deltaY: 0,\n velocity: 0,\n direction: null,\n startTime: now,\n });\n\n transitionRef.current = 'none';\n updateRenderState({ transition: 'none' });\n \n callbacksRef.current.onSwipeStart?.();\n },\n [updateRenderState]\n );\n\n // Handle swipe move - use refs to avoid closure issues\n const gestureStateRef = useRef(gestureState);\n gestureStateRef.current = gestureState;\n\n const handleSwipeMove = useCallback(\n (event: PointerEvent | TouchEvent | MouseEvent) => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const coords = getEventCoordinates(event as any);\n let deltaX = coords.x - state.startX;\n let deltaY = coords.y - state.startY;\n\n // Constrain movement based on preventSwipe directions\n if (preventSwipe.includes('left') && deltaX < 0) deltaX = 0;\n if (preventSwipe.includes('right') && deltaX > 0) deltaX = 0;\n if (preventSwipe.includes('up') && deltaY < 0) deltaY = 0;\n if (preventSwipe.includes('down') && deltaY > 0) deltaY = 0;\n\n // Update gesture state\n setGestureState(prev => ({\n ...prev,\n currentX: coords.x,\n currentY: coords.y,\n deltaX,\n deltaY,\n }));\n\n // Use RAF for smooth updates - cancel previous frame\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n\n animationFrameRef.current = requestAnimationFrame(() => {\n const rotation = enableRotation ? calculateRotation(deltaX, maxRotation) : 0;\n const newOpacity = fadeOnSwipe ? calculateOpacity(deltaX, deltaY, threshold) : 1;\n const newTransform = `translate3d(${deltaX}px, ${deltaY}px, 0px) rotate(${rotation}deg)`;\n\n // Update refs immediately for internal use\n transformRef.current = newTransform;\n opacityRef.current = newOpacity;\n\n // Batch update to React state\n updateRenderState({\n transform: newTransform,\n opacity: newOpacity,\n });\n });\n },\n [enableRotation, maxRotation, threshold, preventSwipe, fadeOnSwipe, updateRenderState]\n );\n\n // Handle swipe end\n const handleSwipeEnd = useCallback(() => {\n const state = gestureStateRef.current;\n if (!state.isDragging) return;\n\n const { deltaX, deltaY, startTime } = state;\n const timeDelta = Date.now() - startTime;\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n const velocity = calculateVelocity(distance, timeDelta);\n\n const direction = getSwipeDirection(deltaX, deltaY, threshold / 2);\n const shouldSwipe = distance >= threshold || velocity >= velocityThreshold;\n\n // Check if direction is prevented\n const isDirectionPrevented = direction && preventSwipe.includes(direction);\n\n if (shouldSwipe && direction && !isDirectionPrevented) {\n // Execute swipe\n const exitTransition = `transform ${exitDuration}ms ease-out, opacity ${exitDuration}ms ease-out`;\n \n // Calculate exit position (move far enough off screen)\n const multiplier = 2;\n const exitX = deltaX * multiplier;\n const exitY = deltaY * multiplier;\n const rotation = enableRotation ? calculateRotation(exitX, maxRotation * 2) : 0;\n const exitTransform = `translate3d(${exitX}px, ${exitY}px, 0px) rotate(${rotation}deg)`;\n\n updateRenderState({\n transition: exitTransition,\n transform: exitTransform,\n opacity: 0,\n });\n\n // Trigger callback after animation\n safeTimeout(() => {\n switch (direction) {\n case 'left':\n callbacksRef.current.onSwipeLeft?.();\n break;\n case 'right':\n callbacksRef.current.onSwipeRight?.();\n break;\n case 'up':\n callbacksRef.current.onSwipeUp?.();\n break;\n case 'down':\n callbacksRef.current.onSwipeDown?.();\n break;\n }\n \n callbacksRef.current.onSwipeEnd?.();\n\n // Reset after callback\n safeTimeout(() => {\n updateRenderState({\n transition: 'none',\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n }, 50);\n }, exitDuration);\n } else {\n // Spring back\n const returnTransition = `transform ${returnDuration}ms cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity ${returnDuration}ms ease-out`;\n \n updateRenderState({\n transition: returnTransition,\n transform: 'translate3d(0px, 0px, 0px) rotate(0deg)',\n opacity: 1,\n });\n\n callbacksRef.current.onSwipeEnd?.();\n }\n\n setGestureState(prev => ({ ...prev, isDragging: false }));\n }, [\n threshold,\n velocityThreshold,\n exitDuration,\n returnDuration,\n enableRotation,\n maxRotation,\n preventSwipe,\n updateRenderState,\n safeTimeout,\n ]);\n\n // Stable event handler refs to avoid re-attaching listeners\n const handlersRef = useRef({\n handleSwipeStart,\n handleSwipeMove,\n handleSwipeEnd,\n });\n handlersRef.current = { handleSwipeStart, handleSwipeMove, handleSwipeEnd };\n\n // Attach event listeners with stable references\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const onPointerDown = (e: PointerEvent) => {\n handlersRef.current.handleSwipeStart(e);\n };\n\n element.addEventListener('pointerdown', onPointerDown);\n\n return () => {\n element.removeEventListener('pointerdown', onPointerDown);\n };\n }, []); // Empty deps - handlers are accessed via ref\n\n // Attach document listeners when dragging\n useEffect(() => {\n if (!gestureState.isDragging) return;\n\n const onPointerMove = (e: PointerEvent) => {\n handlersRef.current.handleSwipeMove(e);\n };\n\n const onPointerUp = () => {\n handlersRef.current.handleSwipeEnd();\n };\n\n document.addEventListener('pointermove', onPointerMove);\n document.addEventListener('pointerup', onPointerUp);\n document.addEventListener('pointercancel', onPointerUp);\n\n return () => {\n document.removeEventListener('pointermove', onPointerMove);\n document.removeEventListener('pointerup', onPointerUp);\n document.removeEventListener('pointercancel', onPointerUp);\n };\n }, [gestureState.isDragging]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n // Clear all pending timeouts\n timeoutRefs.current.forEach(id => clearTimeout(id));\n timeoutRefs.current.clear();\n };\n }, []);\n\n return {\n ref,\n transform: renderState.transform,\n opacity: renderState.opacity,\n transition: renderState.transition,\n isDragging: gestureState.isDragging,\n deltaX: gestureState.deltaX,\n deltaY: gestureState.deltaY,\n };\n};\n","import React, { CSSProperties, useMemo, memo } from 'react';\nimport { useSwipe } from '../hooks/useSwipe';\nimport { SwipeCardProps, SwipeCallbacks, SwipeConfig } from '../types';\n\n/**\n * SwipeCard Component\n * \n * A performant swipeable card component with smooth animations.\n * Supports swipe in all four directions: left, right, up, and down.\n * \n * @example\n * ```tsx\n * <SwipeCard\n * onSwipeLeft={() => console.log('Swiped left')}\n * onSwipeRight={() => console.log('Swiped right')}\n * threshold={100}\n * swipeStyles={{\n * // backgroundColor is optional - transparent by default (card content stays visible)\n * right: { \n * backgroundColor: 'rgba(34, 197, 94, 0.6)', // green overlay\n * label: '👍 Like',\n * labelStyle: { position: 'absolute', top: 20, right: 20 }\n * },\n * left: { \n * backgroundColor: 'rgba(239, 68, 68, 0.6)', // red overlay\n * label: '👎 Nope',\n * labelStyle: { position: 'absolute', top: 20, left: 20 }\n * },\n * }}\n * >\n * <div>Your content here</div>\n * </SwipeCard>\n * ```\n */\n\n// Default label style - constant, no need to recreate\nconst DEFAULT_LABEL_STYLE: CSSProperties = {\n fontSize: '2rem',\n fontWeight: 'bold',\n color: '#fff',\n letterSpacing: '2px',\n textShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n};\n\n// Default styles for each direction - constant\n// backgroundColor defaults to transparent so card content remains visible unless explicitly set\nconst DEFAULT_SWIPE_STYLES = {\n right: { backgroundColor: 'transparent', label: '✓ Accept', labelStyle: DEFAULT_LABEL_STYLE },\n left: { backgroundColor: 'transparent', label: '✗ Reject', labelStyle: DEFAULT_LABEL_STYLE },\n up: { backgroundColor: 'transparent', label: '⭐ Super', labelStyle: DEFAULT_LABEL_STYLE },\n down: { backgroundColor: 'transparent', label: '⏭ Skip', labelStyle: DEFAULT_LABEL_STYLE },\n} as const;\n\n// Empty array constant to prevent recreating on each render\nconst EMPTY_PREVENT_SWIPE: readonly string[] = [];\n\nconst SwipeCardInner: React.FC<SwipeCardProps> = ({\n children,\n className = '',\n style,\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n threshold = 100,\n velocityThreshold = 0.5,\n maxRotation = 15,\n exitDuration = 300,\n returnDuration = 200,\n enableRotation = true,\n preventSwipe = EMPTY_PREVENT_SWIPE as any,\n fadeOnSwipe = true,\n swipeStyles,\n showOverlay: showOverlayProp = true,\n}) => {\n // Memoize callbacks object to prevent unnecessary hook updates\n const callbacks: SwipeCallbacks = useMemo(() => ({\n onSwipeLeft,\n onSwipeRight,\n onSwipeUp,\n onSwipeDown,\n onSwipeStart,\n onSwipeEnd,\n }), [onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown, onSwipeStart, onSwipeEnd]);\n\n // Memoize config object\n const config: SwipeConfig = useMemo(() => ({\n threshold,\n velocityThreshold,\n maxRotation,\n exitDuration,\n returnDuration,\n enableRotation,\n preventSwipe,\n fadeOnSwipe,\n }), [threshold, velocityThreshold, maxRotation, exitDuration, returnDuration, enableRotation, preventSwipe, fadeOnSwipe]);\n\n const { ref, transform, opacity, transition, isDragging, deltaX, deltaY } = useSwipe(callbacks, config);\n\n // Memoize merged swipe styles\n const mergedSwipeStyles = useMemo(() => ({\n right: { \n ...DEFAULT_SWIPE_STYLES.right, \n ...swipeStyles?.right,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.right.labelStyle, ...swipeStyles?.right?.labelStyle }\n },\n left: { \n ...DEFAULT_SWIPE_STYLES.left, \n ...swipeStyles?.left,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.left.labelStyle, ...swipeStyles?.left?.labelStyle }\n },\n up: { \n ...DEFAULT_SWIPE_STYLES.up, \n ...swipeStyles?.up,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.up.labelStyle, ...swipeStyles?.up?.labelStyle }\n },\n down: { \n ...DEFAULT_SWIPE_STYLES.down, \n ...swipeStyles?.down,\n labelStyle: { ...DEFAULT_SWIPE_STYLES.down.labelStyle, ...swipeStyles?.down?.labelStyle }\n },\n }), [\n swipeStyles?.right, \n swipeStyles?.left, \n swipeStyles?.up, \n swipeStyles?.down,\n ]);\n\n // Calculate swipe state - these are cheap, no need to memoize\n const absX = Math.abs(deltaX);\n const absY = Math.abs(deltaY);\n const isPrimaryHorizontal = absX >= absY;\n const swipeDistance = isPrimaryHorizontal ? absX : absY;\n const swipeProgress = Math.min(swipeDistance / threshold, 1);\n \n const isSwipingRight = isPrimaryHorizontal && deltaX > 20;\n const isSwipingLeft = isPrimaryHorizontal && deltaX < -20;\n const isSwipingUp = !isPrimaryHorizontal && deltaY < -20;\n const isSwipingDown = !isPrimaryHorizontal && deltaY > 20;\n \n const isActionInProgress = swipeProgress >= 0.15;\n const showOverlay = showOverlayProp && isDragging && swipeDistance > 10;\n\n // Calculate current direction info - single calculation\n const currentDirection = useMemo(() => {\n if (isSwipingRight) return 'right' as const;\n if (isSwipingLeft) return 'left' as const;\n if (isSwipingUp) return 'up' as const;\n if (isSwipingDown) return 'down' as const;\n return null;\n }, [isSwipingRight, isSwipingLeft, isSwipingUp, isSwipingDown]);\n\n const currentStyle = currentDirection ? mergedSwipeStyles[currentDirection] : null;\n const backgroundColor = currentStyle?.backgroundColor ?? 'inherit';\n const labelConfig = currentStyle ? { label: currentStyle.label, labelStyle: currentStyle.labelStyle } : null;\n\n // Memoize card style - only recalculate when values change\n const cardStyle: CSSProperties = useMemo(() => ({\n ...style,\n transform,\n opacity,\n transition,\n touchAction: 'none',\n userSelect: 'none',\n WebkitUserSelect: 'none',\n cursor: isDragging ? 'grabbing' : 'grab',\n willChange: isDragging ? 'transform, opacity' : 'auto',\n position: 'absolute',\n }), [style, transform, opacity, transition, isDragging]);\n\n // Memoize overlay style\n const overlayStyle: CSSProperties = useMemo(() => ({\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'inherit',\n pointerEvents: 'none',\n zIndex: 10,\n opacity: showOverlay ? swipeProgress : 0,\n transition: isDragging ? 'none' : 'opacity 200ms ease-out',\n backgroundColor: showOverlay ? backgroundColor : 'inherit',\n }), [showOverlay, swipeProgress, isDragging, backgroundColor]);\n\n // Memoize computed label style\n const computedLabelStyle: CSSProperties = useMemo(() => ({\n ...labelConfig?.labelStyle,\n transform: `scale(${0.8 + swipeProgress * 0.4})`,\n opacity: swipeProgress,\n }), [labelConfig?.labelStyle, swipeProgress]);\n\n return (\n <div\n ref={ref}\n className={`swipeon-card ${className}`}\n style={cardStyle}\n >\n {children}\n <div style={overlayStyle}>\n {showOverlay && isActionInProgress && labelConfig?.label && (\n <span style={computedLabelStyle}>\n {labelConfig.label}\n </span>\n )}\n </div>\n </div>\n );\n};\n\n// Memoize the entire component to prevent unnecessary re-renders from parent\nexport const SwipeCard = memo(SwipeCardInner);\n\nexport default SwipeCard;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swipeon-react",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "description": "A high-performance React swipe card library with smooth animations and multi-directional swipe support",
6
6
  "main": "dist/index.js",