import React, { forwardRef, useImperativeHandle, useRef, ReactElement, ComponentType, ReactNode } from 'react'; import { SheetSize, SizeInfo, TrueSheet, TrueSheetProps } from '@lodev09/react-native-true-sheet'; import { Keyboard, StyleSheet, View, TouchableOpacity, Platform, GestureResponderEvent, Text } from 'react-native'; import Ionicons from 'react-native-vector-icons/Ionicons'; import SaveFileButton from './SaveFileButton'; import { useTheme } from './themes'; import { Image } from '@rneui/base'; interface BottomModalProps extends TrueSheetProps { children?: React.ReactNode; onClose?: () => void; onCloseModalPressed?: () => Promise; isGrabberVisible?: boolean; sizes?: SheetSize[] | undefined; footer?: ReactElement | ComponentType | null; footerDefaultMargins?: boolean | number; onPresent?: () => void; onSizeChange?: (size: SizeInfo) => void; showCloseButton?: boolean; shareContent?: BottomModalShareContent; shareButtonOnPress?: (event: GestureResponderEvent) => void; header?: ReactElement | ComponentType | null; headerTitle?: string; headerSubtitle?: string; } type BottomModalShareContent = { fileName: string; fileContent: string; }; export interface BottomModalHandle { present: () => Promise; dismiss: () => Promise; } const BottomModal = forwardRef( ( { onClose, onCloseModalPressed, onPresent, onSizeChange, showCloseButton = true, isGrabberVisible = true, shareContent, shareButtonOnPress, sizes = ['auto'], footer, footerDefaultMargins, header, headerTitle, headerSubtitle, children, ...props }, ref, ) => { const trueSheetRef = useRef(null); const { colors } = useTheme(); const stylesHook = StyleSheet.create({ barButton: { backgroundColor: colors.lightButton, }, headerTitle: { color: colors.foregroundColor, }, }); useImperativeHandle(ref, () => ({ present: async () => { Keyboard.dismiss(); if (trueSheetRef.current?.present) { await trueSheetRef.current.present(); } else { return Promise.resolve(); } }, dismiss: async () => { Keyboard.dismiss(); if (trueSheetRef.current?.dismiss) { await trueSheetRef.current.dismiss(); } else { return Promise.resolve(); } }, })); const dismiss = async () => { try { await onCloseModalPressed?.(); await trueSheetRef.current?.dismiss(); } catch (error) { console.error('Error during dismiss:', error); } }; const renderTopRightButton = () => { const buttons = []; if (shareContent || shareButtonOnPress) { if (shareContent) { buttons.push( , ); } else if (shareButtonOnPress) { buttons.push( , ); } } if (showCloseButton) { buttons.push( {Platform.OS === 'ios' ? ( ) : ( )} , ); } return {buttons}; }; const renderHeader = () => { if (headerTitle || headerSubtitle) { return ( {headerTitle && {headerTitle}} {headerSubtitle && {headerSubtitle}} {renderTopRightButton()} ); } return ( {typeof header === 'function' ?
: header} {renderTopRightButton()} ); }; const renderFooter = (): ReactElement | undefined => { // Footer is not working correctly on Android yet. if (!footer) return undefined; if (React.isValidElement(footer)) { return footerDefaultMargins ? {footer} : footer; } else if (typeof footer === 'function') { const ModalFooterComponent = footer as ComponentType; return ; } return undefined; }; const FooterComponent = Platform.OS !== 'android' && renderFooter(); return ( {children} {Platform.OS === 'android' && (renderFooter() as ReactNode)} {renderHeader()} ); }, ); export default BottomModal; const styles = StyleSheet.create({ footerContainer: { alignItems: 'center', justifyContent: 'center', }, headerContainer: { position: 'absolute', flexDirection: 'row', alignItems: 'center', paddingVertical: 8, minHeight: 22, right: 16, top: 16, }, headerContent: { flex: 1, justifyContent: 'center', minHeight: 22, }, headerTitle: { fontSize: 18, fontWeight: 'bold', }, closeButton: { width: 10, height: 10, }, headerSubtitle: { fontSize: 14, }, topRightButton: { justifyContent: 'center', alignItems: 'center', width: 30, height: 30, borderRadius: 15, marginLeft: 22, }, topRightButtonContainer: { flexDirection: 'row', alignItems: 'center', }, childrenContainer: { paddingTop: 66, paddingHorizontal: 16, width: '100%', }, });