Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds useCurrentTabScrollY hook #265

Merged
merged 8 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# [5.0.0](https://github.com/PedroBern/react-native-collapsible-tab-view/compare/v5.0.0-rc.1...v5.0.0-rc.10) (2022-05-25)
# [5.0.0](https://github.com/PedroBern/react-native-collapsible-tab-view/compare/v5.0.0-rc.1...v5.0.0-rc.10) (2022-06-29)

### Performance Improvements

Expand All @@ -16,6 +16,8 @@

* custom label component ([51a7234](https://github.com/PedroBern/react-native-collapsible-tab-view/commit/51a7234fec8f19f384ed771789d883aee247260f))
* `keepActiveTabCentered` property on scrollable MaterialTabBar to keep tab in the center ([6d35e31](https://github.com/PedroBern/react-native-collapsible-tab-view/commit/6d35e3151355d35830a8387af642c5af5a13c54d))
* `useCurrentTabScrollY` ([73ee5d7](https://github.com/PedroBern/react-native-collapsible-tab-view/commit/73ee5d7c5e2b470551a5ad1dedae68413d3d5da0))

### Code Refactoring

* remove obsolete HeaderComponent and FooterComponent ([cb2cb04](https://github.com/PedroBern/react-native-collapsible-tab-view/commit/cb2cb04bbcf1dd86484c2a77f273e10ee6ceabbe))
Expand All @@ -25,6 +27,7 @@

* use `renderHeader` and `renderTabBar` instead of HeaderComponent and FooterComponent
* a peer dependency on `react-native-pager-view@5` is now required
* `useHeaderMeasurements` now returns the `height` as an `Animated.SharedValue`

## [4.5.2](https://github.com/PedroBern/react-native-collapsible-tab-view/compare/v4.5.1...v4.5.2) (2022-01-15)

Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,17 @@ Returns the top distance and the header height. See the animated header example
const { top, height } = useHeaderMeasurements()
```

### useCurrentTabScrollY

Returns the vertical scroll position of the current tab as an Animated SharedValue.

Because this library requires handling `onScroll` for its functionality, this is the only way to react to changes to the scroll position of the underlying scrollable component.

```tsx
const scrollY = useCurrentTabScrollY()
```


## Default Tab Bar

### MaterialTabItem
Expand Down
11 changes: 11 additions & 0 deletions documentation/README_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ Returns the top distance and the header height. See the animated header example
const { top, height } = useHeaderMeasurements()
```

### useCurrentTabScrollY

Returns the vertical scroll position of the current tab as an Animated SharedValue.

Because this library requires handling `onScroll` for its functionality, this is the only way to react to changes to the scroll position of the underlying scrollable component.

```tsx
const scrollY = useCurrentTabScrollY()
```


## Default Tab Bar

$TAB_BAR_API
Expand Down
16 changes: 12 additions & 4 deletions example/src/AnimatedHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from 'react'
import { Text, StyleSheet, View } from 'react-native'
import { StyleSheet, View } from 'react-native'
import { useHeaderMeasurements } from 'react-native-collapsible-tab-view'
import Animated, {
interpolate,
useAnimatedStyle,
useDerivedValue,
} from 'react-native-reanimated'

import { useCurrentTabScrollY } from '../../src/hooks'
import ExampleComponent from './Shared/ExampleComponent'
import ReText from './Shared/ReText'
import { ExampleComponentType } from './types'

const title = 'Animated Header'
Expand All @@ -15,15 +18,20 @@ const MIN_HEADER_HEIGHT = 48

export const Header = () => {
const { top, height } = useHeaderMeasurements()
const scrollY = useCurrentTabScrollY()

const scrollYText = useDerivedValue(
() => `Scroll Y is: ${scrollY.value.toFixed(2)}`
)

const stylez = useAnimatedStyle(() => {
return {
transform: [
{
translateY: interpolate(
top.value,
[0, -(height - MIN_HEADER_HEIGHT)],
[0, (height - MIN_HEADER_HEIGHT) / 2]
[0, -(height.value || 0 - MIN_HEADER_HEIGHT)],
[0, (height.value || 0 - MIN_HEADER_HEIGHT) / 2]
),
},
],
Expand All @@ -33,7 +41,7 @@ export const Header = () => {
return (
<View style={[styles.root]}>
<Animated.View style={[styles.container, stylez]}>
<Text style={styles.text}>{title}</Text>
<ReText style={styles.text} text={scrollYText} />
</Animated.View>
</View>
)
Expand Down
6 changes: 5 additions & 1 deletion example/src/Shared/Contacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ const renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />
const ListEmptyComponent = () => {
const { top, height } = Tabs.useHeaderMeasurements()
const translateY = useDerivedValue(() => {
return interpolate(-top.value, [0, height], [-height / 2, 0])
return interpolate(
-top.value,
[0, height.value || 0],
[-(height.value || 0) / 2, 0]
)
}, [height])

const stylez = useAnimatedStyle(() => {
Expand Down
42 changes: 42 additions & 0 deletions example/src/Shared/ReText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// courtesy of https://github.com/wcandillon/react-native-redash/blob/fd0b0ddb3b4c10ae88cf1f8a95890c7c5eb3c475/src/ReText.tsx

import React from 'react'
import type { TextProps as RNTextProps } from 'react-native'
import { StyleSheet, TextInput } from 'react-native'
import Animated, { useAnimatedProps } from 'react-native-reanimated'

const styles = StyleSheet.create({
baseStyle: {
color: 'black',
},
})
Animated.addWhitelistedNativeProps({ text: true })

interface TextProps {
text: Animated.SharedValue<string>
style?: Animated.AnimateProps<RNTextProps>['style']
}

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)

const ReText = (props: TextProps) => {
const { text, style } = { style: {}, ...props }
const animatedProps = useAnimatedProps(() => {
return {
text: text.value,
// Here we use any because the text prop is not available in the type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any
})
return (
<AnimatedTextInput
underlineColorAndroid="transparent"
editable={false}
value={text.value}
style={[styles.baseStyle, style]}
{...{ animatedProps }}
/>
)
}

export default ReText
6 changes: 5 additions & 1 deletion example/src/Shared/SectionContacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,11 @@ const renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />
const ListEmptyComponent = () => {
const { top, height } = Tabs.useHeaderMeasurements()
const translateY = useDerivedValue(() => {
return interpolate(-top.value, [0, height], [-height / 2, 0])
return interpolate(
-top.value,
[0, height.value || 0],
[-(height.value || 0) / 2, 0]
)
}, [height])

const stylez = useAnimatedStyle(() => {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-collapsible-tab-view",
"version": "5.0.0-rc.10",
"version": "5.0.0-rc.13",
"description": "Collapsible tab view component for React Native",
"main": "lib/commonjs/index.js",
"react-native": "src/index.tsx",
Expand Down
1 change: 1 addition & 0 deletions src/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ export const Container = React.memo(
tabName: tabNames.value[i],
})
index.value = i
scrollYCurrent.value = scrollY.value[index.value] || 0
}
},
[]
Expand Down
16 changes: 12 additions & 4 deletions src/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -568,25 +568,33 @@ export function useConvertAnimatedToValue<T>(
return value
}

interface HeaderMeasurements {
export interface HeaderMeasurements {
/**
* Animated value that represents the current Y translation of the header
*/
top: Animated.SharedValue<number>
/**
* The height of the header
* Animated value that represents the height of the header
*/
height: number
height: Animated.SharedValue<number | undefined>
}

export function useHeaderMeasurements(): HeaderMeasurements {
const { headerTranslateY, headerHeight } = useTabsContext()
return {
top: headerTranslateY,
height: headerHeight.value || 0,
height: headerHeight,
}
}

/**
* Returns the vertical scroll position of the current tab as an Animated SharedValue
*/
export function useCurrentTabScrollY(): Animated.SharedValue<number> {
const { scrollYCurrent } = useTabsContext()
return scrollYCurrent
}

/**
* Returns the currently focused tab name
*/
Expand Down
3 changes: 3 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ export const Tabs = {

export { Container, Tab, Lazy, FlatList, ScrollView, SectionList }
export {
useCurrentTabScrollY,
useHeaderMeasurements,
useFocusedTab,
useAnimatedTabIndex,
useCollapsibleStyle,
} from './hooks'
export type { HeaderMeasurements } from './hooks'

export { MaterialTabBar } from './MaterialTabBar/TabBar'
export { MaterialTabItem } from './MaterialTabBar/TabItem'