BlueWallet/components/BottomModal.tsx

128 lines
3.5 KiB
TypeScript
Raw Normal View History

2024-07-06 16:58:42 -04:00
import React, { forwardRef, useImperativeHandle, useRef, ReactElement, ComponentType, JSXElementConstructor, ReactNode } from 'react';
2024-07-02 10:41:17 -04:00
import { SheetSize, SizeInfo, TrueSheet, TrueSheetProps } from '@lodev09/react-native-true-sheet';
2024-07-06 16:58:42 -04:00
import { Keyboard, StyleSheet, View, TouchableOpacity, Platform, Image } from 'react-native';
2024-05-20 10:54:13 +01:00
2024-06-30 13:17:55 -04:00
interface BottomModalProps extends TrueSheetProps {
2024-02-10 00:35:24 -04:00
children?: React.ReactNode;
2024-06-30 13:17:55 -04:00
onClose?: () => void;
isGrabberVisible?: boolean;
2024-06-30 18:27:37 -04:00
sizes?: SheetSize[] | undefined;
2024-08-02 13:08:14 -04:00
footer?: ReactElement | ComponentType<any> | null;
2024-07-01 12:58:19 -04:00
footerDefaultMargins?: boolean | number;
2024-07-02 10:41:17 -04:00
onPresent?: () => void;
onSizeChange?: (size: SizeInfo) => void;
2024-07-06 16:58:42 -04:00
showCloseButton?: boolean;
2024-02-10 00:35:24 -04:00
}
2024-06-30 13:17:55 -04:00
export interface BottomModalHandle {
present: () => Promise<void>;
dismiss: () => Promise<void>;
}
2024-07-06 16:58:42 -04:00
const styles = StyleSheet.create({
footerContainer: {
alignItems: 'center',
justifyContent: 'center',
},
buttonContainer: {
position: 'absolute',
backgroundColor: 'lightgray',
justifyContent: 'center',
alignItems: 'center',
2024-07-11 21:39:05 -04:00
width: 30,
height: 30,
borderRadius: 15,
2024-07-06 16:58:42 -04:00
top: 20,
right: 20,
zIndex: 10,
},
});
2024-06-30 13:17:55 -04:00
const BottomModal = forwardRef<BottomModalHandle, BottomModalProps>(
2024-07-01 12:58:19 -04:00
(
2024-07-06 16:58:42 -04:00
{
onClose,
onPresent,
onSizeChange,
showCloseButton = true,
isGrabberVisible = true,
sizes = ['auto'],
footer,
footerDefaultMargins,
children,
...props
},
2024-07-01 12:58:19 -04:00
ref,
) => {
2024-06-30 13:17:55 -04:00
const trueSheetRef = useRef<TrueSheet>(null);
2024-02-10 00:35:24 -04:00
2024-06-30 13:17:55 -04:00
useImperativeHandle(ref, () => ({
present: async () => {
2024-07-04 15:55:58 -04:00
Keyboard.dismiss();
2024-06-30 13:17:55 -04:00
if (trueSheetRef.current?.present) {
await trueSheetRef.current.present();
} else {
return Promise.resolve();
}
},
dismiss: async () => {
2024-07-04 15:55:58 -04:00
Keyboard.dismiss();
2024-06-30 13:17:55 -04:00
if (trueSheetRef.current?.dismiss) {
await trueSheetRef.current.dismiss();
} else {
return Promise.resolve();
}
},
}));
2024-07-06 16:58:42 -04:00
const dismiss = () => {
trueSheetRef.current?.dismiss();
};
const renderTopRightButton = () =>
showCloseButton ? (
2024-07-14 10:03:29 -04:00
<TouchableOpacity style={styles.buttonContainer} onPress={dismiss} testID="ModalDoneButton">
2024-07-06 16:58:42 -04:00
<Image source={require('../img/close.png')} width={20} height={20} />
</TouchableOpacity>
) : null;
const renderFooter = (): ReactElement<any, string | JSXElementConstructor<any>> | ComponentType<unknown> | undefined => {
// Footer is not working correctly on Android yet.
if (!footer) return undefined;
2024-07-01 12:58:19 -04:00
if (React.isValidElement(footer)) {
2024-07-06 16:58:42 -04:00
return footerDefaultMargins ? <View style={styles.footerContainer}>{footer}</View> : footer;
} else if (typeof footer === 'function') {
// Render the footer component dynamically
const FooterComponent = footer as ComponentType<any>;
return <FooterComponent />;
2024-07-01 12:58:19 -04:00
}
2024-07-06 16:58:42 -04:00
return undefined;
};
2024-07-01 12:58:19 -04:00
2024-07-06 17:55:03 -04:00
const FooterComponent = Platform.OS !== 'android' && renderFooter();
2024-06-30 13:17:55 -04:00
return (
<TrueSheet
ref={trueSheetRef}
cornerRadius={24}
2024-06-30 18:27:37 -04:00
sizes={sizes}
2024-06-30 13:17:55 -04:00
onDismiss={onClose}
onPresent={onPresent}
onSizeChange={onSizeChange}
grabber={isGrabberVisible}
2024-07-06 17:55:03 -04:00
// Footer is not working correctly on Android yet.
FooterComponent={FooterComponent as ReactElement}
2024-06-30 13:17:55 -04:00
{...props}
>
{children}
2024-07-06 16:58:42 -04:00
{renderTopRightButton()}
2024-07-06 17:55:03 -04:00
{Platform.OS === 'android' && (renderFooter() as ReactNode)}
2024-06-30 13:17:55 -04:00
</TrueSheet>
);
},
);
2020-11-17 11:43:38 +03:00
export default BottomModal;