2024-04-25 15:02:10 +02:00
|
|
|
import * as React from 'react';
|
|
|
|
import { useMemo } from 'react';
|
|
|
|
import { StyleSheet, View, ViewStyle, useWindowDimensions } from 'react-native';
|
|
|
|
import { IconButton, Surface } from 'react-native-paper';
|
|
|
|
import { themeStyle } from './global-style';
|
|
|
|
import Modal from './Modal';
|
|
|
|
import { _ } from '@joplin/lib/locale';
|
|
|
|
|
2024-06-04 10:57:52 +02:00
|
|
|
export enum DialogSize {
|
|
|
|
Small = 'small',
|
|
|
|
|
|
|
|
// Ideal for panels and dialogs that should be fullscreen even on large devices
|
|
|
|
Large = 'large',
|
|
|
|
}
|
|
|
|
|
2024-04-25 15:02:10 +02:00
|
|
|
interface Props {
|
|
|
|
themeId: number;
|
|
|
|
visible: boolean;
|
|
|
|
onDismiss: ()=> void;
|
|
|
|
containerStyle?: ViewStyle;
|
|
|
|
children: React.ReactNode;
|
2024-06-04 10:57:52 +02:00
|
|
|
|
|
|
|
size: DialogSize;
|
2024-04-25 15:02:10 +02:00
|
|
|
}
|
|
|
|
|
2024-06-04 10:57:52 +02:00
|
|
|
const useStyles = (themeId: number, containerStyle: ViewStyle, size: DialogSize) => {
|
2024-04-25 15:02:10 +02:00
|
|
|
const windowSize = useWindowDimensions();
|
|
|
|
|
|
|
|
return useMemo(() => {
|
|
|
|
const theme = themeStyle(themeId);
|
|
|
|
|
2024-06-04 10:57:52 +02:00
|
|
|
const maxWidth = size === DialogSize.Large ? Infinity : 500;
|
|
|
|
const maxHeight = size === DialogSize.Large ? Infinity : 700;
|
|
|
|
|
2024-04-25 15:02:10 +02:00
|
|
|
return StyleSheet.create({
|
|
|
|
webView: {
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
display: 'flex',
|
|
|
|
},
|
|
|
|
webViewContainer: {
|
|
|
|
flexGrow: 1,
|
|
|
|
flexShrink: 1,
|
|
|
|
},
|
|
|
|
closeButtonContainer: {
|
|
|
|
flexDirection: 'row',
|
|
|
|
justifyContent: 'flex-end',
|
|
|
|
},
|
|
|
|
dialog: {
|
|
|
|
backgroundColor: theme.backgroundColor,
|
|
|
|
borderRadius: 12,
|
|
|
|
padding: 10,
|
|
|
|
|
2024-06-04 10:57:52 +02:00
|
|
|
// Use Math.min with width and height -- the maxWidth and maxHeight style
|
|
|
|
// properties don't seem to limit the size for this.
|
|
|
|
height: Math.min(maxHeight, windowSize.height * 0.9),
|
|
|
|
width: Math.min(maxWidth, windowSize.width * 0.97),
|
2024-05-27 10:05:15 +02:00
|
|
|
flexShrink: 1,
|
2024-04-25 15:02:10 +02:00
|
|
|
|
|
|
|
// Center
|
|
|
|
marginLeft: 'auto',
|
|
|
|
marginRight: 'auto',
|
|
|
|
|
|
|
|
...containerStyle,
|
|
|
|
},
|
2024-05-27 10:05:15 +02:00
|
|
|
dialogContainer: {
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
flexGrow: 1,
|
|
|
|
},
|
2024-04-25 15:02:10 +02:00
|
|
|
});
|
2024-06-04 10:57:52 +02:00
|
|
|
}, [themeId, windowSize.width, windowSize.height, containerStyle, size]);
|
2024-04-25 15:02:10 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const DismissibleDialog: React.FC<Props> = props => {
|
2024-06-04 10:57:52 +02:00
|
|
|
const styles = useStyles(props.themeId, props.containerStyle, props.size);
|
2024-04-25 15:02:10 +02:00
|
|
|
|
|
|
|
const closeButton = (
|
|
|
|
<View style={styles.closeButtonContainer}>
|
|
|
|
<IconButton
|
|
|
|
icon='close'
|
|
|
|
accessibilityLabel={_('Close')}
|
|
|
|
onPress={props.onDismiss}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Modal
|
|
|
|
visible={props.visible}
|
|
|
|
onDismiss={props.onDismiss}
|
|
|
|
onRequestClose={props.onDismiss}
|
2024-05-27 10:05:15 +02:00
|
|
|
containerStyle={styles.dialogContainer}
|
2024-04-25 15:02:10 +02:00
|
|
|
animationType='fade'
|
2024-05-27 10:05:15 +02:00
|
|
|
backgroundColor='rgba(0, 0, 0, 0.1)'
|
2024-04-25 15:02:10 +02:00
|
|
|
transparent={true}
|
|
|
|
>
|
|
|
|
<Surface style={styles.dialog} elevation={1}>
|
|
|
|
{closeButton}
|
|
|
|
{props.children}
|
|
|
|
</Surface>
|
|
|
|
</Modal>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default DismissibleDialog;
|