mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at verify-code 186 lines 5.0 kB view raw
1/** 2 * In the Web build, we center all content so that it mirrors the 3 * mobile experience (a single narrow column). We then place a UI 4 * shell around the content if you're in desktop. 5 * 6 * Because scrolling is handled by components deep in the hierarchy, 7 * we can't just wrap the top-level element with a max width. The 8 * centering has to be done at the ScrollView. 9 * 10 * These components wrap the RN ScrollView-based components to provide 11 * consistent layout. It also provides <CenteredView> for views that 12 * need to match layout but which aren't scrolled. 13 */ 14 15import React from 'react' 16import { 17 FlatList, 18 FlatListProps, 19 ScrollViewProps, 20 StyleSheet, 21 View, 22 ViewProps, 23} from 'react-native' 24import Animated from 'react-native-reanimated' 25 26import {usePalette} from 'lib/hooks/usePalette' 27import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 28import {addStyle} from 'lib/styles' 29 30interface AddedProps { 31 desktopFixedHeight?: boolean | number 32} 33 34export const CenteredView = React.forwardRef(function CenteredView( 35 { 36 style, 37 sideBorders, 38 topBorder, 39 ...props 40 }: React.PropsWithChildren< 41 ViewProps & {sideBorders?: boolean; topBorder?: boolean} 42 >, 43 ref: React.Ref<View>, 44) { 45 const pal = usePalette('default') 46 const {isMobile} = useWebMediaQueries() 47 if (!isMobile) { 48 style = addStyle(style, styles.container) 49 } 50 if (sideBorders && !isMobile) { 51 style = addStyle(style, { 52 borderLeftWidth: StyleSheet.hairlineWidth, 53 borderRightWidth: StyleSheet.hairlineWidth, 54 }) 55 style = addStyle(style, pal.border) 56 } 57 if (topBorder) { 58 style = addStyle(style, { 59 borderTopWidth: 1, 60 }) 61 style = addStyle(style, pal.border) 62 } 63 return <View ref={ref} style={style} {...props} /> 64}) 65 66export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>( 67 { 68 contentContainerStyle, 69 style, 70 contentOffset, 71 desktopFixedHeight, 72 ...props 73 }: React.PropsWithChildren<FlatListProps<ItemT> & AddedProps>, 74 ref: React.Ref<FlatList<ItemT>>, 75) { 76 const pal = usePalette('default') 77 const {isMobile} = useWebMediaQueries() 78 if (!isMobile) { 79 contentContainerStyle = addStyle( 80 contentContainerStyle, 81 styles.containerScroll, 82 ) 83 } 84 if (contentOffset && contentOffset?.y !== 0) { 85 // NOTE 86 // we use paddingTop & contentOffset to space around the floating header 87 // but reactnative web puts the paddingTop on the wrong element (style instead of the contentContainer) 88 // so we manually correct it here 89 // -prf 90 style = addStyle(style, { 91 paddingTop: 0, 92 }) 93 contentContainerStyle = addStyle(contentContainerStyle, { 94 paddingTop: Math.abs(contentOffset.y), 95 }) 96 } 97 if (desktopFixedHeight) { 98 if (typeof desktopFixedHeight === 'number') { 99 // @ts-ignore Web only -prf 100 style = addStyle(style, { 101 height: `calc(100vh - ${desktopFixedHeight}px)`, 102 }) 103 } else { 104 style = addStyle(style, styles.fixedHeight) 105 } 106 if (!isMobile) { 107 // NOTE 108 // react native web produces *three* wrapping divs 109 // the first two use the `style` prop and the innermost uses the 110 // `contentContainerStyle`. Unfortunately the stable-gutter style 111 // needs to be applied to only the "middle" of these. To hack 112 // around this, we set data-stable-gutters which can then be 113 // styled in our external CSS. 114 // -prf 115 // @ts-ignore web only -prf 116 props.dataSet = props.dataSet || {} 117 // @ts-ignore web only -prf 118 props.dataSet.stableGutters = '1' 119 } 120 } 121 return ( 122 <Animated.FlatList 123 ref={ref} 124 contentContainerStyle={[ 125 styles.contentContainer, 126 contentContainerStyle, 127 pal.border, 128 ]} 129 style={style} 130 contentOffset={contentOffset} 131 {...props} 132 /> 133 ) 134}) 135 136export const ScrollView = React.forwardRef(function ScrollViewImpl( 137 {contentContainerStyle, ...props}: React.PropsWithChildren<ScrollViewProps>, 138 ref: React.Ref<Animated.ScrollView>, 139) { 140 const pal = usePalette('default') 141 142 const {isMobile} = useWebMediaQueries() 143 if (!isMobile) { 144 contentContainerStyle = addStyle( 145 contentContainerStyle, 146 styles.containerScroll, 147 ) 148 } 149 return ( 150 <Animated.ScrollView 151 contentContainerStyle={[ 152 styles.contentContainer, 153 contentContainerStyle, 154 pal.border, 155 ]} 156 // @ts-ignore something is wrong with the reanimated types -prf 157 ref={ref} 158 {...props} 159 /> 160 ) 161}) 162 163const styles = StyleSheet.create({ 164 contentContainer: { 165 borderLeftWidth: StyleSheet.hairlineWidth, 166 borderRightWidth: StyleSheet.hairlineWidth, 167 // @ts-ignore web only 168 minHeight: '100vh', 169 }, 170 container: { 171 width: '100%', 172 maxWidth: 600, 173 marginLeft: 'auto', 174 marginRight: 'auto', 175 }, 176 containerScroll: { 177 width: '100%', 178 maxWidth: 600, 179 marginLeft: 'auto', 180 marginRight: 'auto', 181 }, 182 fixedHeight: { 183 // @ts-ignore web only 184 height: '100vh', 185 }, 186})