From d313f25d87d48e9c73fb0d86a322a1d3e5069ab4 Mon Sep 17 00:00:00 2001 From: Yang Date: Thu, 14 Sep 2023 10:22:56 +0800 Subject: [PATCH] chore: swipe-action --- packages/zarm/src/swipe-action/useSwipe.ts | 107 +++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 packages/zarm/src/swipe-action/useSwipe.ts diff --git a/packages/zarm/src/swipe-action/useSwipe.ts b/packages/zarm/src/swipe-action/useSwipe.ts new file mode 100644 index 000000000..661b61ffb --- /dev/null +++ b/packages/zarm/src/swipe-action/useSwipe.ts @@ -0,0 +1,107 @@ +import { useSafeState } from 'ahooks'; +import { CSSProperties, useRef } from 'react'; + +const computeStyle = (offsetLeft, animationDuration) => { + return { + WebkitTransitionDuration: `${animationDuration}ms`, + transitionDuration: `${animationDuration}ms`, + WebkitTransform: `translate3d(${offsetLeft}px, 0, 0)`, + transform: `translate3d(${offsetLeft}px, 0, 0)`, + }; +}; + +const useSwipe = () => { + const isOpen = useRef(null); + const dragging = useRef(false); + const dragStart = useRef(0); + const [style, setStyle] = useSafeState(computeStyle(0, 0)); + + const doTransition = (offsetLeft, duration) => { + setStyle(computeStyle(offsetLeft, duration)); + }; + + const afterClose = () => { + isOpen.current = null; + dragStart.current = 0; + }; + + const onSwipe = ( + state, + { + leftActions, + rightActions, + moveDistanceRatio, + btnsLeftWidth, + btnsRightWidth, + moveTimeSpan, + animationDuration, + onOpen, + close, + }, + ) => { + const [offsetX] = state.offset; + if ((isOpen.current === 'right' && offsetX < 0) || (isOpen.current === 'left' && offsetX > 0)) { + return false; + } + if (state.down) { + dragging.current = true; + } + if (!dragging.current) return; + dragStart.current = offsetX; + + if (offsetX > 0 && !leftActions) { + return false; + } + + if (offsetX < 0 && !rightActions) { + return false; + } + + if (state.last) { + const timeSpan = Math.floor(state.elapsedTime); + let distanceX = 0; + let _isOpen = false; + + if ( + btnsLeftWidth > 0 && + (offsetX / btnsLeftWidth > moveDistanceRatio! || (offsetX > 0 && timeSpan <= moveTimeSpan!)) + ) { + distanceX = btnsLeftWidth; + _isOpen = true; + } else if ( + (btnsRightWidth > 0 && offsetX / btnsRightWidth < -moveDistanceRatio!) || + (offsetX < 0 && timeSpan <= moveTimeSpan!) + ) { + distanceX = -btnsRightWidth; + _isOpen = true; + } + doTransition(distanceX, animationDuration); + + if (_isOpen) { + // 打开 + isOpen.current = distanceX > 0 ? 'left' : 'right'; + onOpen?.(); + } else { + // 还原 + close(); + } + window.setTimeout(() => { + dragging.current = false; + }); + } else { + doTransition(offsetX, 0); + } + }; + + return { + style, + doTransition, + onSwipe, + isOpen, + afterClose, + dragStart, + dragging, + }; +}; + +export default useSwipe;