diff --git a/.gitignore b/.gitignore index f8e01ab..5836df1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ npm-debug.log* node_modules lib +.idea/ diff --git a/README.md b/README.md index fd52b92..e99923e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # React Native Swipeable [![NPM version][npm-image]][npm-url] -A powerful React Native swipe component. Supports both iOS and Android. +A powerful React Native swipe component. Supports both iOS and Android. ## Installation ```sh -npm i --save react-native-swipeable +npm i --save react-native-swipeable-row ``` ## Usage @@ -15,7 +15,7 @@ npm i --save react-native-swipeable Wrap your ListView/TableView items with the `Swipeable` component: ```javascript -import Swipeable from 'react-native-swipeable'; +import Swipeable from 'react-native-swipeable-row'; const leftContent = Pull to activate; @@ -50,6 +50,8 @@ function MyListItem() { | `rightButtonWidth` | integer | 75 | (optional) resting visible peek of each right button after buttons are swiped open | | `onRef` | function | `null` | (optional) receive swipeable component instance reference | | `onPanAnimatedValueRef` | function | `null` | (optional) receive swipeable pan `Animated.ValueXY` reference for upstream animations | +| `bounceOnMount` | boolean | `false` | (optional) To alert the user that swiping is possible | +| `disable` | boolean | `false` | (optional) Disable swiping | ### Advanced Props @@ -80,6 +82,14 @@ class MyListItem extends Component { } ``` +#### bounceRight(onDone) + +Bounce the right component to alert swiping is possible. `onDone` is an optional callback. + +#### bounceLeft(onDone) + +Bounce the left component to alert swiping is possible. `onDone` is an optional callback. + ## Example To run [the example](https://github.com/jshanson7/react-native-swipeable/blob/master/example/swipeable-example.js): @@ -125,4 +135,4 @@ or: MIT [npm-image]: https://badge.fury.io/js/react-native-swipeable.svg -[npm-url]: https://npmjs.org/package/react-native-swipeable +[npm-url]: https://npmjs.org/package/react-native-swipeable-row diff --git a/example/swipeable-example.js b/example/swipeable-example.js index fbaafaa..406a9e9 100644 --- a/example/swipeable-example.js +++ b/example/swipeable-example.js @@ -57,6 +57,8 @@ function Example1({onOpen, onClose}) { ]} onRightButtonsOpenRelease={onOpen} onRightButtonsCloseRelease={onClose} + swipeStartMinLeftEdgeClearance={10} + swipeStartMinRightEdgeClearance={10} > Example 1 @@ -96,6 +98,8 @@ function Example2({onOpen, onClose}) { )} onLeftButtonsOpenRelease={onOpen} onLeftButtonsCloseRelease={onClose} + swipeStartMinLeftEdgeClearance={10} + swipeStartMinRightEdgeClearance={10} > Example 2 @@ -127,6 +131,7 @@ class Example3 extends Component { onLeftActionActivate={() => this.setState({leftActionActivated: true})} onLeftActionDeactivate={() => this.setState({leftActionActivated: false})} onLeftActionComplete={() => this.setState({toggle: !toggle})} + swipeStartMinLeftEdgeClearance={10} > Example 3 diff --git a/package.json b/package.json index cb0e27d..701a6fe 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "react-native-swipeable", - "version": "0.6.0", - "description": "A powerful React Native swipe component", + "name": "react-native-swipeable-row", + "version": "0.8.1", + "description": "A powerful React Native swipe component based on @jshanson7 package", "main": "lib/index.js", "scripts": { "build": "make build", "lint": "make lint" }, - "author": "Jeff Hanson", + "author": "MÃ¥rten Cederman", "license": "MIT", "devDependencies": { "babel-cli": "^6.18.0", @@ -28,7 +28,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/jshanson7/react-native-swipeable.git" + "url": "git+https://github.com/Cederman/react-native-swipeable" }, "keywords": [ "react", diff --git a/src/index.js b/src/index.js index d77cf98..244bf99 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-unresolved, import/extensions */ import React, {PureComponent} from 'react'; -import {Animated, Easing, PanResponder, StyleSheet, View, ViewPropTypes} from 'react-native'; +import {Animated, Dimensions, Easing, PanResponder, StyleSheet, View, ViewPropTypes} from 'react-native'; import {PropTypes} from 'prop-types'; /* eslint-enable import/no-unresolved, import/extensions */ @@ -74,6 +74,9 @@ export default class Swipeable extends PureComponent { onRef: PropTypes.func, onPanAnimatedValueRef: PropTypes.func, swipeStartMinDistance: PropTypes.number, + swipeStartMinLeftEdgeClearance: PropTypes.number, + swipeStartMinRightEdgeClearance: PropTypes.number, + disable: PropTypes.bool, // styles style: ViewPropTypes.style, @@ -151,7 +154,11 @@ export default class Swipeable extends PureComponent { // misc onRef: noop, onPanAnimatedValueRef: noop, - swipeStartMinDistance: 15 + swipeStartMinDistance: 15, + swipeStartMinLeftEdgeClearance: 0, + swipeStartMinRightEdgeClearance: 0, + bounceOnMount: false, + disable: false, }; state = { @@ -173,6 +180,12 @@ export default class Swipeable extends PureComponent { onPanAnimatedValueRef(this.state.pan); } + componentDidMount() { + if (this.props.bounceOnMount) { + setTimeout(this._bounceOnMount, 700); + } + } + componentWillUnmount() { this._unmounted = true; } @@ -199,6 +212,48 @@ export default class Swipeable extends PureComponent { animationFn(pan, animationConfig).start(onDone); }; + _bounceOnMount = () => { + if (this._canSwipeLeft()) { + this.bounceRight(this.bounceLeft); + } else if (this._canSwipeRight()) { + this.bounceLeft(); + } + }; + + bounceRight = (onDone) => { + if (this._canSwipeLeft()) { + this.setState({ + rightActionActivated: true, + rightButtonsActivated: true, + rightButtonsOpen: true + }); + this._bounce({x: -50, y: 0}, onDone); + } + }; + + bounceLeft = (onDone) => { + if (this._canSwipeRight()) { + this.setState({ + leftActionActivated: true, + leftButtonsActivated: true, + leftButtonsOpen: true + }); + this._bounce({x: 50, y: 0}, onDone); + } + }; + + _bounce = (toValue, onDone) => { + const {pan} = this.state; + pan.flattenOffset(); + + const {swipeReleaseAnimationFn, swipeReleaseAnimationConfig} = this.props; + Animated.timing(pan, { + toValue, + duration: 250, + easing: Easing.elastic(0.5) + }).start(() => this.recenter(swipeReleaseAnimationFn, swipeReleaseAnimationConfig, () => onDone && onDone())); + }; + _unmounted = false; _handlePan = Animated.event([null, { @@ -206,11 +261,21 @@ export default class Swipeable extends PureComponent { dy: this.state.pan.y }]); - _handleMoveShouldSetPanResponder = (event, gestureState) => ( - Math.abs(gestureState.dx) > this.props.swipeStartMinDistance - ); + _handleMoveShouldSetPanResponder = (event, gestureState) => { + const {swipeStartMinDistance, swipeStartMinLeftEdgeClearance, swipeStartMinRightEdgeClearance} = this.props; + const gestureStartX = gestureState.moveX - gestureState.dx; + return Math.abs(gestureState.dx) > swipeStartMinDistance + && (swipeStartMinLeftEdgeClearance === 0 + || gestureStartX >= swipeStartMinLeftEdgeClearance) + && (swipeStartMinRightEdgeClearance === 0 + || gestureStartX <= Dimensions.get('window').width - swipeStartMinRightEdgeClearance); + }; _handlePanResponderStart = (event, gestureState) => { + if (this.props.disable) { + return; + } + const {lastOffset, pan} = this.state; pan.setOffset(lastOffset); @@ -218,6 +283,10 @@ export default class Swipeable extends PureComponent { }; _handlePanResponderMove = (event, gestureState) => { + if (this.props.disable) { + return; + } + const { leftActionActivationDistance, leftButtonsActivationDistance, @@ -313,6 +382,10 @@ export default class Swipeable extends PureComponent { }; _handlePanResponderEnd = (event, gestureState) => { + if (this.props.disable) { + return; + } + const { onLeftActionRelease, onLeftActionDeactivate,