mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at remove-preload 147 lines 3.6 kB view raw
1import React, {createRef, useState, useMemo, useRef} from 'react' 2import {Animated, Pressable, StyleSheet, View} from 'react-native' 3import {Text} from './text/Text' 4import {usePalette} from 'lib/hooks/usePalette' 5import {useLingui} from '@lingui/react' 6import {msg} from '@lingui/macro' 7 8interface Layout { 9 x: number 10 width: number 11} 12 13export function Selector({ 14 selectedIndex, 15 items, 16 panX, 17 onSelect, 18}: { 19 selectedIndex: number 20 items: string[] 21 panX: Animated.Value 22 onSelect?: (index: number) => void 23}) { 24 const {_} = useLingui() 25 const containerRef = useRef<View>(null) 26 const pal = usePalette('default') 27 const [itemLayouts, setItemLayouts] = useState<undefined | Layout[]>( 28 undefined, 29 ) 30 const itemRefs = useMemo( 31 () => Array.from({length: items.length}).map(() => createRef<View>()), 32 [items.length], 33 ) 34 35 const currentLayouts = useMemo(() => { 36 const left = itemLayouts?.[selectedIndex - 1] || {x: 0, width: 0} 37 const middle = itemLayouts?.[selectedIndex] || {x: 0, width: 0} 38 const right = itemLayouts?.[selectedIndex + 1] || { 39 x: middle.x + 20, 40 width: middle.width, 41 } 42 return [left, middle, right] 43 }, [selectedIndex, itemLayouts]) 44 45 const underlineStyle = { 46 backgroundColor: pal.colors.text, 47 left: panX.interpolate({ 48 inputRange: [-1, 0, 1], 49 outputRange: [ 50 currentLayouts[0].x, 51 currentLayouts[1].x, 52 currentLayouts[2].x, 53 ], 54 }), 55 width: panX.interpolate({ 56 inputRange: [-1, 0, 1], 57 outputRange: [ 58 currentLayouts[0].width, 59 currentLayouts[1].width, 60 currentLayouts[2].width, 61 ], 62 }), 63 } 64 65 const onLayout = () => { 66 const promises = [] 67 for (let i = 0; i < items.length; i++) { 68 promises.push( 69 new Promise<Layout>(resolve => { 70 if (!containerRef.current || !itemRefs[i].current) { 71 return resolve({x: 0, width: 0}) 72 } 73 itemRefs[i].current?.measureLayout( 74 containerRef.current, 75 (x: number, _y: number, width: number) => { 76 resolve({x, width}) 77 }, 78 ) 79 }), 80 ) 81 } 82 Promise.all(promises).then((layouts: Layout[]) => { 83 setItemLayouts(layouts) 84 }) 85 } 86 87 const onPressItem = (index: number) => { 88 onSelect?.(index) 89 } 90 91 const numItems = items.length 92 93 return ( 94 <View 95 style={[pal.view, styles.outer]} 96 onLayout={onLayout} 97 ref={containerRef}> 98 <Animated.View style={[styles.underline, underlineStyle]} /> 99 {items.map((item, i) => { 100 const selected = i === selectedIndex 101 return ( 102 <Pressable 103 testID={`selector-${i}`} 104 key={item} 105 onPress={() => onPressItem(i)} 106 accessibilityLabel={_(msg`Select ${item}`)} 107 accessibilityHint={_(msg`Select option ${i} of ${numItems}`)}> 108 <View style={styles.item} ref={itemRefs[i]}> 109 <Text 110 style={ 111 selected 112 ? [styles.labelSelected, pal.text] 113 : [styles.label, pal.textLight] 114 }> 115 {item} 116 </Text> 117 </View> 118 </Pressable> 119 ) 120 })} 121 </View> 122 ) 123} 124 125const styles = StyleSheet.create({ 126 outer: { 127 flexDirection: 'row', 128 paddingTop: 8, 129 paddingBottom: 12, 130 paddingHorizontal: 14, 131 }, 132 item: { 133 marginRight: 14, 134 paddingHorizontal: 10, 135 }, 136 label: { 137 fontWeight: '600', 138 }, 139 labelSelected: { 140 fontWeight: '600', 141 }, 142 underline: { 143 position: 'absolute', 144 height: 4, 145 bottom: 0, 146 }, 147})