@momo-kits/swipe 0.0.32-beta → 0.0.32
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/SwipeAction.js +656 -1
- package/SwipeActionList.js +146 -1
- package/Swiper.js +772 -0
- package/index.js +7 -1
- package/package.json +5 -12
- package/publish.sh +2 -2
- package/babel.config.js +0 -1
package/SwipeAction.js
CHANGED
|
@@ -1 +1,656 @@
|
|
|
1
|
-
var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _extends2=_interopRequireDefault(require("@babel/runtime/helpers/extends"));var _defineProperty2=_interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));var _classCallCheck2=_interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));var _createClass2=_interopRequireDefault(require("@babel/runtime/helpers/createClass"));var _inherits2=_interopRequireDefault(require("@babel/runtime/helpers/inherits"));var _possibleConstructorReturn2=_interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));var _getPrototypeOf2=_interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));var _react=_interopRequireWildcard(require("react"));var _propTypes=_interopRequireDefault(require("prop-types"));var _reactNative=require("react-native");var _core=require("@momo-kits/core");var _jsxFileName="/Users/trinh.ho2/momo-folk/kits/src/libs/swipe/dist/SwipeAction.js";function _getRequireWildcardCache(nodeInterop){if(typeof WeakMap!=="function")return null;var cacheBabelInterop=new WeakMap();var cacheNodeInterop=new WeakMap();return(_getRequireWildcardCache=function _getRequireWildcardCache(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop;})(nodeInterop);}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule){return obj;}if(obj===null||typeof obj!=="object"&&typeof obj!=="function"){return{default:obj};}var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj)){return cache.get(obj);}var newObj={};var hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj){if(key!=="default"&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;if(desc&&(desc.get||desc.set)){Object.defineProperty(newObj,key,desc);}else{newObj[key]=obj[key];}}}newObj.default=obj;if(cache){cache.set(obj,newObj);}return newObj;}function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly){symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable;});}keys.push.apply(keys,symbols);}return keys;}function _objectSpread(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};if(i%2){ownKeys(Object(source),true).forEach(function(key){(0,_defineProperty2.default)(target,key,source[key]);});}else if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source));}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key));});}}return target;}function _createSuper(Derived){var hasNativeReflectConstruct=_isNativeReflectConstruct();return function _createSuperInternal(){var Super=(0,_getPrototypeOf2.default)(Derived),result;if(hasNativeReflectConstruct){var NewTarget=(0,_getPrototypeOf2.default)(this).constructor;result=Reflect.construct(Super,arguments,NewTarget);}else{result=Super.apply(this,arguments);}return(0,_possibleConstructorReturn2.default)(this,result);};}function _isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}));return true;}catch(e){return false;}}var DEFAULT_PREVIEW_OPEN_DELAY=700;var PREVIEW_CLOSE_DELAY=300;var MAX_VELOCITY_CONTRIBUTION=5;var SCROLL_LOCK_MILLISECONDS=300;var SCREEN_WIDTH=_reactNative.Dimensions.get('window').width;var WIDTH_HIDDEN_RIGHT=190;var SwipeAction=function(_Component){(0,_inherits2.default)(SwipeAction,_Component);var _super=_createSuper(SwipeAction);function SwipeAction(props){var _this;(0,_classCallCheck2.default)(this,SwipeAction);_this=_super.call(this,props);_this.ensureScrollEnabled=function(){if(!_this.parentScrollEnabled){_this.parentScrollEnabled=true;_this.props.setScrollEnabled&&_this.props.setScrollEnabled(true);}};_this.onLeftActionLayout=function(_ref){var nativeEvent=_ref.nativeEvent;_this.setState({leftOpenValue:nativeEvent.layout.width});};_this.onRightActionLayout=function(_ref2){var nativeEvent=_ref2.nativeEvent;_this.setState({rightOpenValue:-nativeEvent.layout.width});};_this.renderHiddenContent=function(){var _rightAction$slice;var _this$props=_this.props,actionBackground=_this$props.actionBackground,rowIndex=_this$props.rowIndex,rightAction=_this$props.rightAction,leftAction=_this$props.leftAction;var hiddenRowStyle=_objectSpread(_objectSpread({},styles.standaloneRowBack),{backgroundColor:actionBackground});return _react.default.createElement(_reactNative.View,{style:hiddenRowStyle,__source:{fileName:_jsxFileName,lineNumber:439,columnNumber:4}},_this.state.isLeftActionVisible&&_react.default.createElement(_reactNative.View,{style:styles.leftItemRow,__source:{fileName:_jsxFileName,lineNumber:443,columnNumber:7}},_react.default.createElement(_reactNative.View,{style:{flexDirection:'row'},onLayout:_this.onLeftActionLayout,__source:{fileName:_jsxFileName,lineNumber:444,columnNumber:8}},leftAction==null?void 0:leftAction.map==null?void 0:leftAction.map(function(item,index){return _this.renderLeftAction(item,index);}))),_this.state.isRightActionVisible&&_react.default.createElement(_reactNative.View,{style:styles.rightItemRow,__source:{fileName:_jsxFileName,lineNumber:455,columnNumber:7}},_react.default.createElement(_reactNative.View,{style:{flexDirection:'row'},onLayout:_this.onRightActionLayout,__source:{fileName:_jsxFileName,lineNumber:456,columnNumber:8}},rightAction==null?void 0:rightAction.slice==null?void 0:(_rightAction$slice=rightAction.slice(0))==null?void 0:_rightAction$slice.reverse().map(function(item,index){return _this.renderRightAction(item,index);}))));};_this.renderIcon=function(icon){var actionIconStyle=_this.props.actionIconStyle;var iconSource=_core.ValueUtil.getImageSource(icon);return _react.default.createElement(_reactNative.Image,{source:iconSource,resizeMode:"contain",style:[styles.icon,actionIconStyle],__source:{fileName:_jsxFileName,lineNumber:473,columnNumber:4}});};_this.renderTitle=function(title){var actionTextStyle=_this.props.actionTextStyle;return _react.default.createElement(_core.Text.SubTitle,{style:[styles.text,actionTextStyle],__source:{fileName:_jsxFileName,lineNumber:484,columnNumber:4}},title);};_this.onActionPress=function(item,rowIndex){return function(){var onPress=item.onPress;onPress==null?void 0:onPress(item,rowIndex);};};_this.renderRightAction=function(item,index){var _this$props2=_this.props,rowIndex=_this$props2.rowIndex,renderRightAction=_this$props2.renderRightAction;if(renderRightAction){return _react.default.createElement(_reactNative.View,{key:item+index,__source:{fileName:_jsxFileName,lineNumber:499,columnNumber:5}},renderRightAction({item:item,index:index,rowIndex:rowIndex}));}return _react.default.createElement(_reactNative.TouchableOpacity,{key:index.toString(),style:[styles.buttonContainer,{backgroundColor:item.color,height:_this.state.hiddenHeight}],onPress:_this.onActionPress(item,rowIndex),__source:{fileName:_jsxFileName,lineNumber:505,columnNumber:4}},item.icon&&_this.renderIcon(item.icon),item.title&&_this.renderTitle(item.title));};_this.renderLeftAction=function(item,index){var _this$props3=_this.props,rowIndex=_this$props3.rowIndex,renderLeftAction=_this$props3.renderLeftAction;if(renderLeftAction){return _react.default.createElement(_reactNative.View,{key:item+index,__source:{fileName:_jsxFileName,lineNumber:523,columnNumber:5}},renderLeftAction({item:item,index:index,rowIndex:rowIndex}));}return _react.default.createElement(_reactNative.TouchableOpacity,{key:index.toString(),style:[styles.buttonContainer,{backgroundColor:item.color,height:_this.state.hiddenHeight}],onPress:_this.onActionPress(item,rowIndex),__source:{fileName:_jsxFileName,lineNumber:529,columnNumber:4}},item.icon&&_this.renderIcon(item.icon),item.title&&_this.renderTitle(item.title));};_this.isOpen=false;_this.previousTrackedTranslateX=0;_this.previousTrackedDirection=null;_this.horizontalSwipeGestureBegan=false;_this.swipeInitialX=null;_this.parentScrollEnabled=true;_this.ranPreview=false;_this._ensureScrollEnabledTimer=null;_this.isForceClosing=false;_this.state={dimensionsSet:false,hiddenHeight:_this.props.disableHiddenLayoutCalculation?'100%':0,hiddenWidth:_this.props.disableHiddenLayoutCalculation?'100%':0,isLeftActionVisible:false,isRightActionVisible:false,leftOpenValue:0,rightOpenValue:0};var _this$props4=_this.props,_leftAction=_this$props4.leftAction,_rightAction=_this$props4.rightAction;var buttonCellWidth=WIDTH_HIDDEN_RIGHT/2;_this.stopLeftSwipe=SCREEN_WIDTH;_this.stopRightSwipe=-SCREEN_WIDTH;_this._translateX=new _reactNative.Animated.Value(0);if(_this.props.onSwipeValueChange){_this._translateX.addListener(function(_ref3){var value=_ref3.value;var direction=_this.previousTrackedDirection;if(value!==_this.previousTrackedTranslateX){direction=value>_this.previousTrackedTranslateX?'right':'left';}_this.props.onSwipeValueChange&&_this.props.onSwipeValueChange({isOpen:_this.isOpen,direction:direction,value:value});_this.previousTrackedTranslateX=value;_this.previousTrackedDirection=direction;});}if(_this.props.forceCloseToRightThreshold&&_this.props.forceCloseToRightThreshold>0){_this._translateX.addListener(function(_ref4){var value=_ref4.value;if(!_this.isForceClosing&&SCREEN_WIDTH+value<_this.props.forceCloseToRightThreshold){_this.isForceClosing=true;_this.forceCloseRow('right');if(_this.props.onForceCloseToRight){_this.props.onForceCloseToRight();}}});}if(_this.props.forceCloseToLeftThreshold&&_this.props.forceCloseToLeftThreshold>0){_this._translateX.addListener(function(_ref5){var value=_ref5.value;if(!_this.isForceClosing&&SCREEN_WIDTH-value<_this.props.forceCloseToLeftThreshold){_this.isForceClosing=true;_this.forceCloseRow('left');if(_this.props.onForceCloseToLeft){_this.props.onForceCloseToLeft();}}});}return _this;}(0,_createClass2.default)(SwipeAction,[{key:"UNSAFE_componentWillMount",value:function UNSAFE_componentWillMount(){var _this2=this;this._panResponder=_reactNative.PanResponder.create({onMoveShouldSetPanResponder:function onMoveShouldSetPanResponder(e,gs){return _this2.handleOnMoveShouldSetPanResponder(e,gs);},onPanResponderMove:function onPanResponderMove(e,gs){return _this2.handlePanResponderMove(e,gs);},onPanResponderRelease:function onPanResponderRelease(e,gs){return _this2.handlePanResponderEnd(e,gs);},onPanResponderTerminate:function onPanResponderTerminate(e,gs){return _this2.handlePanResponderEnd(e,gs);},onShouldBlockNativeResponder:function onShouldBlockNativeResponder(_){return false;}});}},{key:"componentWillUnmount",value:function componentWillUnmount(){clearTimeout(this._ensureScrollEnabledTimer);this._translateX.removeAllListeners();}},{key:"shouldComponentUpdate",value:function shouldComponentUpdate(nextProps,nextState){if(this.state.hiddenHeight!==nextState.hiddenHeight||this.state.hiddenWidth!==nextState.hiddenWidth||!this.props.shouldItemUpdate||this.props.shouldItemUpdate&&this.props.shouldItemUpdate(this.props.item,nextProps.item)){return true;}return false;}},{key:"getPreviewAnimation",value:function getPreviewAnimation(toValue,delay){return _reactNative.Animated.timing(this._translateX,{duration:this.props.previewDuration,toValue:toValue,delay:delay,useNativeDriver:this.props.useNativeDriver});}},{key:"onContentLayout",value:function onContentLayout(e){var _this3=this;this.setState(_objectSpread({dimensionsSet:!this.props.recalculateHiddenLayout},!this.props.disableHiddenLayoutCalculation?{hiddenHeight:e.nativeEvent.layout.height,hiddenWidth:e.nativeEvent.layout.width}:{}));if(this.props.preview&&!this.ranPreview){this.ranPreview=true;var previewOpenValue=this.props.previewOpenValue||this.state.rightOpenValue*0.5;this.getPreviewAnimation(previewOpenValue,this.props.previewOpenDelay).start(function(_){_this3.getPreviewAnimation(0,PREVIEW_CLOSE_DELAY).start();});}}},{key:"onPress",value:function onPress(){if(this.swipeInitialX==null||this.swipeInitialX===0){if(this.props.onPress&&typeof this.props.onPress==='function'){this.props.onPress();}}else{if(this.props.closeOnPress){this.closeRow();}}}},{key:"handleOnMoveShouldSetPanResponder",value:function handleOnMoveShouldSetPanResponder(e,gs){var dx=gs.dx;return Math.abs(dx)>this.props.directionalDistanceChangeThreshold;}},{key:"handlePanResponderMove",value:function handlePanResponderMove(e,gestureState){if(this.isForceClosing){return;}var dx=gestureState.dx,dy=gestureState.dy;var absDx=Math.abs(dx);var absDy=Math.abs(dy);if(absDx>this.props.directionalDistanceChangeThreshold||absDy>this.props.directionalDistanceChangeThreshold){if(absDy>absDx&&!this.horizontalSwipeGestureBegan){return;}if(this.parentScrollEnabled){this.parentScrollEnabled=false;this.props.setScrollEnabled&&this.props.setScrollEnabled(false);}if(this.swipeInitialX===null){this.swipeInitialX=this._translateX._value;}if(!this.horizontalSwipeGestureBegan){this.horizontalSwipeGestureBegan=true;var direction=dx>0?'TO_RIGHT':'TO_LEFT';this.props.swipeGestureBegan&&this.props.swipeGestureBegan(direction);}var newDX=this.swipeInitialX+dx;if(this.props.disableRightAction&&newDX<0){newDX=0;}if(this.props.disableLeftAction&&newDX>0){newDX=0;}if(this.stopLeftSwipe&&newDX>this.stopLeftSwipe){newDX=this.stopLeftSwipe;}if(this.stopRightSwipe&&newDX<this.stopRightSwipe){newDX=this.stopRightSwipe;}if(newDX>0){this.setState({isLeftActionVisible:true,isRightActionVisible:false});}else if(newDX<0){this.setState({isRightActionVisible:true,isLeftActionVisible:false});}this._translateX.setValue(newDX);}}},{key:"handlePanResponderEnd",value:function handlePanResponderEnd(e,gestureState){if(this.isForceClosing){this.isForceClosing=false;}var swipeToOpenVelocityContribution=this.props.swipeToOpenVelocityContribution;var possibleExtraPixels=this.state.rightOpenValue*swipeToOpenVelocityContribution;var clampedVelocity=Math.min(gestureState.vx,MAX_VELOCITY_CONTRIBUTION);var projectedExtraPixels=possibleExtraPixels*(clampedVelocity/MAX_VELOCITY_CONTRIBUTION);this._ensureScrollEnabledTimer=setTimeout(this.ensureScrollEnabled,SCROLL_LOCK_MILLISECONDS);var toValue=0;if(this._translateX._value>=0){if(this.swipeInitialX<this._translateX._value){if(this._translateX._value-projectedExtraPixels>this.state.leftOpenValue*(this.props.swipeToOpenPercent/100)){toValue=this.state.leftOpenValue;}}else if(this._translateX._value-projectedExtraPixels>this.state.leftOpenValue*(1-this.props.swipeToClosePercent/100)){toValue=this.state.leftOpenValue;}}else{if(this.swipeInitialX>this._translateX._value){if(this._translateX._value-projectedExtraPixels<this.state.rightOpenValue*(this.props.swipeToOpenPercent/100)){toValue=this.state.rightOpenValue;}}else if(this._translateX._value-projectedExtraPixels<this.state.rightOpenValue*(1-this.props.swipeToClosePercent/100)){toValue=this.state.rightOpenValue;}}this.props.swipeGestureEnd&&this.props.swipeGestureEnd();this.manuallySwipeRow(toValue);}},{key:"closeRow",value:function closeRow(){this.manuallySwipeRow(0);}},{key:"forceCloseRow",value:function forceCloseRow(direction){var _this4=this;this.manuallySwipeRow(0,function(){if(direction==='right'&&_this4.props.onForceCloseToRightEnd){_this4.props.onForceCloseToRightEnd();}else if(direction==='left'&&_this4.props.onForceCloseToLeftEnd){_this4.props.onForceCloseToLeftEnd();}});}},{key:"closeRowWithoutAnimation",value:function closeRowWithoutAnimation(){this._translateX.setValue(0);this.ensureScrollEnabled();this.isOpen=false;this.props.onDidClose&&this.props.onDidClose();this.props.onClose&&this.props.onClose();this.swipeInitialX=null;this.horizontalSwipeGestureBegan=false;}},{key:"manuallySwipeRow",value:function manuallySwipeRow(toValue,onAnimationEnd){var _this5=this;_reactNative.Animated.spring(this._translateX,{toValue:toValue,friction:this.props.friction,tension:this.props.tension,useNativeDriver:this.props.useNativeDriver}).start(function(_){_this5._translateX.setValue(toValue);_this5.ensureScrollEnabled();if(toValue===0){_this5.isOpen=false;_this5.props.onDidClose&&_this5.props.onDidClose();}else{_this5.isOpen=true;_this5.props.onDidOpen&&_this5.props.onDidOpen(toValue);}if(onAnimationEnd){onAnimationEnd();}});if(toValue===0){this.props.onClose&&this.props.onClose();}else{this.props.onOpen&&this.props.onOpen(toValue);}this.swipeInitialX=toValue;this.horizontalSwipeGestureBegan=false;}},{key:"renderVisibleContent",value:function renderVisibleContent(){var _this6=this;if(this.props.children){var onPress=this.props.children.props.onPress;if(onPress){var newOnPress=function newOnPress(_){_this6.onPress();onPress();};return _react.default.cloneElement(this.props.children,_objectSpread(_objectSpread({},this.props.children.props),{},{onPress:newOnPress}));}return _react.default.createElement(_reactNative.TouchableOpacity,{activeOpacity:1,onPress:function onPress(_){return _this6.onPress();},__source:{fileName:_jsxFileName,lineNumber:372,columnNumber:5}},this.props.children);}}},{key:"renderRowContent",value:function renderRowContent(){var _this7=this;if(this.state.dimensionsSet){return _react.default.createElement(_reactNative.Animated.View,(0,_extends2.default)({manipulationModes:['translateX']},this._panResponder.panHandlers,{style:{zIndex:2,transform:[{translateX:this._translateX}]},__source:{fileName:_jsxFileName,lineNumber:387,columnNumber:5}}),this.renderVisibleContent());}return _react.default.createElement(_reactNative.Animated.View,(0,_extends2.default)({manipulationModes:['translateX']},this._panResponder.panHandlers,{onLayout:function onLayout(e){return _this7.onContentLayout(e);},style:{zIndex:2,transform:[{translateX:this._translateX}]},__source:{fileName:_jsxFileName,lineNumber:402,columnNumber:4}}),this.renderVisibleContent());}},{key:"render",value:function render(){return _react.default.createElement(_reactNative.View,{style:this.props.style?this.props.style:styles.container,__source:{fileName:_jsxFileName,lineNumber:545,columnNumber:4}},_react.default.createElement(_reactNative.View,{style:[styles.hidden,{height:this.state.hiddenHeight,width:this.state.hiddenWidth}],__source:{fileName:_jsxFileName,lineNumber:546,columnNumber:5}},this.renderHiddenContent()),this.renderRowContent());}}]);return SwipeAction;}(_react.Component);var styles=_reactNative.StyleSheet.create({container:{},hidden:{zIndex:1,bottom:0,left:0,overflow:'hidden',position:'absolute',right:0,top:0},standaloneRowBack:{backgroundColor:_core.Colors.white,alignItems:'center',flex:1,flexDirection:'row',justifyContent:'space-between'},leftItemRow:{alignItems:'center',flex:1,flexDirection:'row',justifyContent:'flex-start',paddingRight:10},rightItemRow:{alignItems:'center',flex:1,flexDirection:'row',justifyContent:'flex-end',paddingLeft:10},buttonContainer:{backgroundColor:'red',alignItems:'center',justifyContent:'center',width:88},icon:{height:24,width:24,tintColor:'white'},text:{color:_core.Colors.white,textAlign:'center',marginHorizontal:10,marginTop:10}});SwipeAction.propTypes={onOpen:_propTypes.default.func,closeOnPress:_propTypes.default.bool,disableRightAction:_propTypes.default.bool,disableLeftAction:_propTypes.default.bool,onClose:_propTypes.default.func,style:_propTypes.default.oneOfType([_propTypes.default.object,_propTypes.default.array]),leftAction:_propTypes.default.array,rightAction:_propTypes.default.array,renderRightAction:_propTypes.default.func,renderLeftAction:_propTypes.default.func,onPress:_propTypes.default.func,children:_propTypes.default.element.isRequired,actionBackground:_propTypes.default.string,actionTextStyle:_propTypes.default.object};SwipeAction.defaultProps={closeOnPress:true,disableRightAction:true,disableLeftAction:true,recalculateHiddenLayout:false,disableHiddenLayoutCalculation:false,preview:false,previewDuration:300,previewOpenDelay:DEFAULT_PREVIEW_OPEN_DELAY,directionalDistanceChangeThreshold:2,swipeToOpenPercent:50,swipeToOpenVelocityContribution:0,swipeToClosePercent:50,swipeToPerformActionPercent:50,item:{},useNativeDriver:true,rightAction:[],leftAction:[],actionBackground:_core.Colors.white};var _default=SwipeAction;exports.default=_default;
|
|
1
|
+
/* eslint-disable react/default-props-match-prop-types */
|
|
2
|
+
/* eslint-disable react/jsx-closing-tag-location */
|
|
3
|
+
/* eslint-disable react/jsx-indent-props */
|
|
4
|
+
/* eslint-disable indent */
|
|
5
|
+
/* eslint-disable react/jsx-indent */
|
|
6
|
+
/* eslint-disable no-unused-vars */
|
|
7
|
+
/* eslint-disable no-mixed-spaces-and-tabs */
|
|
8
|
+
/* eslint-disable no-lonely-if */
|
|
9
|
+
/* eslint-disable no-tabs */
|
|
10
|
+
/* eslint-disable no-unused-expressions */
|
|
11
|
+
/* eslint-disable react/destructuring-assignment */
|
|
12
|
+
|
|
13
|
+
import React, {
|
|
14
|
+
Component,
|
|
15
|
+
} from 'react';
|
|
16
|
+
import PropTypes from 'prop-types';
|
|
17
|
+
import {
|
|
18
|
+
Dimensions,
|
|
19
|
+
Animated,
|
|
20
|
+
PanResponder,
|
|
21
|
+
StyleSheet,
|
|
22
|
+
TouchableOpacity,
|
|
23
|
+
View,
|
|
24
|
+
Image
|
|
25
|
+
} from 'react-native';
|
|
26
|
+
import { Colors, ValueUtil, Text } from '@momo-kits/core';
|
|
27
|
+
|
|
28
|
+
const DEFAULT_PREVIEW_OPEN_DELAY = 700;
|
|
29
|
+
const PREVIEW_CLOSE_DELAY = 300;
|
|
30
|
+
const MAX_VELOCITY_CONTRIBUTION = 5;
|
|
31
|
+
const SCROLL_LOCK_MILLISECONDS = 300;
|
|
32
|
+
const SCREEN_WIDTH = Dimensions.get('window').width;
|
|
33
|
+
const WIDTH_HIDDEN_RIGHT = 190;
|
|
34
|
+
class SwipeAction extends Component {
|
|
35
|
+
constructor(props) {
|
|
36
|
+
super(props);
|
|
37
|
+
this.isOpen = false;
|
|
38
|
+
this.previousTrackedTranslateX = 0;
|
|
39
|
+
this.previousTrackedDirection = null;
|
|
40
|
+
this.horizontalSwipeGestureBegan = false;
|
|
41
|
+
this.swipeInitialX = null;
|
|
42
|
+
this.parentScrollEnabled = true;
|
|
43
|
+
this.ranPreview = false;
|
|
44
|
+
this._ensureScrollEnabledTimer = null;
|
|
45
|
+
this.isForceClosing = false;
|
|
46
|
+
this.state = {
|
|
47
|
+
dimensionsSet: false,
|
|
48
|
+
hiddenHeight: this.props.disableHiddenLayoutCalculation ? '100%' : 0,
|
|
49
|
+
hiddenWidth: this.props.disableHiddenLayoutCalculation ? '100%' : 0,
|
|
50
|
+
isLeftActionVisible: false,
|
|
51
|
+
isRightActionVisible: false,
|
|
52
|
+
leftOpenValue: 0,
|
|
53
|
+
rightOpenValue: 0
|
|
54
|
+
};
|
|
55
|
+
const { leftAction, rightAction } = this.props;
|
|
56
|
+
const buttonCellWidth = WIDTH_HIDDEN_RIGHT / 2;
|
|
57
|
+
// leftAction ? this.leftOpenValue = leftAction.length * buttonCellWidth : 0;
|
|
58
|
+
// rightAction ? this.rightOpenValue = -rightAction.length * buttonCellWidth : 0;
|
|
59
|
+
this.stopLeftSwipe = SCREEN_WIDTH;
|
|
60
|
+
this.stopRightSwipe = -SCREEN_WIDTH;
|
|
61
|
+
this._translateX = new Animated.Value(0);
|
|
62
|
+
if (this.props.onSwipeValueChange) {
|
|
63
|
+
this._translateX.addListener(({ value }) => {
|
|
64
|
+
let direction = this.previousTrackedDirection;
|
|
65
|
+
if (value !== this.previousTrackedTranslateX) {
|
|
66
|
+
direction = value > this.previousTrackedTranslateX ? 'right' : 'left';
|
|
67
|
+
}
|
|
68
|
+
this.props.onSwipeValueChange && this.props.onSwipeValueChange({
|
|
69
|
+
isOpen: this.isOpen,
|
|
70
|
+
direction,
|
|
71
|
+
value,
|
|
72
|
+
});
|
|
73
|
+
this.previousTrackedTranslateX = value;
|
|
74
|
+
this.previousTrackedDirection = direction;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (this.props.forceCloseToRightThreshold && this.props.forceCloseToRightThreshold > 0) {
|
|
79
|
+
this._translateX.addListener(({ value }) => {
|
|
80
|
+
if (!this.isForceClosing && (SCREEN_WIDTH + value) < this.props.forceCloseToRightThreshold) {
|
|
81
|
+
this.isForceClosing = true;
|
|
82
|
+
this.forceCloseRow('right');
|
|
83
|
+
if (this.props.onForceCloseToRight) {
|
|
84
|
+
this.props.onForceCloseToRight();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (this.props.forceCloseToLeftThreshold && this.props.forceCloseToLeftThreshold > 0) {
|
|
91
|
+
this._translateX.addListener(({ value }) => {
|
|
92
|
+
if (!this.isForceClosing && (SCREEN_WIDTH - value) < this.props.forceCloseToLeftThreshold) {
|
|
93
|
+
this.isForceClosing = true;
|
|
94
|
+
this.forceCloseRow('left');
|
|
95
|
+
if (this.props.onForceCloseToLeft) {
|
|
96
|
+
this.props.onForceCloseToLeft();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
UNSAFE_componentWillMount() {
|
|
104
|
+
this._panResponder = PanResponder.create({
|
|
105
|
+
onMoveShouldSetPanResponder: (e, gs) => this.handleOnMoveShouldSetPanResponder(e, gs),
|
|
106
|
+
onPanResponderMove: (e, gs) => this.handlePanResponderMove(e, gs),
|
|
107
|
+
onPanResponderRelease: (e, gs) => this.handlePanResponderEnd(e, gs),
|
|
108
|
+
onPanResponderTerminate: (e, gs) => this.handlePanResponderEnd(e, gs),
|
|
109
|
+
onShouldBlockNativeResponder: (_) => false,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
componentWillUnmount() {
|
|
114
|
+
clearTimeout(this._ensureScrollEnabledTimer);
|
|
115
|
+
this._translateX.removeAllListeners();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
shouldComponentUpdate(nextProps, nextState) {
|
|
119
|
+
if (this.state.hiddenHeight !== nextState.hiddenHeight
|
|
120
|
+
|| this.state.hiddenWidth !== nextState.hiddenWidth
|
|
121
|
+
|| !this.props.shouldItemUpdate
|
|
122
|
+
|| (this.props.shouldItemUpdate && this.props.shouldItemUpdate(this.props.item, nextProps.item))) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
getPreviewAnimation(toValue, delay) {
|
|
130
|
+
return Animated.timing(
|
|
131
|
+
this._translateX,
|
|
132
|
+
{
|
|
133
|
+
duration: this.props.previewDuration, toValue, delay, useNativeDriver: this.props.useNativeDriver
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
onContentLayout(e) {
|
|
139
|
+
this.setState({
|
|
140
|
+
dimensionsSet: !this.props.recalculateHiddenLayout,
|
|
141
|
+
...(!this.props.disableHiddenLayoutCalculation ? {
|
|
142
|
+
hiddenHeight: e.nativeEvent.layout.height,
|
|
143
|
+
hiddenWidth: e.nativeEvent.layout.width,
|
|
144
|
+
} : {})
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
if (this.props.preview && !this.ranPreview) {
|
|
148
|
+
this.ranPreview = true;
|
|
149
|
+
const previewOpenValue = this.props.previewOpenValue || this.state.rightOpenValue * 0.5;
|
|
150
|
+
this.getPreviewAnimation(previewOpenValue, this.props.previewOpenDelay)
|
|
151
|
+
.start((_) => {
|
|
152
|
+
this.getPreviewAnimation(0, PREVIEW_CLOSE_DELAY).start();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
onPress() {
|
|
158
|
+
if (this.swipeInitialX == null || this.swipeInitialX === 0) {
|
|
159
|
+
if (this.props.onPress && typeof this.props.onPress === 'function') {
|
|
160
|
+
this.props.onPress();
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
if (this.props.closeOnPress) {
|
|
164
|
+
this.closeRow();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
handleOnMoveShouldSetPanResponder(e, gs) {
|
|
170
|
+
const { dx } = gs;
|
|
171
|
+
return Math.abs(dx) > this.props.directionalDistanceChangeThreshold;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
handlePanResponderMove(e, gestureState) {
|
|
175
|
+
/* If the view is force closing, then ignore Moves. Return */
|
|
176
|
+
if (this.isForceClosing) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Else, do normal job */
|
|
181
|
+
const { dx, dy } = gestureState;
|
|
182
|
+
const absDx = Math.abs(dx);
|
|
183
|
+
const absDy = Math.abs(dy);
|
|
184
|
+
|
|
185
|
+
// this check may not be necessary because we don't capture the move until we pass the threshold
|
|
186
|
+
// just being extra safe here
|
|
187
|
+
if (absDx > this.props.directionalDistanceChangeThreshold || absDy > this.props.directionalDistanceChangeThreshold) {
|
|
188
|
+
// we have enough to determine direction
|
|
189
|
+
if (absDy > absDx && !this.horizontalSwipeGestureBegan) {
|
|
190
|
+
// user is moving vertically, do nothing, listView will handle
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// user is moving horizontally
|
|
195
|
+
if (this.parentScrollEnabled) {
|
|
196
|
+
// disable scrolling on the listView parent
|
|
197
|
+
this.parentScrollEnabled = false;
|
|
198
|
+
this.props.setScrollEnabled && this.props.setScrollEnabled(false);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (this.swipeInitialX === null) {
|
|
202
|
+
// set tranlateX value when user started swiping
|
|
203
|
+
this.swipeInitialX = this._translateX._value;
|
|
204
|
+
}
|
|
205
|
+
if (!this.horizontalSwipeGestureBegan) {
|
|
206
|
+
this.horizontalSwipeGestureBegan = true;
|
|
207
|
+
const direction = dx > 0 ? 'TO_RIGHT' : 'TO_LEFT';
|
|
208
|
+
this.props.swipeGestureBegan && this.props.swipeGestureBegan(direction);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let newDX = this.swipeInitialX + dx;
|
|
212
|
+
if (this.props.disableRightAction && newDX < 0) { newDX = 0; }
|
|
213
|
+
if (this.props.disableLeftAction && newDX > 0) { newDX = 0; }
|
|
214
|
+
|
|
215
|
+
if (this.stopLeftSwipe && newDX > this.stopLeftSwipe) { newDX = this.stopLeftSwipe; }
|
|
216
|
+
if (this.stopRightSwipe && newDX < this.stopRightSwipe) { newDX = this.stopRightSwipe; }
|
|
217
|
+
|
|
218
|
+
// set action buttons visibility
|
|
219
|
+
if (newDX > 0) {
|
|
220
|
+
this.setState({
|
|
221
|
+
isLeftActionVisible: true,
|
|
222
|
+
isRightActionVisible: false
|
|
223
|
+
});
|
|
224
|
+
} else if (newDX < 0) {
|
|
225
|
+
this.setState({
|
|
226
|
+
isRightActionVisible: true,
|
|
227
|
+
isLeftActionVisible: false,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
this._translateX.setValue(newDX);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
ensureScrollEnabled = () => {
|
|
236
|
+
if (!this.parentScrollEnabled) {
|
|
237
|
+
this.parentScrollEnabled = true;
|
|
238
|
+
this.props.setScrollEnabled && this.props.setScrollEnabled(true);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
handlePanResponderEnd(e, gestureState) {
|
|
243
|
+
/* PandEnd will reset the force-closing state when it's true. */
|
|
244
|
+
if (this.isForceClosing) {
|
|
245
|
+
this.isForceClosing = false;
|
|
246
|
+
}
|
|
247
|
+
// decide how much the velocity will affect the final position that the list item settles in.
|
|
248
|
+
const { swipeToOpenVelocityContribution } = this.props;
|
|
249
|
+
const possibleExtraPixels = this.state.rightOpenValue * (swipeToOpenVelocityContribution);
|
|
250
|
+
const clampedVelocity = Math.min(gestureState.vx, MAX_VELOCITY_CONTRIBUTION);
|
|
251
|
+
const projectedExtraPixels = possibleExtraPixels * (clampedVelocity / MAX_VELOCITY_CONTRIBUTION);
|
|
252
|
+
|
|
253
|
+
// re-enable scrolling on listView parent
|
|
254
|
+
this._ensureScrollEnabledTimer = setTimeout(this.ensureScrollEnabled, SCROLL_LOCK_MILLISECONDS);
|
|
255
|
+
|
|
256
|
+
// finish up the animation
|
|
257
|
+
let toValue = 0;
|
|
258
|
+
if (this._translateX._value >= 0) {
|
|
259
|
+
// trying to swipe right
|
|
260
|
+
if (this.swipeInitialX < this._translateX._value) {
|
|
261
|
+
if ((this._translateX._value - projectedExtraPixels) > this.state.leftOpenValue * (this.props.swipeToOpenPercent / 100)) {
|
|
262
|
+
// we're more than halfway
|
|
263
|
+
toValue = this.state.leftOpenValue;
|
|
264
|
+
}
|
|
265
|
+
} else if ((this._translateX._value - projectedExtraPixels) > this.state.leftOpenValue * (1 - (this.props.swipeToClosePercent / 100))) {
|
|
266
|
+
toValue = this.state.leftOpenValue;
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
// trying to swipe left
|
|
270
|
+
if (this.swipeInitialX > this._translateX._value) {
|
|
271
|
+
if ((this._translateX._value - projectedExtraPixels) < this.state.rightOpenValue * (this.props.swipeToOpenPercent / 100)) {
|
|
272
|
+
// we're more than halfway
|
|
273
|
+
toValue = this.state.rightOpenValue;
|
|
274
|
+
}
|
|
275
|
+
} else if ((this._translateX._value - projectedExtraPixels) < this.state.rightOpenValue * (1 - (this.props.swipeToClosePercent / 100))) {
|
|
276
|
+
toValue = this.state.rightOpenValue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
this.props.swipeGestureEnd && this.props.swipeGestureEnd();
|
|
281
|
+
this.manuallySwipeRow(toValue);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/*
|
|
285
|
+
* This method is called by SwipeListView
|
|
286
|
+
*/
|
|
287
|
+
closeRow() {
|
|
288
|
+
this.manuallySwipeRow(0);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Force close the row toward the end of the given direction.
|
|
293
|
+
* @param {String} direction The direction to force close.
|
|
294
|
+
*/
|
|
295
|
+
forceCloseRow(direction) {
|
|
296
|
+
this.manuallySwipeRow(0, () => {
|
|
297
|
+
if (direction === 'right' && this.props.onForceCloseToRightEnd) {
|
|
298
|
+
this.props.onForceCloseToRightEnd();
|
|
299
|
+
} else if (direction === 'left' && this.props.onForceCloseToLeftEnd) {
|
|
300
|
+
this.props.onForceCloseToLeftEnd();
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
closeRowWithoutAnimation() {
|
|
306
|
+
this._translateX.setValue(0);
|
|
307
|
+
|
|
308
|
+
this.ensureScrollEnabled();
|
|
309
|
+
this.isOpen = false;
|
|
310
|
+
this.props.onDidClose && this.props.onDidClose();
|
|
311
|
+
|
|
312
|
+
this.props.onClose && this.props.onClose();
|
|
313
|
+
|
|
314
|
+
this.swipeInitialX = null;
|
|
315
|
+
this.horizontalSwipeGestureBegan = false;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
manuallySwipeRow(toValue, onAnimationEnd) {
|
|
319
|
+
Animated.spring(
|
|
320
|
+
this._translateX,
|
|
321
|
+
{
|
|
322
|
+
toValue,
|
|
323
|
+
friction: this.props.friction,
|
|
324
|
+
tension: this.props.tension,
|
|
325
|
+
useNativeDriver: this.props.useNativeDriver,
|
|
326
|
+
}
|
|
327
|
+
).start((_) => {
|
|
328
|
+
this._translateX.setValue(toValue);
|
|
329
|
+
this.ensureScrollEnabled();
|
|
330
|
+
if (toValue === 0) {
|
|
331
|
+
this.isOpen = false;
|
|
332
|
+
this.props.onDidClose && this.props.onDidClose();
|
|
333
|
+
} else {
|
|
334
|
+
this.isOpen = true;
|
|
335
|
+
this.props.onDidOpen && this.props.onDidOpen(toValue);
|
|
336
|
+
}
|
|
337
|
+
if (onAnimationEnd) {
|
|
338
|
+
onAnimationEnd();
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
if (toValue === 0) {
|
|
343
|
+
this.props.onClose && this.props.onClose();
|
|
344
|
+
} else {
|
|
345
|
+
this.props.onOpen && this.props.onOpen(toValue);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// reset everything
|
|
349
|
+
this.swipeInitialX = toValue;
|
|
350
|
+
this.horizontalSwipeGestureBegan = false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
renderVisibleContent() {
|
|
354
|
+
if (this.props.children) {
|
|
355
|
+
// handle touchables
|
|
356
|
+
const { onPress } = this.props.children.props;
|
|
357
|
+
|
|
358
|
+
if (onPress) {
|
|
359
|
+
const newOnPress = (_) => {
|
|
360
|
+
this.onPress();
|
|
361
|
+
onPress();
|
|
362
|
+
};
|
|
363
|
+
return React.cloneElement(
|
|
364
|
+
this.props.children,
|
|
365
|
+
{
|
|
366
|
+
...this.props.children.props,
|
|
367
|
+
onPress: newOnPress
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
return (
|
|
372
|
+
<TouchableOpacity
|
|
373
|
+
activeOpacity={1}
|
|
374
|
+
onPress={(_) => this.onPress()}
|
|
375
|
+
>
|
|
376
|
+
{this.props.children}
|
|
377
|
+
</TouchableOpacity>
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
renderRowContent() {
|
|
383
|
+
// We do this annoying if statement for performance.
|
|
384
|
+
// We don't want the onLayout func to run after it runs once.
|
|
385
|
+
if (this.state.dimensionsSet) {
|
|
386
|
+
return (
|
|
387
|
+
<Animated.View
|
|
388
|
+
manipulationModes={['translateX']}
|
|
389
|
+
{...this._panResponder.panHandlers}
|
|
390
|
+
style={{
|
|
391
|
+
zIndex: 2,
|
|
392
|
+
transform: [
|
|
393
|
+
{ translateX: this._translateX }
|
|
394
|
+
]
|
|
395
|
+
}}
|
|
396
|
+
>
|
|
397
|
+
{this.renderVisibleContent()}
|
|
398
|
+
</Animated.View>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
return (
|
|
402
|
+
<Animated.View
|
|
403
|
+
manipulationModes={['translateX']}
|
|
404
|
+
{...this._panResponder.panHandlers}
|
|
405
|
+
onLayout={(e) => this.onContentLayout(e)}
|
|
406
|
+
style={{
|
|
407
|
+
zIndex: 2,
|
|
408
|
+
transform: [
|
|
409
|
+
{ translateX: this._translateX }
|
|
410
|
+
]
|
|
411
|
+
}}
|
|
412
|
+
>
|
|
413
|
+
{this.renderVisibleContent()}
|
|
414
|
+
</Animated.View>
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
onLeftActionLayout = ({ nativeEvent }) => {
|
|
419
|
+
this.setState({
|
|
420
|
+
leftOpenValue: nativeEvent.layout.width
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
onRightActionLayout = ({ nativeEvent }) => {
|
|
425
|
+
this.setState({
|
|
426
|
+
rightOpenValue: -nativeEvent.layout.width
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
renderHiddenContent = () => {
|
|
431
|
+
const {
|
|
432
|
+
actionBackground, rowIndex, rightAction, leftAction
|
|
433
|
+
} = this.props;
|
|
434
|
+
const hiddenRowStyle = {
|
|
435
|
+
...styles.standaloneRowBack,
|
|
436
|
+
...{ backgroundColor: actionBackground }
|
|
437
|
+
};
|
|
438
|
+
return (
|
|
439
|
+
<View style={hiddenRowStyle}>
|
|
440
|
+
{
|
|
441
|
+
this.state.isLeftActionVisible
|
|
442
|
+
&& (
|
|
443
|
+
<View style={styles.leftItemRow}>
|
|
444
|
+
<View style={{ flexDirection: 'row' }} onLayout={this.onLeftActionLayout}>
|
|
445
|
+
{
|
|
446
|
+
leftAction?.map?.((item, index) => this.renderLeftAction(item, index))
|
|
447
|
+
}
|
|
448
|
+
</View>
|
|
449
|
+
</View>
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
{
|
|
453
|
+
this.state.isRightActionVisible
|
|
454
|
+
&& (
|
|
455
|
+
<View style={styles.rightItemRow}>
|
|
456
|
+
<View style={{ flexDirection: 'row' }} onLayout={this.onRightActionLayout}>
|
|
457
|
+
{
|
|
458
|
+
rightAction?.slice?.(0)?.reverse().map((item, index) => this.renderRightAction(item, index))
|
|
459
|
+
}
|
|
460
|
+
</View>
|
|
461
|
+
</View>
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
</View>
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
renderIcon = (icon) => {
|
|
470
|
+
const { actionIconStyle } = this.props;
|
|
471
|
+
const iconSource = ValueUtil.getImageSource(icon);
|
|
472
|
+
return (
|
|
473
|
+
<Image
|
|
474
|
+
source={iconSource}
|
|
475
|
+
resizeMode="contain"
|
|
476
|
+
style={[styles.icon, actionIconStyle]}
|
|
477
|
+
/>
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
renderTitle = (title) => {
|
|
482
|
+
const { actionTextStyle } = this.props;
|
|
483
|
+
return (
|
|
484
|
+
<Text.SubTitle style={[styles.text, actionTextStyle]}>
|
|
485
|
+
{title}
|
|
486
|
+
</Text.SubTitle>
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
onActionPress = (item, rowIndex) => () => {
|
|
491
|
+
const { onPress } = item;
|
|
492
|
+
onPress?.(item, rowIndex);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
renderRightAction = (item, index) => {
|
|
496
|
+
const { rowIndex, renderRightAction } = this.props;
|
|
497
|
+
if (renderRightAction) {
|
|
498
|
+
return (
|
|
499
|
+
<View key={item + index}>
|
|
500
|
+
{renderRightAction({ item, index, rowIndex })}
|
|
501
|
+
</View>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
return (
|
|
505
|
+
<TouchableOpacity
|
|
506
|
+
key={index.toString()}
|
|
507
|
+
style={[
|
|
508
|
+
styles.buttonContainer,
|
|
509
|
+
{ backgroundColor: item.color, height: this.state.hiddenHeight }
|
|
510
|
+
]}
|
|
511
|
+
onPress={this.onActionPress(item, rowIndex)}
|
|
512
|
+
>
|
|
513
|
+
{item.icon && this.renderIcon(item.icon)}
|
|
514
|
+
{item.title && this.renderTitle(item.title)}
|
|
515
|
+
</TouchableOpacity>
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
renderLeftAction = (item, index) => {
|
|
520
|
+
const { rowIndex, renderLeftAction } = this.props;
|
|
521
|
+
if (renderLeftAction) {
|
|
522
|
+
return (
|
|
523
|
+
<View key={item + index}>
|
|
524
|
+
{renderLeftAction({ item, index, rowIndex })}
|
|
525
|
+
</View>
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
return (
|
|
529
|
+
<TouchableOpacity
|
|
530
|
+
key={index.toString()}
|
|
531
|
+
style={[
|
|
532
|
+
styles.buttonContainer,
|
|
533
|
+
{ backgroundColor: item.color, height: this.state.hiddenHeight }
|
|
534
|
+
]}
|
|
535
|
+
onPress={this.onActionPress(item, rowIndex)}
|
|
536
|
+
>
|
|
537
|
+
{item.icon && this.renderIcon(item.icon)}
|
|
538
|
+
{item.title && this.renderTitle(item.title)}
|
|
539
|
+
</TouchableOpacity>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
render() {
|
|
544
|
+
return (
|
|
545
|
+
<View style={this.props.style ? this.props.style : styles.container}>
|
|
546
|
+
<View style={[
|
|
547
|
+
styles.hidden,
|
|
548
|
+
{
|
|
549
|
+
height: this.state.hiddenHeight,
|
|
550
|
+
width: this.state.hiddenWidth,
|
|
551
|
+
}
|
|
552
|
+
]}
|
|
553
|
+
>
|
|
554
|
+
{this.renderHiddenContent()}
|
|
555
|
+
</View>
|
|
556
|
+
{this.renderRowContent()}
|
|
557
|
+
</View>
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const styles = StyleSheet.create({
|
|
563
|
+
container: {
|
|
564
|
+
// As of RN 0.29 flex: 1 is causing all rows to be the same height
|
|
565
|
+
// flex: 1
|
|
566
|
+
},
|
|
567
|
+
hidden: {
|
|
568
|
+
zIndex: 1,
|
|
569
|
+
bottom: 0,
|
|
570
|
+
left: 0,
|
|
571
|
+
overflow: 'hidden',
|
|
572
|
+
position: 'absolute',
|
|
573
|
+
right: 0,
|
|
574
|
+
top: 0,
|
|
575
|
+
},
|
|
576
|
+
standaloneRowBack: {
|
|
577
|
+
backgroundColor: Colors.white,
|
|
578
|
+
alignItems: 'center',
|
|
579
|
+
flex: 1,
|
|
580
|
+
flexDirection: 'row',
|
|
581
|
+
justifyContent: 'space-between'
|
|
582
|
+
},
|
|
583
|
+
leftItemRow: {
|
|
584
|
+
alignItems: 'center',
|
|
585
|
+
flex: 1,
|
|
586
|
+
flexDirection: 'row',
|
|
587
|
+
justifyContent: 'flex-start',
|
|
588
|
+
paddingRight: 10
|
|
589
|
+
},
|
|
590
|
+
rightItemRow: {
|
|
591
|
+
alignItems: 'center',
|
|
592
|
+
flex: 1,
|
|
593
|
+
flexDirection: 'row',
|
|
594
|
+
justifyContent: 'flex-end',
|
|
595
|
+
paddingLeft: 10,
|
|
596
|
+
},
|
|
597
|
+
buttonContainer: {
|
|
598
|
+
backgroundColor: 'red',
|
|
599
|
+
alignItems: 'center',
|
|
600
|
+
justifyContent: 'center',
|
|
601
|
+
width: 88
|
|
602
|
+
},
|
|
603
|
+
icon: {
|
|
604
|
+
height: 24,
|
|
605
|
+
width: 24,
|
|
606
|
+
tintColor: 'white'
|
|
607
|
+
},
|
|
608
|
+
text: {
|
|
609
|
+
color: Colors.white,
|
|
610
|
+
textAlign: 'center',
|
|
611
|
+
marginHorizontal: 10,
|
|
612
|
+
marginTop: 10
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
SwipeAction.propTypes = {
|
|
617
|
+
onOpen: PropTypes.func,
|
|
618
|
+
closeOnPress: PropTypes.bool,
|
|
619
|
+
disableRightAction: PropTypes.bool,
|
|
620
|
+
disableLeftAction: PropTypes.bool,
|
|
621
|
+
onClose: PropTypes.func,
|
|
622
|
+
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
623
|
+
leftAction: PropTypes.array,
|
|
624
|
+
rightAction: PropTypes.array,
|
|
625
|
+
renderRightAction: PropTypes.func,
|
|
626
|
+
renderLeftAction: PropTypes.func,
|
|
627
|
+
onPress: PropTypes.func,
|
|
628
|
+
children: PropTypes.element.isRequired,
|
|
629
|
+
actionBackground: PropTypes.string,
|
|
630
|
+
actionTextStyle: PropTypes.object,
|
|
631
|
+
swipeGestureBegan: PropTypes.func,
|
|
632
|
+
swipeGestureEnd: PropTypes.func,
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
SwipeAction.defaultProps = {
|
|
636
|
+
closeOnPress: true,
|
|
637
|
+
disableRightAction: true,
|
|
638
|
+
disableLeftAction: true,
|
|
639
|
+
recalculateHiddenLayout: false,
|
|
640
|
+
disableHiddenLayoutCalculation: false,
|
|
641
|
+
preview: false,
|
|
642
|
+
previewDuration: 300,
|
|
643
|
+
previewOpenDelay: DEFAULT_PREVIEW_OPEN_DELAY,
|
|
644
|
+
directionalDistanceChangeThreshold: 2,
|
|
645
|
+
swipeToOpenPercent: 50,
|
|
646
|
+
swipeToOpenVelocityContribution: 0,
|
|
647
|
+
swipeToClosePercent: 50,
|
|
648
|
+
swipeToPerformActionPercent: 50,
|
|
649
|
+
item: {},
|
|
650
|
+
useNativeDriver: true,
|
|
651
|
+
rightAction: [],
|
|
652
|
+
leftAction: [],
|
|
653
|
+
actionBackground: Colors.white
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
export default SwipeAction;
|