import React, { forwardRef, useImperativeHandle, useRef, ReactElement, ComponentType } from 'react'; import { SheetSize, SizeInfo, TrueSheet, TrueSheetProps } from '@lodev09/react-native-true-sheet'; import { Keyboard, Image, StyleSheet, View, TouchableOpacity, Platform, GestureResponderEvent, Text } from 'react-native'; import SaveFileButton from './SaveFileButton'; import { useTheme } from './themes'; import { Icon } 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, closeImage } = 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( , ); } return {buttons}; }; const renderHeader = () => { if (headerTitle || headerSubtitle) { return ( {headerTitle && {headerTitle}} {headerSubtitle && {headerSubtitle}} {renderTopRightButton()} ); } if (showCloseButton || shareContent) return ( {typeof header === 'function' ?
: header} {renderTopRightButton()} ); if (React.isValidElement(header)) { return ( {header} {renderTopRightButton()} ); } return null; }; const renderFooter = (): ReactElement | undefined => { if (React.isValidElement(footer)) { return footerDefaultMargins ? {footer} : footer; } else if (typeof footer === 'function') { const ModalFooterComponent = footer as ComponentType; return ; } return undefined; }; const FooterComponent = renderFooter(); return ( {children} {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, }, headerContainerWithCloseButton: { position: 'absolute', flexDirection: 'row', alignItems: 'center', paddingVertical: 8, minHeight: 22, width: '100%', top: 16, left: 0, justifyContent: 'space-between', }, headerContent: { flex: 1, justifyContent: 'center', minHeight: 22, }, headerTitle: { fontSize: 18, fontWeight: 'bold', }, 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%', }, });