-
-
Notifications
You must be signed in to change notification settings - Fork 813
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* docs: updated readme file * docs: updated scrollables docs * docs: added custom-handle, react-navigation & touchables docs * chore: remove unused dependencies
- Loading branch information
Showing
22 changed files
with
826 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,197 @@ | ||
> This is a cloned project of `react-native-scroll-bottom-sheet` by [@rgommezz](https://github.com/rgommezz), but with different approach and extra functionalities. | ||
<div align="center"> | ||
<h1>Bottom Sheet</h1> | ||
|
||
[](https://www.npmjs.com/package/@gorhom/bottom-sheet) [](https://www.npmjs.com/package/@gorhom/bottom-sheet) [](https://www.npmjs.com/package/@gorhom/bottom-sheet) | ||
|
||
# Bottom Sheet | ||
<img src="./preview.gif"> | ||
|
||
> TODO | ||
A performant interactive bottom sheet with fully configurable options 🚀 | ||
|
||
</div> | ||
|
||
> Initially, this project was a cloned of `react-native-scroll-bottom-sheet` by [@rgommezz](https://github.com/rgommezz) ❤️. However, it is been fully re-written to add extra functionalities and simplify the approach. | ||
--- | ||
|
||
## Table of Contents | ||
|
||
1. [Features](#features) | ||
2. [Installation](#installation) | ||
3. [Usage](#usage) | ||
- [Custom Handle](./docs/custom-handle) | ||
- [React Navigation Integration](./docs/react-navigation) | ||
- [Touchables](./docs/touchables) | ||
4. [Props](#props) | ||
5. [Scrollables](#scrollables) | ||
- [BottomSheetFlatList](./docs/flatlist) | ||
- [BottomSheetSectionList](./docs/sectionlist) | ||
- [BottomSheetScrollView](./docs/scrollview) | ||
- [BottomSheetView](./docs/flatlist) | ||
6. [To Do](#to-do) | ||
7. [Credits](#built-with) | ||
8. [License](#license) | ||
|
||
## Features | ||
|
||
- Smooth interactions & snapping animations. | ||
- Support `FlatList`, `SectionList`, `ScrollView` & `View` scrolling interactions. | ||
- Support `React Navigation` Integration. | ||
- Written in `TypeScript`. | ||
|
||
## Installation | ||
|
||
```sh | ||
yarn add @gorhom/bottom-sheet | ||
# or | ||
npm install @gorhom/bottom-sheet | ||
``` | ||
|
||
> ⚠️ You need to install [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) & [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler) and follow their installation instructions. | ||
## Usage | ||
|
||
```tsx | ||
import React, { useCallback, useMemo, useRef } from 'react'; | ||
import { View, StyleSheet } from 'react-native'; | ||
import BottomSheet from '@gorhom/bottom-sheet'; | ||
|
||
const App = () => { | ||
// hooks | ||
const bottomSheetRef = useRef<BottomSheet>(null); | ||
|
||
// variables | ||
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []); | ||
|
||
// callbacks | ||
const handleSheetChanges = useCallback((index: number) => { | ||
console.log('handleSheetChanges', index); | ||
}, []); | ||
|
||
// renders | ||
return ( | ||
<View style={styles.container}> | ||
<BottomSheet | ||
ref={bottomSheetRef} | ||
initialSnapIndex={1} | ||
snapPoints={snapPoints} | ||
onChange={handleSheetChanges} | ||
> | ||
{/* INSERT A SCROLLABLE HERE */} | ||
</BottomSheet> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
padding: 24, | ||
}, | ||
}); | ||
|
||
export default App; | ||
``` | ||
|
||
## Props | ||
|
||
#### `initialSnapIndex` | ||
|
||
Initial snap index. You also could provide {`-1`} to initiate bottom sheet in closed state. | ||
|
||
> `required:` NO | `type:` number | `default:` 0 | ||
#### `snapPoints` | ||
|
||
Points for the bottom sheet to snap to, `points should be sorted from bottom to top`. It accepts array of number, string or mix. String values should be a percentage. | ||
|
||
> `required:` YES | `type:` Array<string | number> <br> `example:` [100, '50%', '90%'] | ||
#### `topInset` | ||
|
||
Top inset value helps to calculate percentage snap points values. usually comes from `@react-navigation/stack` hook `useHeaderHeight` or from `react-native-safe-area-context` hook `useSafeArea`. | ||
|
||
> `required:` NO | `type:` number | `default:` 0 | ||
#### `animationDuration` | ||
|
||
Snapping animation duration. | ||
|
||
> `required:` NO | `type:` number | `default:` 500 | ||
#### `animationEasing` | ||
|
||
Snapping animation easing function. | ||
|
||
> `required:` NO | `type:` Animated.EasingFunction | `default:` Easing.out(Easing.back(0.75)) | ||
#### `animatedPosition` | ||
|
||
Animated value to be used as a callback for the position node internally. | ||
|
||
> `required:` NO | `type:` Animated.Value<number> | ||
#### `animatedPositionIndex` | ||
|
||
Animated value to be used as a callback for the position index node internally. | ||
|
||
> `required:` NO | `type:` Animated.Value<number> | ||
#### `handleComponent` | ||
|
||
Component to be placed as a sheet handle. | ||
|
||
> `required:` NO | `type:` React.FC<[BottomSheetHandleProps](./src/components/handle/types.d.ts)> | ||
#### `onChange` | ||
|
||
Callback when sheet position changed to a provided point. | ||
|
||
> `required:` NO | `type:` (index: number) => void | ||
#### `children` | ||
|
||
A scrollable node or normal view. | ||
|
||
> `required:` YES | `type:` React.ReactNode[] | React.ReactNode | ||
## Scrollables | ||
|
||
This library provides a pre-integrated views that utilise an internal functionalities with the bottom sheet to allow smooth interactions. These views i called them `Scrollables` and they are: | ||
|
||
- [BottomSheetFlatList](./docs/flatlist) | ||
- [BottomSheetSectionList](./docs/sectionlist) | ||
- [BottomSheetScrollView](./docs/scrollview) | ||
- [BottomSheetView](./docs/flatlist) | ||
|
||
## To Do | ||
|
||
- [ ] Add tablets support. | ||
|
||
<h2 id="built-with">Built With ❤️</h2> | ||
|
||
- [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) | ||
- [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler) | ||
- [react-native-redash](https://github.com/wcandillon/react-native-redash) | ||
- [@react-native-community/bob](https://github.com/react-native-community/bob) | ||
|
||
## Author | ||
|
||
- [Mo Gorhom](https://gorhom.dev/) | ||
|
||
## License | ||
|
||
MIT | ||
|
||
<div align="center"> | ||
|
||
Liked the library? 😇 | ||
|
||
<a href="https://www.buymeacoffee.com/gorhom" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="Buy Me A Coffee" height="50" ></a> | ||
|
||
</div> | ||
|
||
--- | ||
|
||
<p align="center"> | ||
<a href="https://gorhom.dev" target="_blank"><img alt="Mo Gorhom" src="./logo.png"></a> | ||
</p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
# Custom Handle | ||
|
||
The library allows you to override the handle and create your own wonderful interactive animation. | ||
|
||
When you provide your own handle component, it will receive an animated value - `animatedPositionIndex` - that indicates the current position of the sheet. | ||
|
||
Here is an example of a custom handle component: | ||
|
||
```tsx | ||
import React, { useMemo } from 'react'; | ||
import { StyleProp, StyleSheet, ViewStyle } from 'react-native'; | ||
import { BottomSheetHandleProps } from '@gorhom/bottom-sheet'; | ||
import Animated, { interpolate, Extrapolate } from 'react-native-reanimated'; | ||
import { transformOrigin, toRad } from 'react-native-redash'; | ||
|
||
interface HandleProps extends BottomSheetHandleProps { | ||
style?: StyleProp<ViewStyle>; | ||
} | ||
|
||
const Handle: React.FC<HandleProps> = ({ style, animatedPositionIndex }) => { | ||
//#region animations | ||
const borderTopRadius = interpolate(animatedPositionIndex, { | ||
inputRange: [1, 2], | ||
outputRange: [20, 0], | ||
extrapolate: Extrapolate.CLAMP, | ||
}); | ||
const indicatorTransformOriginY = interpolate(animatedPositionIndex, { | ||
inputRange: [0, 1, 2], | ||
outputRange: [-1, 0, 1], | ||
extrapolate: Extrapolate.CLAMP, | ||
}); | ||
const leftIndicatorRotate = interpolate(animatedPositionIndex, { | ||
inputRange: [0, 1, 2], | ||
outputRange: [toRad(-30), 0, toRad(30)], | ||
extrapolate: Extrapolate.CLAMP, | ||
}); | ||
const rightIndicatorRotate = interpolate(animatedPositionIndex, { | ||
inputRange: [0, 1, 2], | ||
outputRange: [toRad(30), 0, toRad(-30)], | ||
extrapolate: Extrapolate.CLAMP, | ||
}); | ||
//#endregion | ||
|
||
//#region styles | ||
const containerStyle = useMemo( | ||
() => [ | ||
styles.header, | ||
style, | ||
{ | ||
borderTopLeftRadius: borderTopRadius, | ||
borderTopRightRadius: borderTopRadius, | ||
}, | ||
], | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[style] | ||
); | ||
const leftIndicatorStyle = useMemo( | ||
() => ({ | ||
...styles.indicator, | ||
...styles.leftIndicator, | ||
transform: transformOrigin( | ||
{ x: 0, y: indicatorTransformOriginY }, | ||
{ | ||
rotate: leftIndicatorRotate, | ||
translateX: -5, | ||
} | ||
), | ||
}), | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[] | ||
); | ||
const rightIndicatorStyle = useMemo( | ||
() => ({ | ||
...styles.indicator, | ||
...styles.rightIndicator, | ||
transform: transformOrigin( | ||
{ x: 0, y: indicatorTransformOriginY }, | ||
{ | ||
rotate: rightIndicatorRotate, | ||
translateX: 5, | ||
} | ||
), | ||
}), | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[] | ||
); | ||
//#endregion | ||
|
||
// render | ||
return ( | ||
<Animated.View style={containerStyle} renderToHardwareTextureAndroid={true}> | ||
<Animated.View style={leftIndicatorStyle} /> | ||
<Animated.View style={rightIndicatorStyle} /> | ||
</Animated.View> | ||
); | ||
}; | ||
|
||
export default Handle; | ||
|
||
const styles = StyleSheet.create({ | ||
header: { | ||
alignContent: 'center', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
backgroundColor: 'white', | ||
paddingVertical: 14, | ||
shadowColor: 'black', | ||
shadowOffset: { | ||
width: 0, | ||
height: -20, | ||
}, | ||
shadowOpacity: 0.1, | ||
shadowRadius: 10, | ||
elevation: 16, | ||
borderBottomWidth: 1, | ||
borderBottomColor: '#fff', | ||
}, | ||
indicator: { | ||
position: 'absolute', | ||
width: 10, | ||
height: 4, | ||
backgroundColor: '#999', | ||
}, | ||
leftIndicator: { | ||
borderTopStartRadius: 2, | ||
borderBottomStartRadius: 2, | ||
}, | ||
rightIndicator: { | ||
borderTopEndRadius: 2, | ||
borderBottomEndRadius: 2, | ||
}, | ||
}); | ||
|
||
``` |
Oops, something went wrong.