1
1
import classNames from 'classnames'
2
- import _inRange from 'lodash/inRange'
3
- import _isEmpty from 'lodash/isEmpty'
4
2
import PropTypes , { InferProps } from 'prop-types'
5
3
import 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'
8
6
import {
9
7
AtSwipeActionProps ,
10
8
AtSwipeActionState ,
11
9
SwipeActionOption
12
10
} from '../../../types/swipe-action'
13
- import {
14
- delayGetClientRect ,
15
- delayGetScrollOffset ,
16
- uuid
17
- } from '../../common/utils'
11
+ import { uuid } from '../../common/utils'
18
12
import AtSwipeActionOptions from './options/index'
19
13
20
14
export default class AtSwipeAction extends React . Component <
@@ -24,48 +18,22 @@ export default class AtSwipeAction extends React.Component<
24
18
public static defaultProps : AtSwipeActionProps
25
19
public static propTypes : InferProps < AtSwipeActionProps >
26
20
27
- private endValue : number
28
- private startX : number
29
- private startY : number
30
21
private maxOffsetSize : number
31
- private domInfo : any
32
- private isMoving : boolean
33
- private isTouching : boolean
22
+ private moveX : number
23
+ private eleWidth : number
34
24
35
25
public constructor ( props : AtSwipeActionProps ) {
36
26
super ( props )
37
- const { isOpened } = props
38
- this . endValue = 0
39
- this . startX = 0
40
- this . startY = 0
41
- 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
27
+ const { isOpened, maxDistance, areaWidth } = props
28
+ this . maxOffsetSize = maxDistance
50
29
this . state = {
51
30
componentId : uuid ( ) ,
52
31
offsetSize : 0 ,
53
- _isOpened : ! ! isOpened
32
+ _isOpened : ! ! isOpened ,
33
+ needAnimation : false
54
34
}
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 = areaWidth
69
37
}
70
38
71
39
public UNSAFE_componentWillReceiveProps ( nextProps : AtSwipeActionProps ) : void {
@@ -78,118 +46,40 @@ export default class AtSwipeAction extends React.Component<
78
46
}
79
47
80
48
private _reset ( isOpened : boolean ) : void {
81
- this . isMoving = false
82
- this . isTouching = false
83
-
84
49
if ( isOpened ) {
85
- this . endValue = - this . maxOffsetSize
86
50
this . setState ( {
87
51
_isOpened : true ,
88
- offsetSize : - this . maxOffsetSize
52
+ offsetSize : 0
89
53
} )
90
54
} else {
91
- this . endValue = 0
92
- this . setState ( {
93
- offsetSize : 0 ,
94
- _isOpened : false
95
- } )
55
+ this . setState (
56
+ {
57
+ offsetSize : this . moveX
58
+ } ,
59
+ ( ) => {
60
+ this . setState ( {
61
+ offsetSize : this . maxOffsetSize ,
62
+ _isOpened : false
63
+ } )
64
+ }
65
+ )
96
66
}
97
67
}
98
68
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
-
105
69
private handleOpened = ( event : CommonEvent ) : void => {
106
70
const { onOpened } = this . props
107
- if ( typeof onOpened === 'function' && this . state . _isOpened ) {
71
+ if ( typeof onOpened === 'function' ) {
108
72
onOpened ( event )
109
73
}
110
74
}
111
75
112
76
private handleClosed = ( event : CommonEvent ) : void => {
113
77
const { onClosed } = this . props
114
- if ( typeof onClosed === 'function' && ! this . state . _isOpened ) {
78
+ if ( typeof onClosed === 'function' ) {
115
79
onClosed ( event )
116
80
}
117
81
}
118
82
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
-
186
- private handleDomInfo = ( { width } : { width : number } ) : void => {
187
- const { _isOpened } = this . state
188
-
189
- this . maxOffsetSize = width
190
- this . _reset ( _isOpened )
191
- }
192
-
193
83
private handleClick = (
194
84
item : SwipeActionOption ,
195
85
index : number ,
@@ -206,51 +96,93 @@ export default class AtSwipeAction extends React.Component<
206
96
}
207
97
}
208
98
99
+ onTouchEnd = e => {
100
+ if ( this . moveX === 0 ) {
101
+ this . _reset ( true )
102
+ this . handleOpened ( e )
103
+ return
104
+ }
105
+ if ( this . moveX === this . maxOffsetSize ) {
106
+ this . _reset ( false )
107
+ this . handleClosed ( e )
108
+ return
109
+ }
110
+ if ( this . state . _isOpened && this . moveX > 0 ) {
111
+ this . _reset ( false )
112
+ this . handleClosed ( e )
113
+ return
114
+ }
115
+ if ( this . maxOffsetSize - this . moveX < this . maxOffsetSize * 0.4 ) {
116
+ this . _reset ( false )
117
+ this . handleClosed ( e )
118
+ } else {
119
+ this . _reset ( true )
120
+ this . handleOpened ( e )
121
+ }
122
+ }
123
+
124
+ onChange = e => {
125
+ this . moveX = e . detail . x
126
+ }
127
+
209
128
public render ( ) : JSX . Element {
210
- const { offsetSize , componentId } = this . state
129
+ const { componentId , offsetSize } = this . state
211
130
const { options } = this . props
212
131
const rootClass = classNames ( 'at-swipe-action' , this . props . className )
213
- const transform = this . computeTransform ( offsetSize )
214
- const transformStyle : React . CSSProperties = transform ? { transform } : { }
215
132
216
133
return (
217
134
< View
218
135
id = { `swipeAction-${ componentId } ` }
219
136
className = { rootClass }
220
- onTouchMove = { this . handleTouchMove }
221
- onTouchEnd = { this . handleTouchEnd }
222
- onTouchStart = { this . handleTouchStart }
137
+ style = { {
138
+ width : ` $ {this . eleWidth } px`
139
+ } }
223
140
>
224
- < View
225
- className = { classNames ( 'at-swipe-action__content' , {
226
- animtion : ! this . isTouching
227
- } ) }
228
- style = { transformStyle }
141
+ < MovableArea
142
+ className = 'at-swipe-action__area'
143
+ style = { {
144
+ width : `${ this . eleWidth + this . maxOffsetSize } px` ,
145
+ transform : `translate(-${ this . maxOffsetSize } px, 0)`
146
+ } }
229
147
>
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 }
148
+ < MovableView
149
+ className = 'at-swipe-action__content'
150
+ direction = 'horizontal'
151
+ damping = { 50 }
152
+ x = { offsetSize }
153
+ onTouchEnd = { this . onTouchEnd }
154
+ onChange = { this . onChange }
155
+ style = { {
156
+ width : `${ this . eleWidth } px`
157
+ } }
238
158
>
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
- ) }
159
+ { this . props . children }
160
+ { Array . isArray ( options ) && options . length > 0 ? (
161
+ < AtSwipeActionOptions
162
+ options = { options }
163
+ componentId = { componentId }
164
+ customStyle = { {
165
+ transform : `translate( ${ this . maxOffsetSize } px, 0)` ,
166
+ opacity : 1
167
+ } }
248
168
>
249
- < Text className = 'option__text' > { item . text } </ Text >
250
- </ View >
251
- ) ) }
252
- </ AtSwipeActionOptions >
253
- ) : null }
169
+ { options . map ( ( item , key ) => (
170
+ < View
171
+ key = { `${ item . text } -${ key } ` }
172
+ style = { item . style }
173
+ onClick = { ( e ) : void => this . handleClick ( item , key , e ) }
174
+ className = { classNames (
175
+ 'at-swipe-action__option' ,
176
+ item . className
177
+ ) }
178
+ >
179
+ < Text className = 'option__text' > { item . text } </ Text >
180
+ </ View >
181
+ ) ) }
182
+ </ AtSwipeActionOptions >
183
+ ) : null }
184
+ </ MovableView >
185
+ </ MovableArea >
254
186
</ View >
255
187
)
256
188
}
@@ -260,7 +192,9 @@ AtSwipeAction.defaultProps = {
260
192
options : [ ] ,
261
193
isOpened : false ,
262
194
disabled : false ,
263
- autoClose : false
195
+ autoClose : false ,
196
+ maxDistance : 0 ,
197
+ areaWidth : 0
264
198
}
265
199
266
200
AtSwipeAction . propTypes = {
0 commit comments