-
Notifications
You must be signed in to change notification settings - Fork 1
/
SelectBreakpoint.tsx
106 lines (94 loc) · 3.02 KB
/
SelectBreakpoint.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import React, { useEffect, useRef } from 'react'
import { View, TouchableOpacity, Text, Animated, Easing, ViewProps } from 'react-native'
import { useResponsive, getBreakpoints, Styled, getValue, Breakpoints } from './index'
const Wrapper = Styled(View, {
flexDirection: 'row',
alignItems: 'center',
height: 24,
})
const Button = Styled(TouchableOpacity, {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
height: '100%',
})
const Cursor = Styled(Animated.View, {
position: 'absolute',
height: '100%',
borderRadius: 10,
})
const getPosition = (index: number, length: number) => (100 / length) * index // (index + 1) * 20 + index * 60 - 5
const capitalizeFirstLetter = (value: string) => value.charAt(0).toUpperCase() + value.slice(1)
const textStyle = (active: boolean, index: number, fontSize: number) => {
return {
fontSize: getValue(fontSize + index * 2),
color: active ? '#FFFFFF' : '#000000',
}
}
const animate = (handle: Animated.Value, toValue: number) =>
Animated.timing(handle, {
toValue,
easing: Easing.ease,
useNativeDriver: false,
duration: 300,
}).start()
type Props = {
onChange?: (value: keyof Breakpoints) => void
waitForAnimation?: boolean
color?: string
fontSize?: number
labels?: { [key: string]: string }
}
export const SelectBreakpoint = ({
onChange,
waitForAnimation = false,
color = 'red',
fontSize = 12,
labels = {},
...props
}: Props & ViewProps) => {
const breakpoints = getBreakpoints()
const breakpointKeys = Object.keys(breakpoints) as (keyof Breakpoints)[]
const { breakpoint, setBreakpoint } = useResponsive()
const currentIndex = Object.keys(breakpoints).findIndex((current) => current === String(breakpoint))
const breakpointCount = Object.keys(breakpoints).length
const currentPosition = getPosition(currentIndex, breakpointCount)
const position = useRef(new Animated.Value(currentPosition)).current
const animatedPosition = position.interpolate({
inputRange: [0, 100],
outputRange: ['0%', '100%'],
})
useEffect(() => {
// Trigger animation if breakpoint is changed from outside.
// @ts-ignore
if (position._value !== currentPosition) {
animate(position, currentPosition)
}
}, [breakpoint, currentPosition, position])
return (
<Wrapper {...props}>
<Cursor style={[{ backgroundColor: color, width: `${100 / breakpointCount}%` }, { left: animatedPosition }]} />
{breakpointKeys.map((key, index) => (
<Button
key={key}
onPress={() => {
animate(position, getPosition(index, Object.keys(breakpoints).length))
setTimeout(
() => {
setBreakpoint(key)
if (onChange) {
onChange(key)
}
},
waitForAnimation ? 300 : 0,
)
}}
>
<Text style={textStyle(key === breakpoint, index, fontSize)}>
{labels[key] ?? capitalizeFirstLetter(key)}
</Text>
</Button>
))}
</Wrapper>
)
}