mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at samuel/exp-cli 175 lines 4.3 kB view raw
1import * as React from 'react' 2import { 3 Dimensions, 4 type LayoutChangeEvent, 5 type NativeSyntheticEvent, 6 Platform, 7 type StyleProp, 8 View, 9 type ViewStyle, 10} from 'react-native' 11import {useSafeAreaInsets} from 'react-native-safe-area-context' 12import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core' 13 14import {isIOS} from '#/platform/detection' 15import { 16 type BottomSheetState, 17 type BottomSheetViewProps, 18} from './BottomSheet.types' 19import {BottomSheetPortalProvider} from './BottomSheetPortal' 20import {Context as PortalContext} from './BottomSheetPortal' 21 22const screenHeight = Dimensions.get('screen').height 23 24const NativeView: React.ComponentType< 25 BottomSheetViewProps & { 26 ref: React.RefObject<any> 27 style: StyleProp<ViewStyle> 28 } 29> = requireNativeViewManager('BottomSheet') 30 31const NativeModule = requireNativeModule('BottomSheet') 32 33const isIOS15 = 34 Platform.OS === 'ios' && 35 // semvar - can be 3 segments, so can't use Number(Platform.Version) 36 Number(Platform.Version.split('.').at(0)) < 16 37 38export class BottomSheetNativeComponent extends React.Component< 39 BottomSheetViewProps, 40 { 41 open: boolean 42 viewHeight?: number 43 } 44> { 45 ref = React.createRef<any>() 46 47 static contextType = PortalContext 48 49 constructor(props: BottomSheetViewProps) { 50 super(props) 51 this.state = { 52 open: false, 53 } 54 } 55 56 present() { 57 this.setState({open: true}) 58 } 59 60 dismiss() { 61 this.ref.current?.dismiss() 62 } 63 64 private onStateChange = ( 65 event: NativeSyntheticEvent<{state: BottomSheetState}>, 66 ) => { 67 const {state} = event.nativeEvent 68 const isOpen = state !== 'closed' 69 this.setState({open: isOpen}) 70 this.props.onStateChange?.(event) 71 } 72 73 private updateLayout = () => { 74 this.ref.current?.updateLayout() 75 } 76 77 static dismissAll = async () => { 78 await NativeModule.dismissAll() 79 } 80 81 render() { 82 const Portal = this.context as React.ContextType<typeof PortalContext> 83 if (!Portal) { 84 throw new Error( 85 'BottomSheet: You need to wrap your component tree with a <BottomSheetPortalProvider> to use the bottom sheet.', 86 ) 87 } 88 89 if (!this.state.open) { 90 return null 91 } 92 93 let extraStyles 94 if (isIOS15 && this.state.viewHeight) { 95 const {viewHeight} = this.state 96 const cornerRadius = this.props.cornerRadius ?? 0 97 if (viewHeight < screenHeight / 2) { 98 extraStyles = { 99 height: viewHeight, 100 marginTop: screenHeight / 2 - viewHeight, 101 borderTopLeftRadius: cornerRadius, 102 borderTopRightRadius: cornerRadius, 103 } 104 } 105 } 106 107 return ( 108 <Portal> 109 <BottomSheetNativeComponentInner 110 {...this.props} 111 nativeViewRef={this.ref} 112 onStateChange={this.onStateChange} 113 extraStyles={extraStyles} 114 onLayout={e => { 115 const {height} = e.nativeEvent.layout 116 this.setState({viewHeight: height}) 117 this.updateLayout() 118 }} 119 /> 120 </Portal> 121 ) 122 } 123} 124 125function BottomSheetNativeComponentInner({ 126 children, 127 backgroundColor, 128 onLayout, 129 onStateChange, 130 nativeViewRef, 131 extraStyles, 132 ...rest 133}: BottomSheetViewProps & { 134 extraStyles?: StyleProp<ViewStyle> 135 onStateChange: ( 136 event: NativeSyntheticEvent<{state: BottomSheetState}>, 137 ) => void 138 nativeViewRef: React.RefObject<View> 139 onLayout: (event: LayoutChangeEvent) => void 140}) { 141 const insets = useSafeAreaInsets() 142 const cornerRadius = rest.cornerRadius ?? 0 143 144 const sheetHeight = isIOS ? screenHeight - insets.top : screenHeight 145 146 return ( 147 <NativeView 148 {...rest} 149 onStateChange={onStateChange} 150 ref={nativeViewRef} 151 style={{ 152 position: 'absolute', 153 height: sheetHeight, 154 width: '100%', 155 }} 156 containerBackgroundColor={backgroundColor}> 157 <View 158 style={[ 159 { 160 flex: 1, 161 backgroundColor, 162 }, 163 Platform.OS === 'android' && { 164 borderTopLeftRadius: cornerRadius, 165 borderTopRightRadius: cornerRadius, 166 }, 167 extraStyles, 168 ]}> 169 <View onLayout={onLayout}> 170 <BottomSheetPortalProvider>{children}</BottomSheetPortalProvider> 171 </View> 172 </View> 173 </NativeView> 174 ) 175}