diff --git a/README.md b/README.md index 85ca3c6..fe92981 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,10 @@ $ yarn add rn-swipeable-panel ## 🚀 How to use ```javascript -import React from "react"; -import { StyleSheet, Text, View } from "react-native"; +import React from 'react'; +import { StyleSheet, Text, View } from 'react-native'; -import SwipeablePanel from "rn-swipeable-panel"; +import { SwipeablePanel } from 'rn-swipeable-panel'; export default App = () => { const [panelProps, setPanelProps] = useState({ diff --git a/index.d.ts b/index.d.ts index f9ee51d..b303539 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,6 +5,9 @@ import * as React from 'react'; +declare var LARGE_PANEL_CONTENT_HEIGHT: number; +declare var SMALL_PANEL_CONTENT_HEIGHT: number; + declare interface SwipeablePanelProps extends React.Props { /** * Required prop for panels actual state. Set true if you want to open panel @@ -69,7 +72,7 @@ declare interface SwipeablePanelProps extends React.Props { /** * Use this prop to override bar style */ - barStyle: object; + barStyle?: object; /** * Set true if you want to make toucable outside of panel @@ -86,4 +89,4 @@ declare interface SwipeablePanelProps extends React.Props { declare class SwipeablePanel extends React.Component {} -export default SwipeablePanel; +export { SwipeablePanel, LARGE_PANEL_CONTENT_HEIGHT, SMALL_PANEL_CONTENT_HEIGHT }; diff --git a/package.json b/package.json index ba3849f..0cbf0d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-swipeable-panel", - "version": "1.1.12", + "version": "1.1.15", "description": "Swipeable bottom panel for react native", "author": "Enes Ozturk", "license": "MIT", @@ -9,6 +9,7 @@ "url": "https://github.com/enesozturk/rn-swipeable-panel" }, "main": "dist/index.js", + "types": "./index.d.ts", "module": "dist/index.modern.js", "source": "src/index.tsx", "engines": { diff --git a/rn-swipeable-panel-1.1.12.tgz b/rn-swipeable-panel-1.1.12.tgz deleted file mode 100644 index 5f09a09..0000000 Binary files a/rn-swipeable-panel-1.1.12.tgz and /dev/null differ diff --git a/rn-swipeable-panel-1.1.14.tgz b/rn-swipeable-panel-1.1.14.tgz new file mode 100644 index 0000000..398df9a Binary files /dev/null and b/rn-swipeable-panel-1.1.14.tgz differ diff --git a/src/Bar.tsx b/src/Bar.tsx index 4b1e497..046ee8e 100644 --- a/src/Bar.tsx +++ b/src/Bar.tsx @@ -1,23 +1,23 @@ -import * as React from 'react' -import { StyleSheet, View } from 'react-native' +import * as React from 'react'; +import { StyleSheet, View } from 'react-native'; type BarProps = { - barStyle?: object -} + barStyle?: object; +}; export const Bar = ({ barStyle }: BarProps) => { return ( - ) -} + ); +}; const BarStyles = StyleSheet.create({ barContainer: { display: 'flex', justifyContent: 'center', - alignItems: 'center' + alignItems: 'center', }, bar: { width: '10%', @@ -25,6 +25,6 @@ const BarStyles = StyleSheet.create({ borderRadius: 5, marginTop: 10, marginBottom: 10, - backgroundColor: '#e2e2e2' - } -}) + backgroundColor: '#e2e2e2', + }, +}); diff --git a/src/Close.tsx b/src/Close.tsx index cb2efd4..af3d128 100644 --- a/src/Close.tsx +++ b/src/Close.tsx @@ -1,36 +1,20 @@ -import * as React from 'react' -import { StyleSheet, TouchableOpacity, View } from 'react-native' +import * as React from 'react'; +import { StyleSheet, TouchableOpacity, View } from 'react-native'; type CloseProps = { - onPress: () => void - rootStyle?: object - iconStyle?: object -} + onPress: () => void; + rootStyle?: object; + iconStyle?: object; +}; export const Close = ({ onPress, rootStyle, iconStyle }: CloseProps) => { return ( - onPress()} - style={[CloseStyles.closeButton, rootStyle]} - > - - + onPress()} style={[CloseStyles.closeButton, rootStyle]}> + + - ) -} + ); +}; const CloseStyles = StyleSheet.create({ closeButton: { @@ -44,13 +28,13 @@ const CloseStyles = StyleSheet.create({ zIndex: 3, display: 'flex', justifyContent: 'center', - alignItems: 'center' + alignItems: 'center', }, iconLine: { position: 'absolute', width: 18, height: 2, borderRadius: 2, - backgroundColor: 'white' - } -}) + backgroundColor: 'white', + }, +}); diff --git a/src/Panel.tsx b/src/Panel.tsx index fecba48..2b635cf 100644 --- a/src/Panel.tsx +++ b/src/Panel.tsx @@ -1,4 +1,4 @@ -import * as React from 'react' +import * as React from 'react'; import { StyleSheet, ScrollView, @@ -7,65 +7,62 @@ import { TouchableWithoutFeedback, Animated, Dimensions, - PanResponder -} from 'react-native' + PanResponder, +} from 'react-native'; -import { Bar } from './Bar' -import { Close } from './Close' +import { Bar } from './Bar'; +import { Close } from './Close'; -let FULL_HEIGHT = Dimensions.get('window').height -let FULL_WIDTH = Dimensions.get('window').width -let PANEL_HEIGHT = FULL_HEIGHT - 100 +let FULL_HEIGHT = Dimensions.get('window').height; +let FULL_WIDTH = Dimensions.get('window').width; +let PANEL_HEIGHT = FULL_HEIGHT - 100; const STATUS = { CLOSED: 0, SMALL: 1, - LARGE: 2 -} + LARGE: 2, +}; type SwipeablePanelProps = { - isActive: boolean - onClose: () => void - showCloseButton?: boolean - fullWidth?: boolean - noBackgroundOpacity?: boolean - style?: object - closeRootStyle?: object - closeIconStyle?: object - closeOnTouchOutside?: boolean - onlyLarge?: boolean - onlySmall?: boolean - openLarge?: boolean - noBar?: boolean - barStyle: object - allowTouchOutside?: boolean -} + isActive: boolean; + onClose: () => void; + showCloseButton?: boolean; + fullWidth?: boolean; + noBackgroundOpacity?: boolean; + style?: object; + closeRootStyle?: object; + closeIconStyle?: object; + closeOnTouchOutside?: boolean; + onlyLarge?: boolean; + onlySmall?: boolean; + openLarge?: boolean; + noBar?: boolean; + barStyle?: object; + allowTouchOutside?: boolean; +}; -type MaybeAnimated = T | Animated.Value +type MaybeAnimated = T | Animated.Value; type SwipeablePanelState = { - status: number - isActive: boolean - showComponent: boolean - canScroll: boolean - opacity: Animated.Value - pan: any - orientation: 'portrait' | 'landscape' - deviceWidth: number - deviceHeight: number - panelHeight: number -} + status: number; + isActive: boolean; + showComponent: boolean; + canScroll: boolean; + opacity: Animated.Value; + pan: any; + orientation: 'portrait' | 'landscape'; + deviceWidth: number; + deviceHeight: number; + panelHeight: number; +}; -class SwipeablePanel extends React.Component< - SwipeablePanelProps, - SwipeablePanelState -> { - pan: Animated.ValueXY - isClosing: boolean - _panResponder: any - animatedValueY: number +class SwipeablePanel extends React.Component { + pan: Animated.ValueXY; + isClosing: boolean; + _panResponder: any; + animatedValueY: number; constructor(props: SwipeablePanelProps) { - super(props) + super(props); this.state = { status: STATUS.CLOSED, isActive: false, @@ -76,139 +73,110 @@ class SwipeablePanel extends React.Component< orientation: FULL_HEIGHT >= FULL_WIDTH ? 'portrait' : 'landscape', deviceWidth: FULL_WIDTH, deviceHeight: FULL_HEIGHT, - panelHeight: PANEL_HEIGHT - } + panelHeight: PANEL_HEIGHT, + }; - this.pan = new Animated.ValueXY({ x: 0, y: FULL_HEIGHT }) - this.isClosing = false - this.animatedValueY = 0 + this.pan = new Animated.ValueXY({ x: 0, y: FULL_HEIGHT }); + this.isClosing = false; + this.animatedValueY = 0; this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: (evt, gestureState) => true, onPanResponderGrant: (evt, gestureState) => { this.state.pan.setOffset({ x: 0, - y: this.animatedValueY - }) - this.state.pan.setValue({ x: 0, y: 0 }) + y: this.animatedValueY, + }); + this.state.pan.setValue({ x: 0, y: 0 }); }, onPanResponderMove: (evt, gestureState) => { if ( - (this.state.status === 1 && - Math.abs(this.state.pan.y._value) <= this.state.pan.y._offset) || + (this.state.status === 1 && Math.abs(this.state.pan.y._value) <= this.state.pan.y._offset) || (this.state.status === 2 && this.state.pan.y._value > -1) ) this.state.pan.setValue({ x: 0, - y: gestureState.dy - }) + y: gestureState.dy, + }); }, onPanResponderRelease: (evt, gestureState) => { - const { onlyLarge, onlySmall } = this.props - this.state.pan.flattenOffset() + const { onlyLarge, onlySmall } = this.props; + this.state.pan.flattenOffset(); - if (gestureState.dy === 0) this._animateTo(this.state.status) + 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) + 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 ? STATUS.CLOSED : STATUS.SMALL) - else this._animateTo(0) - } else this._animateTo(this.state.status) - } - }) + if (this.state.status === STATUS.LARGE) this._animateTo(onlyLarge ? STATUS.CLOSED : STATUS.SMALL); + else this._animateTo(0); + } else this._animateTo(this.state.status); + }, + }); } componentDidMount = () => { - const { isActive, openLarge, onlyLarge, onlySmall } = this.props + const { isActive, openLarge, onlyLarge, onlySmall } = this.props; - this.animatedValueY = 0 - this.state.pan.y.addListener( - (value: any) => (this.animatedValueY = value.value) - ) + this.animatedValueY = 0; + this.state.pan.y.addListener((value: any) => (this.animatedValueY = value.value)); - this.setState({ isActive }) + this.setState({ isActive }); if (isActive) - this._animateTo( - onlySmall - ? STATUS.SMALL - : openLarge - ? STATUS.LARGE - : onlyLarge - ? STATUS.LARGE - : STATUS.SMALL - ) + this._animateTo(onlySmall ? STATUS.SMALL : openLarge ? STATUS.LARGE : onlyLarge ? STATUS.LARGE : STATUS.SMALL); - Dimensions.addEventListener('change', this._onOrientationChange) - } + Dimensions.addEventListener('change', this._onOrientationChange); + }; _onOrientationChange = () => { - const dimesions = Dimensions.get('screen') - FULL_HEIGHT = dimesions.height - FULL_WIDTH = dimesions.width - PANEL_HEIGHT = FULL_HEIGHT - 100 + const dimesions = 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', + orientation: dimesions.height >= dimesions.width ? 'portrait' : 'landscape', deviceWidth: FULL_WIDTH, deviceHeight: FULL_HEIGHT, - panelHeight: PANEL_HEIGHT - }) + panelHeight: PANEL_HEIGHT, + }); - this.props.onClose() - } + this.props.onClose(); + }; - componentDidUpdate( - prevProps: SwipeablePanelProps, - prevState: SwipeablePanelState - ) { - const { isActive, openLarge, onlyLarge, onlySmall } = this.props + componentDidUpdate(prevProps: SwipeablePanelProps, prevState: SwipeablePanelState) { + const { isActive, openLarge, onlyLarge, onlySmall } = this.props; // 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 }) + this.setState({ isActive }); if (isActive) { - this._animateTo( - onlySmall - ? STATUS.SMALL - : openLarge - ? STATUS.LARGE - : onlyLarge - ? STATUS.LARGE - : STATUS.SMALL - ) + this._animateTo(onlySmall ? STATUS.SMALL : openLarge ? STATUS.LARGE : onlyLarge ? STATUS.LARGE : STATUS.SMALL); } else { - this._animateTo() + this._animateTo(); } } - if (prevState.orientation !== this.state.orientation) - this._animateTo(this.state.status) + if (prevState.orientation !== this.state.orientation) this._animateTo(this.state.status); } _animateTo = (newStatus = 0) => { - let newY = 0 + let newY = 0; - if (newStatus === STATUS.CLOSED) newY = PANEL_HEIGHT + if (newStatus === STATUS.CLOSED) newY = PANEL_HEIGHT; else if (newStatus === STATUS.SMALL) - newY = - this.state.orientation === 'portrait' - ? FULL_HEIGHT - 400 - : FULL_HEIGHT / 3 - else if (newStatus === STATUS.LARGE) newY = 0 + newY = this.state.orientation === 'portrait' ? FULL_HEIGHT - 400 : FULL_HEIGHT / 3; + else if (newStatus === STATUS.LARGE) newY = 0; this.setState({ showComponent: true, - status: newStatus - }) + status: newStatus, + }); Animated.spring(this.state.pan, { toValue: { x: 0, y: newY }, @@ -216,20 +184,19 @@ class SwipeablePanel extends React.Component< friction: 25, useNativeDriver: true, restDisplacementThreshold: 10, - restSpeedThreshold: 10 + restSpeedThreshold: 10, }).start(() => { if (newStatus === 0) { - this.props.onClose() + this.props.onClose(); this.setState({ - showComponent: false - }) - } else - this.setState({ canScroll: newStatus === STATUS.LARGE ? true : false }) - }) - } + showComponent: false, + }); + } else this.setState({ canScroll: newStatus === STATUS.LARGE ? true : false }); + }); + }; render() { - const { showComponent, deviceWidth, deviceHeight, panelHeight } = this.state + const { showComponent, deviceWidth, deviceHeight, panelHeight } = this.state; const { noBackgroundOpacity, style, @@ -238,20 +205,18 @@ class SwipeablePanel extends React.Component< closeIconStyle, onClose, allowTouchOutside, - closeOnTouchOutside - } = this.props + closeOnTouchOutside, + } = this.props; return showComponent ? ( {closeOnTouchOutside && ( @@ -262,8 +227,8 @@ class SwipeablePanel extends React.Component< { width: deviceWidth, backgroundColor: 'rgba(0,0,0,0)', - height: allowTouchOutside ? 'auto' : deviceHeight - } + height: allowTouchOutside ? 'auto' : deviceHeight, + }, ]} /> @@ -273,31 +238,25 @@ class SwipeablePanel extends React.Component< SwipeablePanelStyles.panel, { width: this.props.fullWidth ? deviceWidth : deviceWidth - 50, - height: panelHeight + height: panelHeight, }, { transform: this.state.pan.getTranslateTransform() }, - style + style, ]} {...this._panResponder.panHandlers} > {!this.props.noBar && } {this.props.showCloseButton && ( - + )} { - return false + return false; }} onTouchEnd={() => { - return false + return false; }} - contentContainerStyle={ - SwipeablePanelStyles.scrollViewContentContainerStyle - } + contentContainerStyle={SwipeablePanelStyles.scrollViewContentContainerStyle} > {this.state.canScroll ? ( @@ -309,7 +268,7 @@ class SwipeablePanel extends React.Component< - ) : null + ) : null; } } @@ -320,7 +279,7 @@ const SwipeablePanelStyles = StyleSheet.create({ bottom: 0, justifyContent: 'center', alignItems: 'center', - backgroundColor: 'rgba(0,0,0,0.5)' + backgroundColor: 'rgba(0,0,0,0.5)', }, panel: { position: 'absolute', @@ -339,19 +298,19 @@ const SwipeablePanelStyles = StyleSheet.create({ shadowColor: '#000', shadowOffset: { width: 0, - height: 1 + height: 1, }, shadowOpacity: 0.18, shadowRadius: 1.0, elevation: 1, - zIndex: 2 + zIndex: 2, }, scrollViewContentContainerStyle: { - width: '100%' - } -}) + width: '100%', + }, +}); + +const SMALL_PANEL_CONTENT_HEIGHT = PANEL_HEIGHT - (FULL_HEIGHT - 400) - 25; +const LARGE_PANEL_CONTENT_HEIGHT = PANEL_HEIGHT - 25; -export default SwipeablePanel -export const SMALL_PANEL_CONTENT_HEIGHT = - PANEL_HEIGHT - (FULL_HEIGHT - 400) - 25 -export const LARGE_PANEL_CONTENT_HEIGHT = PANEL_HEIGHT - 25 +export { SwipeablePanel, LARGE_PANEL_CONTENT_HEIGHT, SMALL_PANEL_CONTENT_HEIGHT }; diff --git a/src/index.tsx b/src/index.tsx index 60acf77..3c68c46 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,2 +1 @@ -import SwipeablePanel from './Panel' -export default SwipeablePanel +export { SwipeablePanel, LARGE_PANEL_CONTENT_HEIGHT, SMALL_PANEL_CONTENT_HEIGHT } from './Panel'; diff --git a/src/typings.d.ts b/src/typings.d.ts index 8b70fae..50e056a 100644 --- a/src/typings.d.ts +++ b/src/typings.d.ts @@ -3,90 +3,90 @@ // Definitions by: Enes Öztürk // Definitions: https://github.com/DefinitelyTyped/types/rn-swipeable-panel -import * as React from 'react' +import * as React from 'react'; declare interface SwipeablePanelProps extends React.Props { /** * Required prop for panels actual state. Set true if you want to open panel */ - isActive: boolean + isActive: boolean; /** * Set true if you want to show close button */ - showCloseButton?: boolean + showCloseButton?: boolean; /** * Set true if you want to make full with panel */ - fullWidth?: boolean + fullWidth?: boolean; /** * Set true if you want to disable black background opacity */ - noBackgroundOpacity?: boolean + noBackgroundOpacity?: boolean; /** * Use this prop to override panel style */ - style?: object + style?: object; /** * Use this prop to override close button background style */ - closeRootStyle?: object + closeRootStyle?: object; /** * Use this prop to override close button icon style */ - closeIconStyle?: object + closeIconStyle?: object; /** * Set true if you want to close panel by touching outside */ - closeOnTouchOutside?: boolean + closeOnTouchOutside?: boolean; /** * Set true if you want to let panel open just large mode */ - onlyLarge?: boolean + onlyLarge?: boolean; /** * Set true if you want to let panel open just small mode */ - onlySmall?: boolean + onlySmall?: boolean; /** * Set true if you want to open panel large by default */ - openLarge?: boolean + openLarge?: boolean; /** * Set true if you want to remove gray bar */ - noBar?: boolean + noBar?: boolean; /** * Use this prop to override bar style */ - barStyle?: object + barStyle?: object; /** * Set true if you want to make toucable outside of panel */ - allowTouchOutside?: boolean + allowTouchOutside?: boolean; // Event Handlers /** * Required prop to keep panel's state sync with your parent components'state. Will be fired when panel is closed. See the example project. */ - onClose: () => void + onClose: () => void; } -declare class SwipeablePanel extends React.Component< - SwipeablePanelProps, - any -> {} +declare var LARGE_PANEL_CONTENT_HEIGHT: number; +declare var SMALL_PANEL_CONTENT_HEIGHT: number; -export default SwipeablePanel +declare class SwipeablePanel extends React.Component {} + +export { SwipeablePanel, LARGE_PANEL_CONTENT_HEIGHT, SMALL_PANEL_CONTENT_HEIGHT }; diff --git a/tsconfig.json b/tsconfig.json index 804358b..4d61eb3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,11 @@ { "compilerOptions": { "outDir": "dist", - "module": "esnext", - "lib": ["dom", "esnext"], + "module": "ES2015", + "lib": ["ES2015"], + "jsx": "react-native", "moduleResolution": "node", - "jsx": "react", + "strict": true, "sourceMap": true, "declaration": true, "esModuleInterop": true, @@ -13,7 +14,7 @@ "noImplicitAny": true, "strictNullChecks": true, "suppressImplicitAnyIndexErrors": true, - "allowSyntheticDefaultImports": true + "isolatedModules": true }, "include": ["src"], "exclude": ["node_modules", "dist", "example"]