Skip to content

Instantly share code, notes, and snippets.

@vshkl
Created April 5, 2023 11:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vshkl/1e9c5793e288c892d13a689365ff3ab3 to your computer and use it in GitHub Desktop.
Save vshkl/1e9c5793e288c892d13a689365ff3ab3 to your computer and use it in GitHub Desktop.
Start date picker componetn | react-native, typescript, hooks
import React, { Ref, useCallback, useLayoutEffect, useMemo, useRef } from 'react'
import { FlatList, StyleSheet, View, type ViewToken } from 'react-native'
import { useLayout } from '@react-native-community/hooks'
import Label from 'components/atoms/Label'
import DateView, { ITEM_WIDTH } from 'components/molecules/DateView'
import { type DateWithName } from 'components/organisms/SelectIntervalModal'
const ITEM_INTER = 12
type StartDateSelectorNextProps = {
dates: DateWithName[],
initialDate: DateWithName,
onSelected: (date: DateWithName) => void,
}
const StartDateSelectorNext = ({
dates,
initialDate,
onSelected,
}: StartDateSelectorNextProps) => {
const { onLayout, ...layout } = useLayout()
const horizontalOffset = useMemo(() => {
return layout.width / 2 - ITEM_WIDTH / 2
}, [layout])
const contentStyle = useMemo(() => {
return {
paddingHorizontal: horizontalOffset,
}
}, [horizontalOffset])
const dividerStyle = useMemo(() => {
return {
width: ITEM_INTER,
}
}, [])
const viewabilityConfig = useMemo(() => {
return {
waitForInteraction: true,
viewAreaCoveragePercentThreshold: 100,
}
}, [])
const onViewableItemsChanged = useCallback((info: { viewableItems: ViewToken[] }): void => {
const visibleItems = info.viewableItems
const visibleItemsCount = visibleItems.length
const centerItem = visibleItems[Math.ceil(visibleItemsCount / 2 - 1)]
const centerData = dates[centerItem.index ?? 0]
onSelected(centerData)
}, [])
const listRef: Ref<FlatList> = useRef(null)
useLayoutEffect(() => {
setTimeout(() => {
if (listRef.current) {
listRef.current.scrollToOffset({
animated: false,
offset: (ITEM_WIDTH + ITEM_INTER) * dates.indexOf(initialDate),
})
}
}, 250)
}, [])
return (
<View onLayout={onLayout}>
<View style={styles.containerListTitle}>
<Label size='normal' weight='medium' color='primary'>
START DATE
</Label>
</View>
<View style={styles.containerList}>
<View style={styles.containerWindow} />
<FlatList
ref={listRef}
contentContainerStyle={contentStyle}
data={dates}
keyExtractor={(item: DateWithName) => item.date.toString()}
horizontal={true}
showsHorizontalScrollIndicator={false}
centerContent={true}
snapToInterval={ITEM_WIDTH + ITEM_INTER}
decelerationRate="fast"
renderItem={({ item }) => (
<DateView
dayNumber={item.dayNumber}
dayName={item.dayName}
month={item.month}
/>
)}
ItemSeparatorComponent={() => (
<View style={dividerStyle} />
)}
viewabilityConfig={viewabilityConfig}
onViewableItemsChanged={onViewableItemsChanged}
/>
</View>
</View>
)
}
const styles = StyleSheet.create({
containerListTitle: {
marginBottom: 10,
},
containerList: {
marginBottom: 20,
},
containerWindow: {
zIndex: 1,
position: 'absolute',
alignSelf: 'center',
width: ITEM_WIDTH + ITEM_INTER,
height: '100%',
borderWidth: 2,
borderColor: '#000000',
backgroundColor: '#0000001E',
borderRadius: 4,
},
})
export default StartDateSelectorNext
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment