You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
488 lines
15 KiB
488 lines
15 KiB
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
|
|
|
var _reactTweenState = require('react-tween-state');
|
|
|
|
var _reactTweenState2 = _interopRequireDefault(_reactTweenState);
|
|
|
|
var _NativeButton = require('./NativeButton');
|
|
|
|
var _NativeButton2 = _interopRequireDefault(_NativeButton);
|
|
|
|
var _styles = require('./styles');
|
|
|
|
var _styles2 = _interopRequireDefault(_styles);
|
|
|
|
var _react = require('react');
|
|
|
|
var _react2 = _interopRequireDefault(_react);
|
|
|
|
var _propTypes = require('prop-types');
|
|
|
|
var _propTypes2 = _interopRequireDefault(_propTypes);
|
|
|
|
var _createReactClass = require('create-react-class');
|
|
|
|
var _createReactClass2 = _interopRequireDefault(_createReactClass);
|
|
|
|
var _reactNative = require('react-native');
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
var SwipeoutBtn = (0, _createReactClass2.default)({
|
|
displayName: 'SwipeoutBtn',
|
|
|
|
|
|
propTypes: {
|
|
backgroundColor: _propTypes2.default.string,
|
|
color: _propTypes2.default.string,
|
|
component: _propTypes2.default.node,
|
|
onPress: _propTypes2.default.func,
|
|
text: _propTypes2.default.node,
|
|
type: _propTypes2.default.string,
|
|
underlayColor: _propTypes2.default.string
|
|
},
|
|
|
|
getDefaultProps: function getDefaultProps() {
|
|
return {
|
|
backgroundColor: null,
|
|
color: null,
|
|
component: null,
|
|
underlayColor: null,
|
|
height: 0,
|
|
onPress: null,
|
|
disabled: false,
|
|
text: 'Click me',
|
|
type: '',
|
|
width: 0
|
|
};
|
|
},
|
|
|
|
render: function render() {
|
|
var btn = this.props;
|
|
|
|
var styleSwipeoutBtn = [_styles2.default.swipeoutBtn];
|
|
|
|
// apply "type" styles (delete || primary || secondary)
|
|
if (btn.type === 'delete') styleSwipeoutBtn.push(_styles2.default.colorDelete);else if (btn.type === 'primary') styleSwipeoutBtn.push(_styles2.default.colorPrimary);else if (btn.type === 'secondary') styleSwipeoutBtn.push(_styles2.default.colorSecondary);
|
|
|
|
// apply background color
|
|
if (btn.backgroundColor) styleSwipeoutBtn.push([{ backgroundColor: btn.backgroundColor }]);
|
|
|
|
styleSwipeoutBtn.push([{
|
|
height: btn.height,
|
|
width: btn.width
|
|
}]);
|
|
|
|
var styleSwipeoutBtnComponent = [];
|
|
|
|
// set button dimensions
|
|
styleSwipeoutBtnComponent.push([{
|
|
height: btn.height,
|
|
width: btn.width
|
|
}]);
|
|
|
|
var styleSwipeoutBtnText = [_styles2.default.swipeoutBtnText];
|
|
|
|
// apply text color
|
|
if (btn.color) styleSwipeoutBtnText.push({ color: btn.color });
|
|
|
|
return _react2.default.createElement(
|
|
_NativeButton2.default,
|
|
{
|
|
onPress: this.props.onPress,
|
|
underlayColor: this.props.underlayColor,
|
|
disabled: this.props.disabled,
|
|
style: [_styles2.default.swipeoutBtnTouchable, styleSwipeoutBtn],
|
|
textStyle: styleSwipeoutBtnText },
|
|
btn.component ? _react2.default.createElement(
|
|
_reactNative.View,
|
|
{ style: styleSwipeoutBtnComponent },
|
|
btn.component
|
|
) : btn.text
|
|
);
|
|
}
|
|
});
|
|
|
|
var Swipeout = (0, _createReactClass2.default)({
|
|
displayName: 'Swipeout',
|
|
|
|
mixins: [_reactTweenState2.default.Mixin],
|
|
|
|
propTypes: {
|
|
autoClose: _propTypes2.default.bool,
|
|
backgroundColor: _propTypes2.default.string,
|
|
close: _propTypes2.default.bool,
|
|
left: _propTypes2.default.array,
|
|
onOpen: _propTypes2.default.func,
|
|
onClose: _propTypes2.default.func,
|
|
right: _propTypes2.default.array,
|
|
scroll: _propTypes2.default.func,
|
|
style: (_reactNative.ViewPropTypes || _reactNative.View.propTypes).style,
|
|
sensitivity: _propTypes2.default.number,
|
|
buttonWidth: _propTypes2.default.number,
|
|
disabled: _propTypes2.default.bool
|
|
},
|
|
|
|
getDefaultProps: function getDefaultProps() {
|
|
return {
|
|
disabled: false,
|
|
rowID: -1,
|
|
sectionID: -1,
|
|
sensitivity: 50
|
|
};
|
|
},
|
|
|
|
getInitialState: function getInitialState() {
|
|
return {
|
|
autoClose: this.props.autoClose || false,
|
|
btnWidth: 0,
|
|
btnsLeftWidth: 0,
|
|
btnsRightWidth: 0,
|
|
contentHeight: 0,
|
|
contentPos: 0,
|
|
contentWidth: 0,
|
|
openedRight: false,
|
|
swiping: false,
|
|
tweenDuration: 160,
|
|
timeStart: null
|
|
};
|
|
},
|
|
|
|
componentWillMount: function componentWillMount() {
|
|
var _this = this;
|
|
|
|
this._panResponder = _reactNative.PanResponder.create({
|
|
onStartShouldSetPanResponder: function onStartShouldSetPanResponder(event, gestureState) {
|
|
return true;
|
|
},
|
|
onStartShouldSetPanResponderCapture: function onStartShouldSetPanResponderCapture(event, gestureState) {
|
|
return _this.state.openedLeft || _this.state.openedRight;
|
|
},
|
|
onMoveShouldSetPanResponderCapture: function onMoveShouldSetPanResponderCapture(event, gestureState) {
|
|
return Math.abs(gestureState.dx) > _this.props.sensitivity && Math.abs(gestureState.dy) <= _this.props.sensitivity;
|
|
},
|
|
onPanResponderGrant: this._handlePanResponderGrant,
|
|
onPanResponderMove: this._handlePanResponderMove,
|
|
onPanResponderRelease: this._handlePanResponderEnd,
|
|
onPanResponderTerminate: this._handlePanResponderEnd,
|
|
onShouldBlockNativeResponder: function onShouldBlockNativeResponder(event, gestureState) {
|
|
return false;
|
|
},
|
|
onPanResponderTerminationRequest: function onPanResponderTerminationRequest() {
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
|
|
if (nextProps.close) this._close();
|
|
if (nextProps.openRight) this._openRight();
|
|
if (nextProps.openLeft) this._openLeft();
|
|
},
|
|
|
|
_handlePanResponderGrant: function _handlePanResponderGrant(e, gestureState) {
|
|
var _this2 = this;
|
|
|
|
if (this.props.disabled) return;
|
|
if (!this.state.openedLeft && !this.state.openedRight) {
|
|
this._callOnOpen();
|
|
} else {
|
|
this._callOnClose();
|
|
}
|
|
this.refs.swipeoutContent.measure(function (ox, oy, width, height) {
|
|
var buttonWidth = _this2.props.buttonWidth || width / 5;
|
|
_this2.setState({
|
|
btnWidth: buttonWidth,
|
|
btnsLeftWidth: _this2.props.left ? buttonWidth * _this2.props.left.length : 0,
|
|
btnsRightWidth: _this2.props.right ? buttonWidth * _this2.props.right.length : 0,
|
|
swiping: true,
|
|
timeStart: new Date().getTime()
|
|
});
|
|
});
|
|
},
|
|
|
|
_handlePanResponderMove: function _handlePanResponderMove(e, gestureState) {
|
|
if (this.props.disabled) return;
|
|
var posX = gestureState.dx;
|
|
var posY = gestureState.dy;
|
|
var leftWidth = this.state.btnsLeftWidth;
|
|
var rightWidth = this.state.btnsRightWidth;
|
|
if (this.state.openedRight) var posX = gestureState.dx - rightWidth;else if (this.state.openedLeft) var posX = gestureState.dx + leftWidth;
|
|
|
|
// prevent scroll if moveX is true
|
|
var moveX = Math.abs(posX) > Math.abs(posY);
|
|
if (this.props.scroll) {
|
|
if (moveX) this.props.scroll(false);else this.props.scroll(true);
|
|
}
|
|
if (this.state.swiping) {
|
|
// move content to reveal swipeout
|
|
if (posX < 0 && this.props.right) {
|
|
this.setState({ contentPos: Math.min(posX, 0) });
|
|
} else if (posX > 0 && this.props.left) {
|
|
this.setState({ contentPos: Math.max(posX, 0) });
|
|
};
|
|
}
|
|
},
|
|
|
|
_handlePanResponderEnd: function _handlePanResponderEnd(e, gestureState) {
|
|
if (this.props.disabled) return;
|
|
var posX = gestureState.dx;
|
|
var contentPos = this.state.contentPos;
|
|
var contentWidth = this.state.contentWidth;
|
|
var btnsLeftWidth = this.state.btnsLeftWidth;
|
|
var btnsRightWidth = this.state.btnsRightWidth;
|
|
|
|
// minimum threshold to open swipeout
|
|
var openX = contentWidth * 0.33;
|
|
|
|
// should open swipeout
|
|
var openLeft = posX > openX || posX > btnsLeftWidth / 2;
|
|
var openRight = posX < -openX || posX < -btnsRightWidth / 2;
|
|
|
|
// account for open swipeouts
|
|
if (this.state.openedRight) var openRight = posX - openX < -openX;
|
|
if (this.state.openedLeft) var openLeft = posX + openX > openX;
|
|
|
|
// reveal swipeout on quick swipe
|
|
var timeDiff = new Date().getTime() - this.state.timeStart < 200;
|
|
if (timeDiff) {
|
|
var openRight = posX < -openX / 10 && !this.state.openedLeft;
|
|
var openLeft = posX > openX / 10 && !this.state.openedRight;
|
|
}
|
|
|
|
if (this.state.swiping) {
|
|
if (openRight && contentPos < 0 && posX < 0) {
|
|
this._open(-btnsRightWidth, 'right');
|
|
} else if (openLeft && contentPos > 0 && posX > 0) {
|
|
this._open(btnsLeftWidth, 'left');
|
|
} else {
|
|
this._close();
|
|
}
|
|
}
|
|
|
|
// Allow scroll
|
|
if (this.props.scroll) this.props.scroll(true);
|
|
},
|
|
|
|
_tweenContent: function _tweenContent(state, endValue) {
|
|
this.tweenState(state, {
|
|
easing: _reactTweenState2.default.easingTypes.easeInOutQuad,
|
|
duration: endValue === 0 ? this.state.tweenDuration * 1.5 : this.state.tweenDuration,
|
|
endValue: endValue
|
|
});
|
|
},
|
|
|
|
_rubberBandEasing: function _rubberBandEasing(value, limit) {
|
|
if (value < 0 && value < limit) return limit - Math.pow(limit - value, 0.85);else if (value > 0 && value > limit) return limit + Math.pow(value - limit, 0.85);
|
|
return value;
|
|
},
|
|
|
|
// close swipeout on button press
|
|
_autoClose: function _autoClose(btn) {
|
|
if (this.state.autoClose) this._close();
|
|
var onPress = btn.onPress;
|
|
if (onPress) onPress();
|
|
},
|
|
|
|
_open: function _open(contentPos, direction) {
|
|
var left = direction === 'left';
|
|
var _props = this.props,
|
|
sectionID = _props.sectionID,
|
|
rowID = _props.rowID,
|
|
onOpen = _props.onOpen;
|
|
|
|
onOpen && onOpen(sectionID, rowID, direction);
|
|
this._tweenContent('contentPos', contentPos);
|
|
this.setState({
|
|
contentPos: contentPos,
|
|
openedLeft: left,
|
|
openedRight: !left,
|
|
swiping: false
|
|
});
|
|
},
|
|
|
|
_close: function _close() {
|
|
var _props2 = this.props,
|
|
sectionID = _props2.sectionID,
|
|
rowID = _props2.rowID,
|
|
onClose = _props2.onClose;
|
|
|
|
if (onClose && (this.state.openedLeft || this.state.openedRight)) {
|
|
var direction = this.state.openedRight ? 'right' : 'left';
|
|
onClose(sectionID, rowID, direction);
|
|
}
|
|
this._tweenContent('contentPos', 0);
|
|
this._callOnClose();
|
|
this.setState({
|
|
openedRight: false,
|
|
openedLeft: false,
|
|
swiping: false
|
|
});
|
|
},
|
|
|
|
_callOnClose: function _callOnClose() {
|
|
if (this.props.onClose) this.props.onClose(this.props.sectionID, this.props.rowID);
|
|
},
|
|
|
|
_callOnOpen: function _callOnOpen() {
|
|
if (this.props.onOpen) this.props.onOpen(this.props.sectionID, this.props.rowID);
|
|
},
|
|
|
|
_openRight: function _openRight() {
|
|
var _this3 = this;
|
|
|
|
this.refs.swipeoutContent.measure(function (ox, oy, width, height) {
|
|
var btnWidth = _this3.props.buttonWidth || width / 5;
|
|
|
|
_this3.setState({
|
|
btnWidth: btnWidth,
|
|
btnsRightWidth: _this3.props.right ? btnWidth * _this3.props.right.length : 0
|
|
}, function () {
|
|
_this3._tweenContent('contentPos', -_this3.state.btnsRightWidth);
|
|
_this3._callOnOpen();
|
|
_this3.setState({
|
|
contentPos: -_this3.state.btnsRightWidth,
|
|
openedLeft: false,
|
|
openedRight: true,
|
|
swiping: false
|
|
});
|
|
});
|
|
});
|
|
},
|
|
|
|
_openLeft: function _openLeft() {
|
|
var _this4 = this;
|
|
|
|
this.refs.swipeoutContent.measure(function (ox, oy, width, height) {
|
|
var btnWidth = _this4.props.buttonWidth || width / 5;
|
|
|
|
_this4.setState({
|
|
btnWidth: btnWidth,
|
|
btnsLeftWidth: _this4.props.left ? btnWidth * _this4.props.left.length : 0
|
|
}, function () {
|
|
_this4._tweenContent('contentPos', _this4.state.btnsLeftWidth);
|
|
_this4._callOnOpen();
|
|
_this4.setState({
|
|
contentPos: _this4.state.btnsLeftWidth,
|
|
openedLeft: true,
|
|
openedRight: false,
|
|
swiping: false
|
|
});
|
|
});
|
|
});
|
|
},
|
|
|
|
render: function render() {
|
|
var contentWidth = this.state.contentWidth;
|
|
var posX = this.getTweeningValue('contentPos');
|
|
|
|
var styleSwipeout = [_styles2.default.swipeout, this.props.style];
|
|
if (this.props.backgroundColor) {
|
|
styleSwipeout.push([{ backgroundColor: this.props.backgroundColor }]);
|
|
}
|
|
|
|
var limit = -this.state.btnsRightWidth;
|
|
if (posX > 0) var limit = this.state.btnsLeftWidth;
|
|
|
|
var styleLeftPos = {
|
|
left: {
|
|
left: 0,
|
|
overflow: 'hidden',
|
|
width: Math.min(limit * (posX / limit), limit)
|
|
}
|
|
};
|
|
var styleRightPos = {
|
|
right: {
|
|
left: Math.abs(contentWidth + Math.max(limit, posX)),
|
|
right: 0
|
|
}
|
|
};
|
|
var styleContentPos = {
|
|
content: {
|
|
transform: [{ translateX: this._rubberBandEasing(posX, limit) }]
|
|
}
|
|
};
|
|
|
|
var styleContent = [_styles2.default.swipeoutContent];
|
|
styleContent.push(styleContentPos.content);
|
|
|
|
var styleRight = [_styles2.default.swipeoutBtns];
|
|
styleRight.push(styleRightPos.right);
|
|
|
|
var styleLeft = [_styles2.default.swipeoutBtns];
|
|
styleLeft.push(styleLeftPos.left);
|
|
|
|
var isRightVisible = posX < 0;
|
|
var isLeftVisible = posX > 0;
|
|
|
|
return _react2.default.createElement(
|
|
_reactNative.View,
|
|
{ style: styleSwipeout },
|
|
_react2.default.createElement(
|
|
_reactNative.View,
|
|
_extends({
|
|
ref: 'swipeoutContent',
|
|
style: styleContent,
|
|
onLayout: this._onLayout
|
|
}, this._panResponder.panHandlers),
|
|
this.props.children
|
|
),
|
|
this._renderButtons(this.props.right, isRightVisible, styleRight),
|
|
this._renderButtons(this.props.left, isLeftVisible, styleLeft)
|
|
);
|
|
},
|
|
|
|
_onLayout: function _onLayout(event) {
|
|
var _event$nativeEvent$la = event.nativeEvent.layout,
|
|
width = _event$nativeEvent$la.width,
|
|
height = _event$nativeEvent$la.height;
|
|
|
|
this.setState({
|
|
contentWidth: width,
|
|
contentHeight: height
|
|
});
|
|
},
|
|
|
|
_renderButtons: function _renderButtons(buttons, isVisible, style) {
|
|
if (buttons && isVisible) {
|
|
return _react2.default.createElement(
|
|
_reactNative.View,
|
|
{ style: style },
|
|
buttons.map(this._renderButton)
|
|
);
|
|
} else {
|
|
return _react2.default.createElement(_reactNative.View, null);
|
|
}
|
|
},
|
|
|
|
_renderButton: function _renderButton(btn, i) {
|
|
var _this5 = this;
|
|
|
|
return _react2.default.createElement(SwipeoutBtn, {
|
|
backgroundColor: btn.backgroundColor,
|
|
color: btn.color,
|
|
component: btn.component,
|
|
disabled: btn.disabled,
|
|
height: this.state.contentHeight,
|
|
key: i,
|
|
onPress: function onPress() {
|
|
return _this5._autoClose(btn);
|
|
},
|
|
text: btn.text,
|
|
type: btn.type,
|
|
underlayColor: btn.underlayColor,
|
|
width: this.state.btnWidth
|
|
});
|
|
}
|
|
});
|
|
|
|
Swipeout.NativeButton = _NativeButton2.default;
|
|
Swipeout.SwipeoutButton = SwipeoutBtn;
|
|
|
|
exports.default = Swipeout; |