react-native-swipe-up-panel
Version:
Swipeable bottom panel for react native
394 lines (350 loc) • 12.5 kB
JavaScript
var React = require('react');
var reactNative = require('react-native');
function _extends() {
_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;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
var Bar = function Bar(_ref) {
var barStyle = _ref.barStyle;
return /*#__PURE__*/React.createElement(reactNative.View, {
style: BarStyles.barContainer
}, /*#__PURE__*/React.createElement(reactNative.View, {
style: [BarStyles.bar, barStyle]
}));
};
var BarStyles = reactNative.StyleSheet.create({
barContainer: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
},
bar: {
width: '10%',
height: 5,
borderRadius: 5,
marginTop: 10,
marginBottom: 10,
backgroundColor: '#e2e2e2'
}
});
var Close = function Close(_ref) {
var onPress = _ref.onPress,
rootStyle = _ref.rootStyle,
iconStyle = _ref.iconStyle;
return /*#__PURE__*/React.createElement(reactNative.TouchableOpacity, {
activeOpacity: 0.5,
onPress: onPress,
style: [CloseStyles.closeButton, rootStyle]
}, /*#__PURE__*/React.createElement(reactNative.View, {
style: [CloseStyles.iconLine, iconStyle, {
transform: [{
rotateZ: '45deg'
}]
}]
}), /*#__PURE__*/React.createElement(reactNative.View, {
style: [CloseStyles.iconLine, iconStyle, {
transform: [{
rotateZ: '135deg'
}]
}]
}));
};
var CloseStyles = reactNative.StyleSheet.create({
closeButton: {
width: 30,
height: 30,
borderRadius: 15,
position: 'absolute',
right: 15,
top: 15,
backgroundColor: '#e2e2e2',
zIndex: 3,
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
},
iconLine: {
position: 'absolute',
width: 18,
height: 2,
borderRadius: 2,
backgroundColor: 'white'
}
});
var FULL_HEIGHT = reactNative.Dimensions.get('window').height;
var FULL_WIDTH = reactNative.Dimensions.get('window').width;
var PANEL_HEIGHT = FULL_HEIGHT - 100;
var STATUS;
(function (STATUS) {
STATUS[STATUS["CLOSED"] = 0] = "CLOSED";
STATUS[STATUS["SMALL"] = 1] = "SMALL";
STATUS[STATUS["LARGE"] = 2] = "LARGE";
})(STATUS || (STATUS = {}));
var SwipeablePanel = /*#__PURE__*/function (_React$Component) {
_inheritsLoose(SwipeablePanel, _React$Component);
function SwipeablePanel(props) {
var _this;
_this = _React$Component.call(this, props) || this;
_this.SMALL_PANEL_CONTENT_HEIGHT = PANEL_HEIGHT - (FULL_HEIGHT - 400) - 25;
_this.LARGE_PANEL_CONTENT_HEIGHT = PANEL_HEIGHT - 25;
_this.componentDidMount = function () {
var _this$props = _this.props,
isActive = _this$props.isActive,
openLarge = _this$props.openLarge,
onlyLarge = _this$props.onlyLarge,
onlySmall = _this$props.onlySmall;
_this.animatedValueY = 0;
_this.state.pan.y.addListener(function (value) {
return _this.animatedValueY = value.value;
});
_this.setState({
isActive: isActive
});
if (isActive) _this._animateTo(onlySmall ? STATUS.SMALL : openLarge ? STATUS.LARGE : onlyLarge ? STATUS.LARGE : STATUS.SMALL);
reactNative.Dimensions.addEventListener('change', _this._onOrientationChange);
};
_this._onOrientationChange = function () {
var dimesions = reactNative.Dimensions.get('screen');
FULL_HEIGHT = dimesions.height;
FULL_WIDTH = dimesions.width;
PANEL_HEIGHT = FULL_HEIGHT - 100;
_this.setState({
orientation: dimesions.height >= dimesions.width ? 'portrait' : 'landscape',
deviceWidth: FULL_WIDTH,
deviceHeight: FULL_HEIGHT,
panelHeight: PANEL_HEIGHT
});
if (_this.props.onClose) _this.props.onClose();
};
_this._animateTo = function (newStatus) {
if (newStatus === void 0) {
newStatus = 0;
}
var newY = 0;
if (_this.props.canClose && newStatus === STATUS.CLOSED) {
newY = PANEL_HEIGHT;
} else if (newStatus === STATUS.SMALL) {
newY = _this.props.smallPanelHeight ? FULL_HEIGHT - _this.props.smallPanelHeight : _this.state.orientation === 'portrait' ? FULL_HEIGHT - 400 : FULL_HEIGHT / 3;
} else if (newStatus === STATUS.LARGE) {
newY = _this.props.largePanelHeight ? FULL_HEIGHT - _this.props.largePanelHeight : 0;
}
_this.setState({
showComponent: true,
status: newStatus,
currentHeight: PANEL_HEIGHT - newY
});
reactNative.Animated.spring(_this.state.pan, {
toValue: {
x: 0,
y: newY
},
tension: 40,
friction: 25,
useNativeDriver: true,
restDisplacementThreshold: 10,
restSpeedThreshold: 10
}).start(function () {
var _this$props$onChangeS, _this$props2;
(_this$props$onChangeS = (_this$props2 = _this.props).onChangeStatus) === null || _this$props$onChangeS === void 0 ? void 0 : _this$props$onChangeS.call(_this$props2, newStatus);
if (newStatus === 0) {
if (_this.props.onClose) _this.props.onClose();
_this.setState({
showComponent: false
});
} else {
_this.setState({
canScroll: newStatus === STATUS.LARGE
});
}
});
};
_this.state = {
status: STATUS.CLOSED,
isActive: false,
showComponent: false,
canScroll: false,
opacity: new reactNative.Animated.Value(0),
pan: new reactNative.Animated.ValueXY({
x: 0,
y: FULL_HEIGHT
}),
orientation: FULL_HEIGHT >= FULL_WIDTH ? 'portrait' : 'landscape',
deviceWidth: FULL_WIDTH,
deviceHeight: FULL_HEIGHT,
panelHeight: PANEL_HEIGHT,
currentHeight: _this.props.smallPanelHeight ? FULL_HEIGHT - _this.props.smallPanelHeight : _this.state.orientation === 'portrait' ? FULL_HEIGHT - 400 : FULL_HEIGHT / 3
};
_this.pan = new reactNative.Animated.ValueXY({
x: 0,
y: FULL_HEIGHT
});
_this.isClosing = false;
_this.animatedValueY = 0;
_this._panResponder = reactNative.PanResponder.create({
onStartShouldSetPanResponder: function onStartShouldSetPanResponder() {
return true;
},
onPanResponderGrant: function onPanResponderGrant() {
_this.state.pan.setOffset({
x: 0,
y: _this.animatedValueY
});
_this.state.pan.setValue({
x: 0,
y: 0
});
},
onPanResponderMove: function onPanResponderMove(evt, gestureState) {
if (_this.state.status === STATUS.SMALL && Math.abs(_this.state.pan.y._value) <= _this.state.pan.y._offset || _this.state.status === STATUS.LARGE && _this.state.pan.y._value > -1) _this.state.pan.setValue({
x: 0,
y: _this.state.status === STATUS.LARGE ? Math.max(0, gestureState.dy) : gestureState.dy
});
},
onPanResponderRelease: function onPanResponderRelease(evt, gestureState) {
var _this$props3 = _this.props,
onlyLarge = _this$props3.onlyLarge,
onlySmall = _this$props3.onlySmall;
_this.state.pan.flattenOffset();
if (gestureState.dy === 0) {
_this._animateTo(_this.state.status);
} else if (gestureState.dy < -100 || gestureState.vy < -0.5) {
if (_this.state.status === STATUS.SMALL) _this._animateTo(onlySmall ? STATUS.SMALL : STATUS.LARGE);else _this._animateTo(STATUS.LARGE);
} else if (gestureState.dy > 100 || gestureState.vy > 0.5) {
if (_this.state.status === STATUS.LARGE) _this._animateTo(onlyLarge && _this.props.canClose ? STATUS.CLOSED : STATUS.SMALL);else _this._animateTo(_this.state.status);
} else {
_this._animateTo(_this.state.status);
}
}
});
return _this;
}
var _proto = SwipeablePanel.prototype;
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
var _this$props4 = this.props,
isActive = _this$props4.isActive,
openLarge = _this$props4.openLarge,
onlyLarge = _this$props4.onlyLarge,
onlySmall = _this$props4.onlySmall;
if (onlyLarge && onlySmall) console.warn('Ops. You are using both onlyLarge and onlySmall options. onlySmall will override the onlyLarge in this situation. Please select one of them or none.');
if (prevProps.isActive !== isActive) {
this.setState({
isActive: isActive
});
if (isActive) {
this._animateTo(onlySmall ? STATUS.SMALL : openLarge ? STATUS.LARGE : onlyLarge ? STATUS.LARGE : STATUS.SMALL);
} else {
this._animateTo();
}
}
if (prevState.orientation !== this.state.orientation) this._animateTo(this.state.status);
};
_proto.render = function render() {
var _this$state = this.state,
showComponent = _this$state.showComponent,
deviceWidth = _this$state.deviceWidth,
deviceHeight = _this$state.deviceHeight,
panelHeight = _this$state.panelHeight,
currentHeight = _this$state.currentHeight;
var _this$props5 = this.props,
noBackgroundOpacity = _this$props5.noBackgroundOpacity,
style = _this$props5.style,
barStyle = _this$props5.barStyle,
closeRootStyle = _this$props5.closeRootStyle,
closeIconStyle = _this$props5.closeIconStyle,
onClose = _this$props5.onClose,
allowTouchOutside = _this$props5.allowTouchOutside,
closeOnTouchOutside = _this$props5.closeOnTouchOutside;
return showComponent ? /*#__PURE__*/React.createElement(reactNative.Animated.View, {
style: [SwipeablePanelStyles.background, {
backgroundColor: noBackgroundOpacity ? 'rgba(0,0,0,0)' : 'rgba(0,0,0,0.5)',
height: allowTouchOutside ? currentHeight : deviceHeight,
width: deviceWidth
}]
}, closeOnTouchOutside && /*#__PURE__*/React.createElement(reactNative.TouchableWithoutFeedback, {
onPress: onClose
}, /*#__PURE__*/React.createElement(reactNative.View, {
style: [SwipeablePanelStyles.background, {
width: deviceWidth,
backgroundColor: 'rgba(0,0,0,0)',
height: allowTouchOutside ? currentHeight : deviceHeight
}]
})), /*#__PURE__*/React.createElement(reactNative.Animated.View, _extends({
style: [SwipeablePanelStyles.panel, {
width: this.props.fullWidth ? deviceWidth : deviceWidth - 50,
height: panelHeight
}, {
transform: this.state.pan.getTranslateTransform()
}, style]
}, this._panResponder.panHandlers), !this.props.noBar && /*#__PURE__*/React.createElement(Bar, {
barStyle: barStyle
}), this.props.showCloseButton && /*#__PURE__*/React.createElement(Close, {
rootStyle: closeRootStyle,
iconStyle: closeIconStyle,
onPress: this.props.onClose
}), this.props.children)) : null;
};
return SwipeablePanel;
}(React.Component);
var SwipeablePanelStyles = reactNative.StyleSheet.create({
background: {
position: 'absolute',
zIndex: 1,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.5)'
},
panel: {
position: 'absolute',
height: PANEL_HEIGHT,
width: FULL_WIDTH - 50,
transform: [{
translateY: FULL_HEIGHT - 100
}],
display: 'flex',
flexDirection: 'column',
backgroundColor: 'white',
bottom: 0,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
overflow: 'hidden',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 1
},
shadowOpacity: 0.18,
shadowRadius: 1.0,
elevation: 1,
zIndex: 2
},
scrollViewContentContainerStyle: {
width: '100%'
}
});
exports.SwipeablePanel = SwipeablePanel;
//# sourceMappingURL=index.js.map