Skip to content

Commit

Permalink
feat: added RTL support
Browse files Browse the repository at this point in the history
  • Loading branch information
tsdmrfth committed Apr 10, 2021
1 parent 4dd5548 commit 45605fa
Showing 1 changed file with 63 additions and 23 deletions.
86 changes: 63 additions & 23 deletions src/Steve.js
Expand Up @@ -2,22 +2,37 @@ import React, { useRef, useState } from 'react'
import Animated, {
useAnimatedGestureHandler,
useSharedValue,
withDecay,
withSpring,
cancelAnimation,
useAnimatedStyle
useAnimatedStyle,
withDecay
} from 'react-native-reanimated'
import { Dimensions } from 'react-native'
import { PanGestureHandler } from 'react-native-gesture-handler'

const { width: screenWidth } = Dimensions.get('window')
const containerPaddingHorizontal = 10

export const Steve = ({ data, renderItem, keyExtractor, containerStyle }) => {
const getContainerHorizontalSpacing = style => {
const {
margin = 0,
marginHorizontal = 0,
marginLeft = 0,
marginRight = 0,
padding = 0,
paddingHorizontal = 0,
paddingLeft = 0,
paddingRight = 0
} = style || {}
return 2 * (margin + marginHorizontal + padding + paddingHorizontal)
+ (marginLeft + marginRight + paddingLeft + paddingRight)
}

export const Steve = ({ data, renderItem, keyExtractor, containerStyle, isRTL, itemStyle }) => {
const itemLayoutsCache = useRef({})
const [itemLayouts, setItemLayouts] = useState({})
const containerHorizontalSpacing = getContainerHorizontalSpacing(containerStyle)
const translateX = useSharedValue(0)
const paddingHorizontal = containerStyle?.paddingHorizontal || containerPaddingHorizontal
const rtlStyle = isRTL ? { flexDirection: 'row-reverse' } : {}
const onGestureEvent = useAnimatedGestureHandler({
onStart: (event, context) => {
if (context.isDecayAnimationRunning) {
Expand All @@ -32,18 +47,21 @@ export const Steve = ({ data, renderItem, keyExtractor, containerStyle }) => {
context.offset = translateX.value
const { offset } = context
const { velocityX } = event
const maxLevelDifference = screenWidth - Math.max(...Object.values(itemLayouts.sumWidthOfLayer))
const maximumLayerWidth = Math.max(...Object.values(itemLayouts.sumWidthOfLayer))
const levelDifference = screenWidth - maximumLayerWidth - containerHorizontalSpacing
const leftBound = 0
const rightBound = maxLevelDifference - paddingHorizontal
const rightBound = isRTL ? -levelDifference : levelDifference
const firstCondition = isRTL ? (offset < leftBound) : (offset > leftBound)
const secondCondition = isRTL ? (offset > rightBound) : (offset < rightBound)

if (offset > leftBound) {
if (firstCondition) {
context.offset = leftBound
translateX.value = withSpring(leftBound, {
velocity: velocityX,
mass: 0.6,
stiffness: 90
})
} else if (offset < rightBound) {
} else if (secondCondition) {
context.offset = rightBound
translateX.value = withSpring(rightBound, {
velocity: velocityX,
Expand All @@ -52,10 +70,26 @@ export const Steve = ({ data, renderItem, keyExtractor, containerStyle }) => {
})
} else {
context.isDecayAnimationRunning = true
let clamp

if (isRTL) {
if (velocityX < 0) {
clamp = [0, translateX.value]
} else {
clamp = [translateX.value, rightBound]
}
} else {
if (velocityX < 0) {
clamp = [rightBound, translateX.value]
} else {
clamp = [translateX.value, 0]
}
}

translateX.value = withDecay(
{
velocity: velocityX,
clamp: velocityX < 0 ? [rightBound, translateX.value] : [translateX.value, 0]
clamp
},
() => {
context.isDecayAnimationRunning = false
Expand Down Expand Up @@ -103,7 +137,7 @@ export const Steve = ({ data, renderItem, keyExtractor, containerStyle }) => {

return (
<Animated.View
{...{ style }}
style={[style, itemStyle]}
onLayout={event => handleItemLayout(event, itemKey)}>
{renderItem({ item, index })}
</Animated.View>
Expand All @@ -121,9 +155,20 @@ export const Steve = ({ data, renderItem, keyExtractor, containerStyle }) => {
}

const finalizeLayoutSetUp = () => {
let spacingBetweenItems = 0
itemLayoutsCache.current = Object
.values(itemLayoutsCache.current)
.reduce((accumulator, current) => {
.reduce((accumulator, current, index) => {
if (index === 0) {
const firstIndex = isRTL ? 1 : 0
const secondIndex = isRTL ? 0 : 1
const firstKey = keyExtractor(data[firstIndex], firstIndex)
const secondKey = keyExtractor(data[secondIndex], secondIndex)
const firstItem = itemLayoutsCache.current[firstKey]
const secondItem = itemLayoutsCache.current[secondKey]
spacingBetweenItems = secondItem.layout.x - firstItem.layout.width - firstItem.layout.x
}

if (!accumulator.sumWidthOfLayer) {
accumulator.sumWidthOfLayer = {}
}
Expand All @@ -132,22 +177,18 @@ export const Steve = ({ data, renderItem, keyExtractor, containerStyle }) => {
accumulator.sumWidthOfLayer[current.layout.y] = 0
}

const tempMax = accumulator.sumWidthOfLayer[current.layout.y]
const maybeMax = current.layout.x + current.layout.width

if (maybeMax > tempMax) {
accumulator.sumWidthOfLayer[current.layout.y] = maybeMax
}

accumulator.sumWidthOfLayer[current.layout.y] += current.layout.width + spacingBetweenItems
return accumulator
}, itemLayoutsCache.current)
setItemLayouts(itemLayoutsCache.current)
}

return (
<PanGestureHandler {...{ onGestureEvent }}>
<Animated.View style={[styles.container, containerStyle]}>
<Items/>
<Animated.View style={rtlStyle}>
<Animated.View style={[styles.container, containerStyle, rtlStyle]}>
<Items/>
</Animated.View>
</Animated.View>
</PanGestureHandler>
)
Expand All @@ -157,8 +198,7 @@ const styles = {
container: {
flexWrap: 'wrap',
flexDirection: 'row',
width: screenWidth * 1.8,
paddingHorizontal: containerPaddingHorizontal
width: screenWidth * 1.8
}
}

Expand Down

0 comments on commit 45605fa

Please sign in to comment.