docs: update docs (#3)

* docs: updated readme file

* docs: updated scrollables docs

* docs: added custom-handle, react-navigation & touchables docs

* chore: remove unused dependencies
This commit is contained in:
Mo Gorhom
2020-08-11 16:05:16 +02:00
committed by GitHub
parent a58a29fc0f
commit fdef2a92f0
22 changed files with 826 additions and 125 deletions

View File

@@ -1,5 +1,6 @@
MIT License
Copyright (c) 2020 Mo Gorhom
Copyright (c) 2020 Raul Gomez Acuna
Permission is hereby granted, free of charge, to any person obtaining a copy

197
README.md
View File

@@ -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>
[![npm](https://img.shields.io/npm/v/@gorhom/bottom-sheet?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/npm/l/@gorhom/bottom-sheet?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/badge/types-included-blue?style=flat-square)](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>

134
docs/custom-handle.md Normal file
View File

@@ -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,
},
});
```

93
docs/flatlist.md Normal file
View File

@@ -0,0 +1,93 @@
# Bottom Sheet FlatList
Is an extended component of `FlatList` from `react-native`, with bottom sheet integrations.
## Props
#### `focusHook`
This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
> `required:` NO | `type:` (effect: EffectCallback, deps?: DependencyList) => void | `default: ` React.useEffect
## Example
```tsx
import React, { useCallback, useRef, useMemo } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import BottomSheet, { BottomSheetFlatList } from '@gorhom/bottom-sheet';
const App = () => {
// hooks
const sheetRef = useRef<BottomSheet>(null);
// variables
const data = useMemo(
() =>
Array(50)
.fill(0)
.map((_, index) => `index-${index}`),
[]
);
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
const handleSheetChange = useCallback(index => {
console.log('handleSheetChange', index);
}, []);
const handleSnapPress = useCallback(index => {
sheetRef.current?.snapTo(index);
}, []);
const handleClosePress = useCallback(() => {
sheetRef.current?.close();
}, []);
// render
const renderItem = useCallback(
({ item }) => (
<View style={styles.itemContainer}>
<Text>{item}</Text>
</View>
),
[]
);
return (
<View style={styles.container}>
<Button title="Snap To 90%" onPress={() => handleSnapPress(2)} />
<Button title="Snap To 50%" onPress={() => handleSnapPress(1)} />
<Button title="Snap To 25%" onPress={() => handleSnapPress(0)} />
<Button title="Close" onPress={() => handleClosePress()} />
<BottomSheet
ref={sheetRef}
initialSnapIndex={1}
snapPoints={snapPoints}
onChange={handleSheetChange}
>
<BottomSheetFlatList
data={data}
keyExtractor={i => i}
renderItem={renderItem}
contentContainerStyle={styles.contentContainer}
/>
</BottomSheet>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 200,
},
contentContainer: {
backgroundColor: 'white',
},
itemContainer: {
padding: 6,
margin: 6,
backgroundColor: '#eee',
},
});
export default App;
```

10
docs/react-navigation.md Normal file
View File

@@ -0,0 +1,10 @@
# React Navigation
One of the main goal of this library, is to allow user to fully integrate a navigator in the bottom sheet. This integration allow lots of opportunities for a native-like experience in your app :)
However, there are some tricks has to be follow to enable both libraries to work together seamlessly.
- You need to override `safeAreaInsets`, by default `React Navigation` add the safe area insets to all its navigators, but since your navigator will properly won't cover full screen, you will need to override it and set it to `0`.
- You need to override `headerLeft`, due to bottom sheet wrapping the content with `TapGestureHandler` & `PanGestureHandler`, you will need to wrap the header left button with `TouchableOpacity` that this library provide to allow it working.
For more details regarding the implementation, please have a look at the [Navigator Example](../example/src/screens/NavigatorExample.tsx).

92
docs/scrollview.md Normal file
View File

@@ -0,0 +1,92 @@
# Bottom Sheet ScrollView
Is an extended component of `ScrollView` from `react-native`, with bottom sheet integrations.
## Props
#### `focusHook`
This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
> `required:` NO | `type:` (effect: EffectCallback, deps?: DependencyList) => void | `default: ` React.useEffect
## Example
```tsx
import React, { useCallback, useRef, useMemo } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import BottomSheet, { BottomSheetScrollView } from '@gorhom/bottom-sheet';
const App = () => {
// hooks
const sheetRef = useRef<BottomSheet>(null);
// variables
const data = useMemo(
() =>
Array(50)
.fill(0)
.map((_, index) => `index-${index}`),
[]
);
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
const handleSheetChange = useCallback(index => {
console.log('handleSheetChange', index);
}, []);
const handleSnapPress = useCallback(index => {
sheetRef.current?.snapTo(index);
}, []);
const handleClosePress = useCallback(() => {
sheetRef.current?.close();
}, []);
// render
const renderItem = useCallback(
(item) => (
<View key={item} style={styles.itemContainer}>
<Text>{item}</Text>
</View>
),
[]
);
return (
<View style={styles.container}>
<Button title="Snap To 90%" onPress={() => handleSnapPress(2)} />
<Button title="Snap To 50%" onPress={() => handleSnapPress(1)} />
<Button title="Snap To 25%" onPress={() => handleSnapPress(0)} />
<Button title="Close" onPress={() => handleClosePress()} />
<BottomSheet
ref={sheetRef}
initialSnapIndex={1}
snapPoints={snapPoints}
onChange={handleSheetChange}
>
<BottomSheetScrollView
contentContainerStyle={styles.contentContainer}
>
{data.map(renderItem)}
</BottomSheetScrollView>
</BottomSheet>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 200,
},
contentContainer: {
backgroundColor: 'white',
},
itemContainer: {
padding: 6,
margin: 6,
backgroundColor: '#eee',
},
});
export default App;
```

112
docs/sectionlist.md Normal file
View File

@@ -0,0 +1,112 @@
# Bottom Sheet SectionList
Is an extended component of `SectionList` from `react-native`, with bottom sheet integrations.
## Props
#### `focusHook`
This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
> `required:` NO | `type:` (effect: EffectCallback, deps?: DependencyList) => void | `default: ` React.useEffect
## Example
```tsx
import React, { useCallback, useRef, useMemo } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import BottomSheet, { BottomSheetSectionList } from '@gorhom/bottom-sheet';
const App = () => {
// hooks
const sheetRef = useRef<BottomSheet>(null);
// variables
const sections = useMemo(
() =>
Array(10)
.fill(0)
.map((_, index) => ({
title: `Section ${index}`,
data: Array(10)
.fill(0)
.map((_, index) => `Item ${index}`),
})),
[]
);
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
const handleSheetChange = useCallback(index => {
console.log('handleSheetChange', index);
}, []);
const handleSnapPress = useCallback(index => {
sheetRef.current?.snapTo(index);
}, []);
const handleClosePress = useCallback(() => {
sheetRef.current?.close();
}, []);
// render
const renderSectionHeader = useCallback(
({ section }) => (
<View style={styles.sectionHeaderContainer}>
<Text>{section.title}</Text>
</View>
),
[]
);
const renderItem = useCallback(
({ item }) => (
<View style={styles.itemContainer}>
<Text>{item}</Text>
</View>
),
[]
);
return (
<View style={styles.container}>
<Button title="Snap To 90%" onPress={() => handleSnapPress(2)} />
<Button title="Snap To 50%" onPress={() => handleSnapPress(1)} />
<Button title="Snap To 25%" onPress={() => handleSnapPress(0)} />
<Button title="Close" onPress={() => handleClosePress()} />
<BottomSheet
ref={sheetRef}
initialSnapIndex={1}
snapPoints={snapPoints}
onChange={handleSheetChange}
>
<BottomSheetSectionList
sections={sections}
keyExtractor={i => i}
renderSectionHeader={renderSectionHeader}
renderItem={renderItem}
contentContainerStyle={styles.contentContainer}
/>
</BottomSheet>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 200,
},
contentContainer: {
backgroundColor: 'white',
},
sectionHeaderContainer: {
backgroundColor: 'white',
padding: 6,
},
itemContainer: {
padding: 6,
margin: 6,
backgroundColor: '#eee',
},
});
export default App;
```

9
docs/touchables.md Normal file
View File

@@ -0,0 +1,9 @@
# Touchables
Due to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any button's interaction would not function as expected.
To resolve this issue, please use touchables that this library provide.
- TouchableOpacity
- TouchableHighlight
- TouchableWithoutFeedback

94
docs/view.md Normal file
View File

@@ -0,0 +1,94 @@
# Bottom Sheet View
Is an extended component of `View` from `react-native`, with bottom sheet integrations.
> This only needed when the bottom sheet used with `React Navigation`.
## Props
#### `focusHook`
This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
> `required:` NO | `type:` (effect: EffectCallback, deps?: DependencyList) => void | `default: ` React.useEffect
## Example
```tsx
import React, { useCallback, useRef, useMemo } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';
const App = () => {
// hooks
const sheetRef = useRef<BottomSheet>(null);
// variables
const data = useMemo(
() =>
Array(50)
.fill(0)
.map((_, index) => `index-${index}`),
[]
);
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
const handleSheetChange = useCallback(index => {
console.log('handleSheetChange', index);
}, []);
const handleSnapPress = useCallback(index => {
sheetRef.current?.snapTo(index);
}, []);
const handleClosePress = useCallback(() => {
sheetRef.current?.close();
}, []);
// render
const renderItem = useCallback(
(item) => (
<View style={styles.itemContainer}>
<Text>{item}</Text>
</View>
),
[]
);
return (
<View style={styles.container}>
<Button title="Snap To 90%" onPress={() => handleSnapPress(2)} />
<Button title="Snap To 50%" onPress={() => handleSnapPress(1)} />
<Button title="Snap To 25%" onPress={() => handleSnapPress(0)} />
<Button title="Close" onPress={() => handleClosePress()} />
<BottomSheet
ref={sheetRef}
initialSnapIndex={1}
snapPoints={snapPoints}
onChange={handleSheetChange}
>
<BottomSheetView
contentContainerStyle={styles.contentContainer}
>
{data.map(renderItem)}
</BottomSheetView>
</BottomSheet>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 200,
},
contentContainer: {
backgroundColor: 'white',
},
itemContainer: {
padding: 6,
margin: 6,
backgroundColor: '#eee',
},
});
export default App;
```

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -233,8 +233,6 @@ PODS:
- React-cxxreact (= 0.62.2)
- React-jsi (= 0.62.2)
- React-jsinspector (0.62.2)
- react-native-maps (0.27.1):
- React
- react-native-safe-area-context (0.7.3):
- React
- React-RCTActionSheet (0.62.2):
@@ -330,7 +328,6 @@ DEPENDENCIES:
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-maps (from `../node_modules/react-native-maps`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
@@ -393,8 +390,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-maps:
:path: "../node_modules/react-native-maps"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
React-RCTActionSheet:
@@ -454,7 +449,6 @@ SPEC CHECKSUMS:
React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161
React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
react-native-maps: f4b89da81626ad7f151a8bfcb79733295d31ce5c
react-native-safe-area-context: e200d4433aba6b7e60b52da5f37af11f7a0b0392
React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0

View File

@@ -11,15 +11,13 @@
"dependencies": {
"@gorhom/showcase-template": "^0.3.1",
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/native": "^5.3.2",
"@react-navigation/stack": "^5.3.5",
"date-fns": "^2.15.0",
"@react-navigation/native": "^5.7.3",
"@react-navigation/stack": "^5.9.0",
"faker": "^4.1.0",
"lodash.isequal": "^4.5.0",
"react": "16.11.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "^1.7.0",
"react-native-maps": "^0.27.1",
"react-native-reanimated": "^1.11.0",
"react-native-redash": "^14.2.3",
"react-native-safe-area-context": "0.7.3",

View File

@@ -87,7 +87,7 @@ const BasicExample = () => {
initialSnapIndex={1}
handleComponent={Handle}
topInset={headerHeight}
position={position}
animatedPosition={position}
onChange={handleSheetChanges}
>
{/* <View

View File

@@ -1,66 +1,5 @@
import { format, parse, subDays } from 'date-fns';
import Faker from 'faker';
export function generateRandomIntFromInterval(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
export interface ListItemData {
id: string;
title: string;
subtitle: string;
amount: string;
iconColor: string;
}
export const createMockData = () => {
const elementsByDate: {
[key: string]: ListItemData[];
} = {};
const today = new Date();
Array.from({ length: 200 }).forEach((_, index) => {
const date = format(
subDays(today, generateRandomIntFromInterval(0, 30)),
'yyyy LL d'
);
const amount = (generateRandomIntFromInterval(100, 10000) / 100).toFixed(2);
const randomEntry = {
id: String(index),
title: Faker.commerce.productName(),
subtitle: Faker.commerce.productMaterial(),
amount,
iconColor: `rgb(${generateRandomIntFromInterval(
0,
255
)}, ${generateRandomIntFromInterval(
0,
255
)}, ${generateRandomIntFromInterval(0, 255)})`,
};
if (Array.isArray(elementsByDate[date])) {
elementsByDate[date].push(randomEntry);
} else {
elementsByDate[date] = [randomEntry];
}
});
return Object.entries(elementsByDate)
.map(([key, data]) => ({
title: key,
data,
}))
.sort((a, b) => {
return (
parse(b.title, 'yyyy LL d', new Date()).getTime() -
parse(a.title, 'yyyy LL d', new Date()).getTime()
);
})
.map(item => ({
...item,
title: format(parse(item.title, 'yyyy LL d', new Date()), 'ccc d MMM'),
}));
};
export type Contact = {
name: string;
jobTitle: string;

View File

@@ -787,11 +787,11 @@
serve-static "^1.13.1"
"@react-native-community/cli-platform-android@^4.5.1":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-4.10.1.tgz#c326dfcce42acf106cc9c4afb95b360644fa595b"
integrity sha512-RawTRMd+pGQ/k+ZnZ/wTOcPd7sfbxkuhUmBoIthj8WJcufQdda57y/c6Cys9efAxKjvBP02RKX/Uhu+v7aS4jA==
version "4.11.0"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-4.11.0.tgz#0ce9b88ed8b6b0ef962af49d980eb53433c17a84"
integrity sha512-BzqocGjOCjpDW0bM/LUrHMXw4nBvOhDXnHWxaoRp3eeUVsD2oSegoRn52kZo9yhPb9cCPkZJ3b+Web71Ue4j9w==
dependencies:
"@react-native-community/cli-tools" "^4.10.1"
"@react-native-community/cli-tools" "^4.11.0"
chalk "^3.0.0"
execa "^1.0.0"
fs-extra "^8.1.0"
@@ -803,11 +803,11 @@
xmldoc "^1.1.2"
"@react-native-community/cli-platform-ios@^4.5.0":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-4.10.1.tgz#c73d7b33f22458aa806069df0dfc0ed55973679b"
integrity sha512-CiwAcZ0YZ5NBz6cKfa4MRFnPtTadRiy/A+kzaBUzsLXqV2qw5YIl08JEaxAI7sjuoi8/EE8CRCIkjlGYcqNK9Q==
version "4.11.0"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-4.11.0.tgz#5870bf5f2b3c01a0aa672a7c1f7f0fe13337c6b5"
integrity sha512-/qkjnhhJ7BGBTNkHSS8a+z8UgWUQbU6YZOTuYxjNywGUzMiTsb/wlm2cWCY1VEAvWtY97c4plAZ5OferPJHaVA==
dependencies:
"@react-native-community/cli-tools" "^4.10.1"
"@react-native-community/cli-tools" "^4.11.0"
chalk "^3.0.0"
glob "^7.1.3"
js-yaml "^3.13.1"
@@ -815,13 +815,13 @@
plist "^3.0.1"
xcode "^2.0.0"
"@react-native-community/cli-server-api@^4.10.1":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-4.10.1.tgz#6467c1c7e08bda068873bfd3c9d6ce112be969fa"
integrity sha512-GIueLxHr+qZhrSpwabbQuMMEAfdew38LmctYRuHVLOnsya0JZOvxehmD04aUrU54PaTPBj7Iidyrfd8fPDTaow==
"@react-native-community/cli-server-api@^4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-4.11.0.tgz#93887ab8496c9d89b53817297974670184be1191"
integrity sha512-vrRaGq7ezsxyyUsFhAboEtA1CHLDa2UpJygOWHip30LaAluM+vopAJbau2NtHVX54vgQzXo438Tx8TXiRacPhA==
dependencies:
"@react-native-community/cli-debugger-ui" "^4.9.0"
"@react-native-community/cli-tools" "^4.10.1"
"@react-native-community/cli-tools" "^4.11.0"
compression "^1.7.1"
connect "^3.6.5"
errorhandler "^1.5.0"
@@ -829,10 +829,10 @@
serve-static "^1.13.1"
ws "^1.1.0"
"@react-native-community/cli-tools@^4.10.1":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-4.10.1.tgz#11f6833e646fbf53509282912e8d77658a8578b0"
integrity sha512-zGD0h+Ay8Rk8p+2wG41V163am8HfKkoZsVDKYkEKYD8O019if893pZyQ2sDcgk2ppNILrCt9O264dPDe/Ly1ow==
"@react-native-community/cli-tools@^4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-4.11.0.tgz#a53a51da76468a37f89ef7db808acc1d3c5f9cea"
integrity sha512-o2dh9q/778lIYBJxgIvTXkcxi9bSozjt8lv3tpyVmLZNA/PAPmQ7CafT37jWWwdmaSgP7nWyp4DtuE/gRsrXkA==
dependencies:
chalk "^3.0.0"
lodash "^4.17.15"
@@ -847,14 +847,14 @@
integrity sha512-ael2f1onoPF3vF7YqHGWy7NnafzGu+yp88BbFbP0ydoCP2xGSUzmZVw0zakPTC040Id+JQ9WeFczujMkDy6jYQ==
"@react-native-community/cli@^4.5.1":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-4.10.1.tgz#3c1e74f55c004936368d3576d4c1da7d02b89904"
integrity sha512-CtDer1sFxxPCvBBgmTbY5mjXgJiY/j7Nm7PzbbKxVBgpTkz5ZWP9B5e17lkmIweLqKDcM3hseCfsM/wG30fcLg==
version "4.11.0"
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-4.11.0.tgz#58faf2e27ab5601bd2d3ec1cd84a213d33a31480"
integrity sha512-pP2jB7294708pX81l6fjCxnBNGefRj8/X1nqGIgiMpHdI1WXfwR6XuegZPMGgxkiCISs7FZybV7TBl1jVxlVpA==
dependencies:
"@hapi/joi" "^15.0.3"
"@react-native-community/cli-debugger-ui" "^4.9.0"
"@react-native-community/cli-server-api" "^4.10.1"
"@react-native-community/cli-tools" "^4.10.1"
"@react-native-community/cli-server-api" "^4.11.0"
"@react-native-community/cli-tools" "^4.11.0"
"@react-native-community/cli-types" "^4.10.1"
chalk "^3.0.0"
command-exists "^1.2.8"
@@ -903,7 +903,7 @@
react-is "^16.13.0"
use-subscription "^1.4.0"
"@react-navigation/native@^5.3.2":
"@react-navigation/native@^5.7.3":
version "5.7.3"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-5.7.3.tgz#3cda5ee7b0fe0d980db6d788419f0af50a64deac"
integrity sha512-bXb1g/cLpGF2DW1Vxk90Ch5vbaZTk5b/4Fn5xjQlueQODgc9ca+GPEssKZ84hCrNmS+Xg+iK1m/ArawLF5gMlw==
@@ -918,7 +918,7 @@
dependencies:
nanoid "^3.1.12"
"@react-navigation/stack@^5.3.5":
"@react-navigation/stack@^5.9.0":
version "5.9.0"
resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-5.9.0.tgz#bf24607175bf502798cc4c832aa8a86e55f3b365"
integrity sha512-kt6M0ZLMyNKXfKi50n01bHg4/d8zp0Yh5QaQG4d1roWOqdV9ou1nFEK4l2yQ6XKH2lLSYswHElPDZUuWd+6XzA==
@@ -974,9 +974,9 @@
"@types/react" "*"
"@types/react@*", "@types/react@^16.9.23":
version "16.9.45"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.45.tgz#b43ccf3d8a3d2020e6a48c8c8492e5a4bc10f097"
integrity sha512-vv950slTF5UZ5eDOf13b8qC1SD4rTvkqg3HfaUKzr17U97oeJZAa+dUaIHn0QoOJflNTIt6Pem9MmapULs9dkA==
version "16.9.46"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.46.tgz#f0326cd7adceda74148baa9bff6e918632f5069e"
integrity sha512-dbHzO3aAq1lB3jRQuNpuZ/mnu+CdD3H0WVaaBQA8LTT3S33xhVBUj232T8M3tAhSWJs/D/UqORYUlJNl/8VQZg==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
@@ -1674,11 +1674,6 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.2.tgz#ee5ff8f208c8cd613b389f7b222c9801ca62b3f7"
integrity sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==
date-fns@^2.15.0:
version "2.15.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.15.0.tgz#424de6b3778e4e69d3ff27046ec136af58ae5d5f"
integrity sha512-ZCPzAMJZn3rNUvvQIMlXhDr4A+Ar07eLeGsGREoWU19a3Pqf5oYa+ccd+B3F6XVtQY6HANMFdOQ8A+ipFnvJdQ==
dayjs@^1.8.15:
version "1.8.33"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.33.tgz#18bc4a2b6c1c6f4d67b4c4f2536c0b97e5b766f7"
@@ -3555,11 +3550,6 @@ react-native-iphone-x-helper@^1.2.1:
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.2.1.tgz#645e2ffbbb49e80844bb4cbbe34a126fda1e6772"
integrity sha512-/VbpIEp8tSNNHIvstuA3Swx610whci1Zpc9mqNkqn14DkMbw+ORviln2u0XyHG1kPvvwTNGZY6QpeFwxYaSdbQ==
react-native-maps@^0.27.1:
version "0.27.1"
resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-0.27.1.tgz#2f10cd417bb2fd938c9e015b1c9b6d9b1a44b97f"
integrity sha512-HygBkZBecTnIVRYrSiLRAvu4OmXOYso/A7c6Cy73HkOh9CgGV8Ap5eBea24tvmFGptjj5Hg8AJ94/YbmWK1Okw==
react-native-reanimated@^1.11.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-1.11.0.tgz#9fd2e65c3e0886039673667ba99e228776a85764"

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,7 +1,7 @@
{
"name": "@gorhom/bottom-sheet",
"version": "0.0.8",
"description": "",
"description": "A performant interactive bottom sheet with fully configurable options 🚀",
"main": "lib/commonjs/index",
"module": "lib/module/index",
"types": "lib/typescript/index.d.ts",
@@ -12,13 +12,12 @@
],
"keywords": [
"react-native",
"react",
"ios",
"android",
"bottom-sheet",
"bottomsheet",
"cross-platform",
"60FPS"
"reanimated",
"sheet"
],
"repository": "https://github.com/gorhom/react-native-bottom-sheet",
"author": "Mo Gorhom (https://gorhom.dev)",

View File

@@ -3,14 +3,51 @@ import type Animated from 'react-native-reanimated';
import type { BottomSheetHandleProps } from '../handle';
export interface BottomSheetProps extends BottomSheetAnimationConfigs {
/**
* Initial snap index, you also could provide {`-1`} to initiate bottom sheet in closed state.
* @type number
* @default 0
*/
initialSnapIndex?: number;
/**
* Points for the bottom sheet to snap to. It accepts array of number, string or mix.
* String values should be a percentage.
* @type Array<string | number>
* @example
* [100, '50%', '90%']
*/
snapPoints: Array<string | number>;
/**
* 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`.
* @type number
*/
topInset?: number;
/**
* Animated value to be used as a callback of the position node internally.
* @type Animated.Value<number>
*/
animatedPosition?: Animated.Value<number>;
/**
* Animated value to be used as a callback for the position index node internally.
* @type Animated.Value<number>
*/
animatedPositionIndex?: Animated.Value<number>;
/**
* Component to be placed as a sheet handle.
* @see {BottomSheetHandleProps}
* @type React.FC\<BottomSheetHandleProps\>
*/
handleComponent?: React.FC<BottomSheetHandleProps>;
children: React.ReactNode[] | React.ReactNode;
/**
* Callback when sheet position changed to a provided point.
* @type (index: number) => void;
*/
onChange?: (index: number) => void;
/**
* A scrollable node or normal view.
* @type React.ReactNode[] | React.ReactNode
*/
children: React.ReactNode[] | React.ReactNode;
}
export interface BottomSheetAnimationConfigs {

View File

@@ -9,6 +9,10 @@ type BottomSheetFlatListProps<T> = Omit<
| 'onScrollBeginDrag'
| 'scrollEventThrottle'
> & {
/**
* This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
* @type (effect: EffectCallback, deps?: DependencyList) => void
*/
focusHook?: (effect: EffectCallback, deps?: DependencyList) => void;
};

View File

@@ -1,5 +1,9 @@
import type Animated from 'react-native-reanimated';
export interface BottomSheetHandleProps {
/**
* Animated value to be used as a callback for the position index node internally.
* @type Animated.Value<number>
*/
animatedPositionIndex: Animated.Node<number>;
}

View File

@@ -13,6 +13,10 @@ export type BottomSheetScrollViewProps = Omit<
| 'scrollEventThrottle'
> & {
children: React.ReactNode[] | React.ReactNode;
/**
* This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
* @type (effect: EffectCallback, deps?: DependencyList) => void
*/
focusHook?: (effect: EffectCallback, deps?: DependencyList) => void;
};

View File

@@ -9,6 +9,10 @@ type BottomSheetSectionListProps<T> = Omit<
| 'onScrollBeginDrag'
| 'scrollEventThrottle'
> & {
/**
* This needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with `React Navigation`. You will need to provide `useFocusEffect` from `@react-navigation/native`.
* @type (effect: EffectCallback, deps?: DependencyList) => void
*/
focusHook?: (effect: EffectCallback, deps?: DependencyList) => void;
};