|
1 |
| -const PanResponder = require('react-panresponder-web') |
2 | 1 | const React = require('react')
|
3 | 2 | const { useSpring, animated } = require('@react-spring/web')
|
4 | 3 |
|
@@ -149,71 +148,104 @@ const TinderCard = React.forwardRef(
|
149 | 148 | )
|
150 | 149 |
|
151 | 150 | let swipeThresholdFulfilledDirection = 'none'
|
152 |
| - const panResponder = React.useMemo( |
153 |
| - () => |
154 |
| - PanResponder.create({ |
155 |
| - // Ask to be the responder: |
156 |
| - onStartShouldSetPanResponder: (evt, gestureState) => true, |
157 |
| - onStartShouldSetPanResponderCapture: (evt, gestureState) => true, |
158 |
| - onMoveShouldSetPanResponder: (evt, gestureState) => true, |
159 |
| - onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, |
160 |
| - |
161 |
| - onPanResponderGrant: (evt, gestureState) => { |
162 |
| - // The gesture has started. |
163 |
| - // Probably wont need this anymore as postion i relative to swipe! |
164 |
| - setSpringTarget.start({ xyrot: [gestureState.dx, gestureState.dy, 0], config: physics.touchResponsive }) |
165 |
| - }, |
166 |
| - onPanResponderMove: (evt, gestureState) => { |
167 |
| - // Check fulfillment |
168 |
| - if (onSwipeRequirementFulfilled || onSwipeRequirementUnfulfilled) { |
169 |
| - const dir = getSwipeDirection({ |
170 |
| - x: swipeRequirementType === 'velocity' ? gestureState.vx : gestureState.dx, |
171 |
| - y: swipeRequirementType === 'velocity' ? gestureState.vy : gestureState.dy |
172 |
| - }) |
173 |
| - if (dir !== swipeThresholdFulfilledDirection) { |
174 |
| - swipeThresholdFulfilledDirection = dir |
175 |
| - if (swipeThresholdFulfilledDirection === 'none') { |
176 |
| - if (onSwipeRequirementUnfulfilled) onSwipeRequirementUnfulfilled() |
177 |
| - } else { |
178 |
| - if (onSwipeRequirementFulfilled) onSwipeRequirementFulfilled(dir) |
179 |
| - } |
180 |
| - } |
181 |
| - } |
182 | 151 |
|
183 |
| - // use guestureState.vx / guestureState.vy for velocity calculations |
184 |
| - // translate element |
185 |
| - let rot = ((300 * gestureState.vx) / width) * 15// Magic number 300 different on different devices? Run on physical device! |
186 |
| - rot = Math.max(Math.min(rot, settings.maxTilt), -settings.maxTilt) |
187 |
| - setSpringTarget.start({ xyrot: [gestureState.dx, gestureState.dy, rot], config: physics.touchResponsive }) |
188 |
| - }, |
189 |
| - onPanResponderTerminationRequest: (evt, gestureState) => { |
190 |
| - return true |
191 |
| - }, |
192 |
| - onPanResponderRelease: (evt, gestureState) => { |
193 |
| - // The user has released all touches while this view is the |
194 |
| - // responder. This typically means a gesture has succeeded |
195 |
| - // enable |
196 |
| - handleSwipeReleased(setSpringTarget, gestureState) |
197 |
| - } |
198 |
| - }), |
199 |
| - [] |
200 |
| - ) |
| 152 | + const gestureStateFromWebEvent = (ev, startPositon, lastPosition, isTouch) => { |
| 153 | + let dx = isTouch ? ev.touches[0].clientX - startPositon.x : ev.clientX - startPositon.x |
| 154 | + let dy = isTouch ? ev.touches[0].clientY - startPositon.y : ev.clientY - startPositon.y |
201 | 155 |
|
202 |
| - const element = React.useRef() |
| 156 | + // We cant calculate velocity from the first event |
| 157 | + if (startPositon.x === 0 && startPositon.y === 0) { |
| 158 | + dx = 0 |
| 159 | + dy = 0 |
| 160 | + } |
| 161 | + |
| 162 | + const vx = -(dx - lastPosition.dx) / (lastPosition.timeStamp - Date.now()) |
| 163 | + const vy = -(dy - lastPosition.dy) / (lastPosition.timeStamp - Date.now()) |
| 164 | + |
| 165 | + const gestureState = { dx, dy, vx, vy, timeStamp: Date.now() } |
| 166 | + return gestureState |
| 167 | + } |
203 | 168 |
|
204 | 169 | React.useLayoutEffect(() => {
|
| 170 | + let startPositon = { x: 0, y: 0 } |
| 171 | + let lastPosition = { dx: 0, dy: 0, vx: 0, vy: 0, timeStamp: Date.now() } |
| 172 | + let isClicking = false |
| 173 | + |
205 | 174 | element.current.addEventListener(('touchstart'), (ev) => {
|
206 | 175 | if (!ev.srcElement.className.includes('pressable') && ev.cancelable) {
|
207 | 176 | ev.preventDefault()
|
208 | 177 | }
|
| 178 | + |
| 179 | + const gestureState = gestureStateFromWebEvent(ev, startPositon, lastPosition, true) |
| 180 | + lastPosition = gestureState |
| 181 | + startPositon = { x: ev.touches[0].clientX, y: ev.touches[0].clientY } |
| 182 | + }) |
| 183 | + |
| 184 | + element.current.addEventListener(('mousedown'), (ev) => { |
| 185 | + isClicking = true |
| 186 | + const gestureState = gestureStateFromWebEvent(ev, startPositon, lastPosition, false) |
| 187 | + lastPosition = gestureState |
| 188 | + startPositon = { x: ev.clientX, y: ev.clientY } |
| 189 | + }) |
| 190 | + |
| 191 | + const handleMove = (gestureState) => { |
| 192 | + // Check fulfillment |
| 193 | + if (onSwipeRequirementFulfilled || onSwipeRequirementUnfulfilled) { |
| 194 | + const dir = getSwipeDirection({ |
| 195 | + x: swipeRequirementType === 'velocity' ? gestureState.vx : gestureState.dx, |
| 196 | + y: swipeRequirementType === 'velocity' ? gestureState.vy : gestureState.dy |
| 197 | + }) |
| 198 | + if (dir !== swipeThresholdFulfilledDirection) { |
| 199 | + swipeThresholdFulfilledDirection = dir |
| 200 | + if (swipeThresholdFulfilledDirection === 'none') { |
| 201 | + if (onSwipeRequirementUnfulfilled) onSwipeRequirementUnfulfilled() |
| 202 | + } else { |
| 203 | + if (onSwipeRequirementFulfilled) onSwipeRequirementFulfilled(dir) |
| 204 | + } |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + // use guestureState.vx / guestureState.vy for velocity calculations |
| 209 | + // translate element |
| 210 | + let rot = gestureState.vx * 15 // Magic number 15 looks about right |
| 211 | + rot = Math.max(Math.min(rot, settings.maxTilt), -settings.maxTilt) |
| 212 | + setSpringTarget.start({ xyrot: [gestureState.dx, gestureState.dy, rot], config: physics.touchResponsive }) |
| 213 | + } |
| 214 | + |
| 215 | + window.addEventListener(('mousemove'), (ev) => { |
| 216 | + if (!isClicking) return |
| 217 | + const gestureState = gestureStateFromWebEvent(ev, startPositon, lastPosition, false) |
| 218 | + lastPosition = gestureState |
| 219 | + handleMove(gestureState) |
| 220 | + }) |
| 221 | + |
| 222 | + window.addEventListener(('mouseup'), (ev) => { |
| 223 | + if (!isClicking) return |
| 224 | + isClicking = false |
| 225 | + handleSwipeReleased(setSpringTarget, lastPosition) |
| 226 | + startPositon = { x: 0, y: 0 } |
| 227 | + lastPosition = { dx: 0, dy: 0, vx: 0, vy: 0, timeStamp: Date.now() } |
| 228 | + }) |
| 229 | + |
| 230 | + element.current.addEventListener(('touchmove'), (ev) => { |
| 231 | + const gestureState = gestureStateFromWebEvent(ev, startPositon, lastPosition, true) |
| 232 | + lastPosition = gestureState |
| 233 | + handleMove(gestureState) |
| 234 | + }) |
| 235 | + |
| 236 | + element.current.addEventListener(('touchend'), (ev) => { |
| 237 | + handleSwipeReleased(setSpringTarget, lastPosition) |
| 238 | + startPositon = { x: 0, y: 0 } |
| 239 | + lastPosition = { dx: 0, dy: 0, vx: 0, vy: 0, timeStamp: Date.now() } |
209 | 240 | })
|
210 | 241 | })
|
211 | 242 |
|
| 243 | + const element = React.useRef() |
| 244 | + |
212 | 245 | return (
|
213 | 246 | React.createElement(AnimatedDiv, {
|
214 | 247 | ref: element,
|
215 | 248 | className,
|
216 |
| - ...panResponder.panHandlers, |
217 | 249 | style: {
|
218 | 250 | transform: xyrot.to((x, y, rot) => `translate3d(${x}px, ${y}px, ${0}px) rotate(${rot}deg)`)
|
219 | 251 | },
|
|
0 commit comments