Skip to content

Commit

Permalink
feat: add minHeaderHeight prop
Browse files Browse the repository at this point in the history
Close #95
Close #5
  • Loading branch information
tcorreiaubi authored Feb 4, 2021
1 parent fe4ac3c commit 0036da3
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 18 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ const Example: React.FC<Props> = () => {
|headerHeight|`number \| undefined`||Is optional, but will optimize the first render.|
|initialTabName|`string \| undefined`|||
|lazy|`boolean \| undefined`||If lazy, will mount the screens only when the tab is visited. There is a default fade in transition.|
|minHeaderHeight|`number \| undefined`|`0`|Header minimum height when collapsed|
|onIndexChange|`OnTabChangeCallback<string> \| undefined`||Callback fired when the index changes. It receives the previous and current index and tabnames.|
|pagerProps|`Pick<FlatListProps<number>, "ItemSeparatorComponent" \| "ListEmptyComponent" \| "ListFooterComponent" \| "ListFooterComponentStyle" \| "ListHeaderComponent" \| ... 128 more ... \| "persistentScrollbar"> \| undefined`||Props passed to the horiztontal flatlist. If you want for example to disable swiping, you can pass `{ scrollEnabled: false }`|
|refMap|`Record<string, Ref>`|||
Expand Down Expand Up @@ -315,6 +316,7 @@ const { focusedTab, ...rest } = useTabsContext()
|endDrag|`SharedValue<number>`||Used internally.|
|focusedTab|`SharedValue<string>`||Name of the current focused tab.|
|headerHeight|`number`|||
|headerScrollDistance|`SharedValue<number>`|||
|index|`SharedValue<number>`|||
|indexDecimal|`SharedValue<number>`|||
|isGliding|`SharedValue<boolean>`|||
Expand Down
2 changes: 2 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Default from './Default'
import DiffClamp from './DiffClamp'
import DiffClampSnap from './DiffClampSnap'
import Lazy from './Lazy'
import MinHeaderHeight from './MinHeaderHeight'
import OnIndexChange from './OnIndexChange'
import QuickStartDemo from './QuickStartDemo'
import Ref from './Ref'
Expand All @@ -41,6 +42,7 @@ const EXAMPLE_COMPONENTS: ExampleComponentType[] = [
StartOnSpecificTab,
Ref,
OnIndexChange,
MinHeaderHeight,
]

const ExampleList: React.FC<object> = () => {
Expand Down
23 changes: 23 additions & 0 deletions example/src/MinHeaderHeight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'

import ExampleComponent from './Shared/ExampleComponent'
import { buildHeader, HEADER_HEIGHT } from './Shared/Header'
import { ExampleComponentType } from './types'

const title = 'Min Header Height'

const Header = buildHeader(title)
const minHeaderHeight = Math.round(HEADER_HEIGHT / 3)

const DefaultExample: ExampleComponentType = () => {
return (
<ExampleComponent
HeaderComponent={Header}
minHeaderHeight={minHeaderHeight}
/>
)
}

DefaultExample.title = title

export default DefaultExample
61 changes: 43 additions & 18 deletions src/createCollapsibleTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ const createCollapsibleTabs = <T extends ParamList>() => {
initialTabName,
containerRef,
headerHeight: initialHeaderHeight,
minHeaderHeight = 0,
tabBarHeight: initialTabBarHeight = TABBAR_HEIGHT,
snapEnabled = false,
diffClampEnabled = false,
Expand Down Expand Up @@ -213,6 +214,9 @@ const createCollapsibleTabs = <T extends ParamList>() => {
const isGliding = useSharedValue(false)
const endDrag = useSharedValue(0)
const calculateNextOffset = useSharedValue(index.value)
const headerScrollDistance = useDerivedValue(() => {
return headerHeight !== undefined ? headerHeight - minHeaderHeight : 0
}, [headerHeight, minHeaderHeight])

const getItemLayout = React.useCallback(
(_: unknown, index: number) => ({
Expand Down Expand Up @@ -313,9 +317,13 @@ const createCollapsibleTabs = <T extends ParamList>() => {
accDiffClamp.value = 0
} else {
const nextValue = accDiffClamp.value + delta

if (delta > 0) {
// scrolling down
accDiffClamp.value = Math.min(headerHeight || 0, nextValue)
accDiffClamp.value = Math.min(
headerScrollDistance.value,
nextValue
)
} else if (delta < 0) {
// scrolling up
accDiffClamp.value = Math.max(0, nextValue)
Expand Down Expand Up @@ -353,11 +361,11 @@ const createCollapsibleTabs = <T extends ParamList>() => {
{
translateY: diffClampEnabled
? -accDiffClamp.value
: -Math.min(scrollYCurrent.value, headerHeight || 0),
: -Math.min(scrollYCurrent.value, headerScrollDistance.value),
},
],
}
}, [diffClampEnabled, headerHeight])
}, [diffClampEnabled])

const getHeaderHeight = React.useCallback(
(event: LayoutChangeEvent) => {
Expand Down Expand Up @@ -476,6 +484,7 @@ const createCollapsibleTabs = <T extends ParamList>() => {
snapEnabled,
tabBarHeight: tabBarHeight || 0,
headerHeight: headerHeight || 0,
headerScrollDistance,
refMap,
scrollYCurrent,
tabNames,
Expand Down Expand Up @@ -648,6 +657,7 @@ const createCollapsibleTabs = <T extends ParamList>() => {
index,
scrollYCurrent,
headerHeight,
headerScrollDistance,
isGliding,
isSnapping,
snappingTo,
Expand All @@ -662,19 +672,26 @@ const createCollapsibleTabs = <T extends ParamList>() => {
'worklet'
if (snapEnabled) {
if (diffClampEnabled && accDiffClamp.value > 0) {
if (scrollYCurrent.value > headerHeight) {
if (accDiffClamp.value <= headerHeight * snapThreshold) {
if (scrollYCurrent.value > headerScrollDistance.value) {
if (
accDiffClamp.value <=
headerScrollDistance.value * snapThreshold
) {
// snap down
isSnapping.value = true
accDiffClamp.value = withTiming(0, undefined, () => {
isSnapping.value = false
})
} else if (accDiffClamp.value < headerHeight) {
} else if (accDiffClamp.value < headerScrollDistance.value) {
// snap up
isSnapping.value = true
accDiffClamp.value = withTiming(headerHeight, undefined, () => {
isSnapping.value = false
})
accDiffClamp.value = withTiming(
headerScrollDistance.value,
undefined,
() => {
isSnapping.value = false
}
)
}
} else {
isSnapping.value = true
Expand All @@ -683,16 +700,19 @@ const createCollapsibleTabs = <T extends ParamList>() => {
})
}
} else {
if (scrollYCurrent.value <= headerHeight * snapThreshold) {
if (
scrollYCurrent.value <=
headerScrollDistance.value * snapThreshold
) {
// snap down
snappingTo.value = 0
// @ts-ignore
scrollTo(refMap[name], 0, 0, true)
} else if (scrollYCurrent.value <= headerHeight) {
} else if (scrollYCurrent.value <= headerScrollDistance.value) {
// snap up
snappingTo.value = headerHeight
snappingTo.value = headerScrollDistance.value
// @ts-ignore
scrollTo(refMap[name], 0, headerHeight, true)
scrollTo(refMap[name], 0, headerScrollDistance.value, true)
}
isSnapping.value = false
}
Expand Down Expand Up @@ -750,7 +770,7 @@ const createCollapsibleTabs = <T extends ParamList>() => {
},
onMomentumEnd,
},
[headerHeight, name, diffClampEnabled, snapEnabled]
[name, diffClampEnabled, snapEnabled]
)

// sync unfocused scenes
Expand All @@ -766,8 +786,10 @@ const createCollapsibleTabs = <T extends ParamList>() => {
const areEqual = focusedScrollY === tabScrollY

if (!areEqual) {
const currIsOnTop = tabScrollY <= headerHeight + 1
const focusedIsOnTop = focusedScrollY <= headerHeight + 1
const currIsOnTop = tabScrollY <= headerScrollDistance.value + 1
const focusedIsOnTop =
focusedScrollY <= headerScrollDistance.value + 1

if (diffClampEnabled) {
const hasGap = accDiffClamp.value > tabScrollY
if (hasGap || currIsOnTop) {
Expand All @@ -780,7 +802,10 @@ const createCollapsibleTabs = <T extends ParamList>() => {
nextPosition = headerHeight
}
} else if (currIsOnTop || focusedIsOnTop) {
nextPosition = Math.min(focusedScrollY, headerHeight)
nextPosition = Math.min(
focusedScrollY,
headerScrollDistance.value
)
}
}

Expand All @@ -791,7 +816,7 @@ const createCollapsibleTabs = <T extends ParamList>() => {
}
}
},
[diffClampEnabled, snapEnabled, headerHeight]
[diffClampEnabled, snapEnabled]
)

return scrollHandler
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export type CollapsibleProps<T extends ParamList> = {
* Is optional, but will optimize the first render.
*/
tabBarHeight?: number
/**
* Header minimum height when collapsed
*/
minHeaderHeight?: number
snapEnabled?: boolean
diffClampEnabled?: boolean
/**
Expand Down Expand Up @@ -93,6 +97,7 @@ export type CollapsibleProps<T extends ParamList> = {

export type ContextType<T extends ParamList> = {
headerHeight: number
headerScrollDistance: Animated.SharedValue<number>
tabBarHeight: number
snapEnabled: boolean
diffClampEnabled: boolean
Expand Down

0 comments on commit 0036da3

Please sign in to comment.