11import classNames from 'classnames'
2- import _inRange from 'lodash/inRange'
3- import _isEmpty from 'lodash/isEmpty'
42import PropTypes , { InferProps } from 'prop-types'
53import React from 'react'
6- import { Text , View } from '@tarojs/components'
7- import { CommonEvent , ITouchEvent } from '@tarojs/components/types/common'
4+ import { Text , View , MovableArea , MovableView } from '@tarojs/components'
5+ import { CommonEvent } from '@tarojs/components/types/common'
86import {
97 AtSwipeActionProps ,
108 AtSwipeActionState ,
119 SwipeActionOption
1210} from '../../../types/swipe-action'
13- import {
14- delayGetClientRect ,
15- delayGetScrollOffset ,
16- uuid
17- } from '../../common/utils'
11+ import { delayQuerySelector , uuid } from '../../common/utils'
1812import AtSwipeActionOptions from './options/index'
1913
2014export default class AtSwipeAction extends React . Component <
@@ -24,48 +18,22 @@ export default class AtSwipeAction extends React.Component<
2418 public static defaultProps : AtSwipeActionProps
2519 public static propTypes : InferProps < AtSwipeActionProps >
2620
27- private endValue : number
28- private startX : number
29- private startY : number
3021 private maxOffsetSize : number
31- private domInfo : any
32- private isMoving : boolean
33- private isTouching : boolean
22+ private moveX : number
23+ private eleWidth : number
3424
3525 public constructor ( props : AtSwipeActionProps ) {
3626 super ( props )
3727 const { isOpened } = props
38- this . endValue = 0
39- this . startX = 0
40- this . startY = 0
4128 this . maxOffsetSize = 0
42- this . domInfo = {
43- top : 0 ,
44- bottom : 0 ,
45- left : 0 ,
46- right : 0
47- }
48- this . isMoving = false
49- this . isTouching = false
5029 this . state = {
5130 componentId : uuid ( ) ,
5231 offsetSize : 0 ,
53- _isOpened : ! ! isOpened
32+ _isOpened : ! ! isOpened ,
33+ needAnimation : false
5434 }
55- }
56-
57- private getDomInfo ( ) : Promise < void > {
58- return Promise . all ( [
59- delayGetClientRect ( {
60- delayTime : 0 ,
61- selectorStr : `#swipeAction-${ this . state . componentId } `
62- } ) ,
63- delayGetScrollOffset ( { delayTime : 0 } )
64- ] ) . then ( ( [ rect , scrollOffset ] ) => {
65- rect [ 0 ] . top += scrollOffset [ 0 ] . scrollTop
66- rect [ 0 ] . bottom += scrollOffset [ 0 ] . scrollTop
67- this . domInfo = rect [ 0 ]
68- } )
35+ this . moveX = 0
36+ this . eleWidth = 0
6937 }
7038
7139 public UNSAFE_componentWillReceiveProps ( nextProps : AtSwipeActionProps ) : void {
@@ -77,31 +45,49 @@ export default class AtSwipeAction extends React.Component<
7745 }
7846 }
7947
80- private _reset ( isOpened : boolean ) : void {
81- this . isMoving = false
82- this . isTouching = false
48+ public componentDidMount ( ) : void {
49+ if ( this . eleWidth === 0 ) {
50+ delayQuerySelector ( `#swipeAction-${ this . state . componentId } ` , 0 ) . then (
51+ res => {
52+ if ( res [ 0 ] ) {
53+ this . eleWidth = res [ 0 ] . width
54+ }
55+ }
56+ )
57+ }
58+ }
8359
60+ public componentDidUpdate ( ) : void {
61+ delayQuerySelector ( `#swipeAction-${ this . state . componentId } ` , 0 ) . then (
62+ res => {
63+ if ( res [ 0 ] ) {
64+ this . eleWidth = res [ 0 ] . width
65+ }
66+ }
67+ )
68+ }
69+
70+ private _reset ( isOpened : boolean ) : void {
8471 if ( isOpened ) {
85- this . endValue = - this . maxOffsetSize
8672 this . setState ( {
8773 _isOpened : true ,
88- offsetSize : - this . maxOffsetSize
74+ offsetSize : 0
8975 } )
9076 } else {
91- this . endValue = 0
92- this . setState ( {
93- offsetSize : 0 ,
94- _isOpened : false
95- } )
77+ this . setState (
78+ {
79+ offsetSize : this . moveX
80+ } ,
81+ ( ) => {
82+ this . setState ( {
83+ offsetSize : this . maxOffsetSize ,
84+ _isOpened : false
85+ } )
86+ }
87+ )
9688 }
9789 }
9890
99- private computeTransform = ( value : number ) : string | null =>
100- // if (Taro.getEnv() === Taro.ENV_TYPE.ALIPAY) {
101- // return !_isNil(value) ? `translate3d(${value}px,0,0)` : null
102- // }
103- value ? `translate3d(${ value } px,0,0)` : null
104-
10591 private handleOpened = ( event : CommonEvent ) : void => {
10692 const { onOpened } = this . props
10793 if ( typeof onOpened === 'function' && this . state . _isOpened ) {
@@ -116,78 +102,16 @@ export default class AtSwipeAction extends React.Component<
116102 }
117103 }
118104
119- private handleTouchStart = ( e : ITouchEvent ) : void => {
120- const { clientX, clientY } = e . touches [ 0 ]
121-
122- if ( this . props . disabled ) return
123-
124- this . getDomInfo ( )
125-
126- this . startX = clientX
127- this . startY = clientY
128- this . isTouching = true
129- }
130-
131- private handleTouchMove = ( e : ITouchEvent ) : void => {
132- if ( _isEmpty ( this . domInfo ) ) {
133- return
134- }
135-
136- const { startX, startY } = this
137- const { top, bottom, left, right } = this . domInfo
138- const { clientX, clientY, pageX, pageY } = e . touches [ 0 ]
139-
140- const x = Math . abs ( clientX - startX )
141- const y = Math . abs ( clientY - startY )
142-
143- const inDom = _inRange ( pageX , left , right ) && _inRange ( pageY , top , bottom )
144-
145- if ( ! this . isMoving && inDom ) {
146- this . isMoving =
147- y === 0 ||
148- x / y >= Number . parseFloat ( Math . tan ( ( 45 * Math . PI ) / 180 ) . toFixed ( 2 ) )
149- }
150-
151- if ( this . isTouching && this . isMoving ) {
152- e . preventDefault ( )
153-
154- const offsetSize = clientX - this . startX
155- const isRight = offsetSize > 0
156-
157- if ( this . state . offsetSize === 0 && isRight ) return
158-
159- const value = this . endValue + offsetSize
160- this . setState ( {
161- offsetSize : value >= 0 ? 0 : value
162- } )
163- }
164- }
165-
166- private handleTouchEnd = ( event : ITouchEvent ) : void => {
167- this . isTouching = false
168-
169- const { offsetSize } = this . state
170-
171- this . endValue = offsetSize
172-
173- const breakpoint = this . maxOffsetSize / 2
174- const absOffsetSize = Math . abs ( offsetSize )
175-
176- if ( absOffsetSize > breakpoint ) {
177- this . _reset ( true )
178- this . handleOpened ( event )
179- return
180- }
181-
182- this . _reset ( false ) // TODO: Check behavior
183- this . handleClosed ( event )
184- }
185-
186105 private handleDomInfo = ( { width } : { width : number } ) : void => {
187106 const { _isOpened } = this . state
188107
189108 this . maxOffsetSize = width
190109 this . _reset ( _isOpened )
110+ setTimeout ( ( ) => {
111+ this . setState ( {
112+ needAnimation : true
113+ } )
114+ } , 0 )
191115 }
192116
193117 private handleClick = (
@@ -206,51 +130,97 @@ export default class AtSwipeAction extends React.Component<
206130 }
207131 }
208132
133+ onTouchEnd = e => {
134+ if ( this . moveX === 0 ) {
135+ this . _reset ( true )
136+ this . handleOpened ( e )
137+ return
138+ }
139+ if ( this . moveX === this . maxOffsetSize ) {
140+ this . _reset ( false )
141+ this . handleClosed ( e )
142+ return
143+ }
144+ if ( this . state . _isOpened && this . moveX > 0 ) {
145+ this . _reset ( false )
146+ this . handleClosed ( e )
147+ return
148+ }
149+ if ( this . maxOffsetSize - this . moveX < this . maxOffsetSize * 0.4 ) {
150+ this . _reset ( false )
151+ this . handleClosed ( e )
152+ } else {
153+ this . _reset ( true )
154+ this . handleOpened ( e )
155+ }
156+ }
157+
158+ onChange = e => {
159+ this . moveX = e . detail . x
160+ }
161+
209162 public render ( ) : JSX . Element {
210- const { offsetSize, componentId } = this . state
163+ const { componentId , offsetSize, needAnimation } = this . state
211164 const { options } = this . props
212165 const rootClass = classNames ( 'at-swipe-action' , this . props . className )
213- const transform = this . computeTransform ( offsetSize )
214- const transformStyle : React . CSSProperties = transform ? { transform } : { }
215166
216167 return (
217168 < View
218169 id = { `swipeAction-${ componentId } ` }
219170 className = { rootClass }
220- onTouchMove = { this . handleTouchMove }
221- onTouchEnd = { this . handleTouchEnd }
222- onTouchStart = { this . handleTouchStart }
171+ style = { {
172+ width : this . eleWidth === 0 ? '100%' : ` $ {this . eleWidth } px`
173+ } }
223174 >
224- < View
225- className = { classNames ( 'at-swipe-action__content' , {
226- animtion : ! this . isTouching
227- } ) }
228- style = { transformStyle }
175+ < MovableArea
176+ className = 'at-swipe-action__area'
177+ style = { {
178+ width :
179+ this . eleWidth === 0
180+ ? '100%'
181+ : `${ this . eleWidth + this . maxOffsetSize } px` ,
182+ transform :
183+ this . eleWidth === 0
184+ ? `translate(0, 0)`
185+ : `translate(-${ this . maxOffsetSize } px, 0)`
186+ } }
229187 >
230- { this . props . children }
231- </ View >
232-
233- { Array . isArray ( options ) && options . length > 0 ? (
234- < AtSwipeActionOptions
235- options = { options }
236- componentId = { componentId }
237- onQueryedDom = { this . handleDomInfo }
188+ < MovableView
189+ className = 'at-swipe-action__content'
190+ direction = 'horizontal'
191+ damping = { 50 }
192+ x = { offsetSize }
193+ onTouchEnd = { this . onTouchEnd }
194+ onChange = { this . onChange }
195+ animation = { needAnimation }
196+ style = { {
197+ width : this . eleWidth === 0 ? '100%' : `${ this . eleWidth } px`
198+ } }
238199 >
239- { options . map ( ( item , key ) => (
240- < View
241- key = { `${ item . text } -${ key } ` }
242- style = { item . style }
243- onClick = { ( e ) : void => this . handleClick ( item , key , e ) }
244- className = { classNames (
245- 'at-swipe-action__option' ,
246- item . className
247- ) }
248- >
249- < Text className = 'option__text' > { item . text } </ Text >
250- </ View >
251- ) ) }
252- </ AtSwipeActionOptions >
253- ) : null }
200+ { this . props . children }
201+ </ MovableView >
202+ { Array . isArray ( options ) && options . length > 0 ? (
203+ < AtSwipeActionOptions
204+ options = { options }
205+ componentId = { componentId }
206+ onQueryedDom = { this . handleDomInfo }
207+ >
208+ { options . map ( ( item , key ) => (
209+ < View
210+ key = { `${ item . text } -${ key } ` }
211+ style = { item . style }
212+ onClick = { ( e ) : void => this . handleClick ( item , key , e ) }
213+ className = { classNames (
214+ 'at-swipe-action__option' ,
215+ item . className
216+ ) }
217+ >
218+ < Text className = 'option__text' > { item . text } </ Text >
219+ </ View >
220+ ) ) }
221+ </ AtSwipeActionOptions >
222+ ) : null }
223+ </ MovableArea >
254224 </ View >
255225 )
256226 }
0 commit comments