import React, { forwardRef, useImperativeHandle, useRef, useMemo } from 'react'; import { View, Pressable, Text, StyleSheet, TextStyle } from 'react-native'; import Pop, { PopoverPlacement } from 'react-native-popover-view'; import { useThemeFactory } from '../Theme'; import TouchableOpacity from '../TouchableOpacity'; import type { PopoverInstance, PopoverProps, PopoverAction } from './type'; import { createStyle } from './style'; const PlacementMap: Record['placement'], PopoverPlacement> = { auto: PopoverPlacement.AUTO, top: PopoverPlacement.TOP, bottom: PopoverPlacement.BOTTOM, left: PopoverPlacement.LEFT, right: PopoverPlacement.RIGHT, center: PopoverPlacement.CENTER, floating: PopoverPlacement.FLOATING, }; const Popover = forwardRef((props, ref) => { const { children, reference, duration = 300, placement = 'auto', theme = 'light', closeOnClickAction = true, closeOnClickOverlay = true, actions = [], } = props; const { styles, theme: globalTheme } = useThemeFactory(createStyle, theme); const touchable = useRef(null); const [visible, setVisible] = React.useState(false); const actionActiveBackgroundColor = theme === 'light' ? globalTheme.active_color : 'rgba(0, 0, 0, 0.2)'; const openPopover = () => setVisible(true); const closePopover = () => setVisible(false); const handleClose = () => { props.onClickOverlay?.(); closeOnClickOverlay && closePopover(); }; const handlePressAction = (action: PopoverAction, index: number) => { props.onSelect?.(action, index); closeOnClickAction && closePopover(); }; useImperativeHandle(ref, () => ({ show: () => openPopover(), hide: () => closePopover(), })); const arrowSize = useMemo( () => ({ width: globalTheme.popover_arrow_size * 2, height: globalTheme.popover_arrow_size, }), [globalTheme.popover_arrow_size] ); const renderAction = (action: PopoverAction, index: number) => { const { icon, text, color, disabled, style: actionStyle } = action; const actionTextStyle: TextStyle = StyleSheet.flatten(styles.actionText); const disabledActionTextStyle: TextStyle = StyleSheet.flatten(styles.disabledActionText); const textColor = color || (disabled ? disabledActionTextStyle.color : actionTextStyle.color); return ( handlePressAction(action, index)} activeBackgroundColor={actionActiveBackgroundColor} > 0 && styles.actionBorder]}> {icon && ( {React.cloneElement(icon as React.ReactElement, { color: textColor, size: globalTheme.popover_action_icon_size, })} )} {text} ); }; return ( <> {React.isValidElement(reference) ? React.cloneElement(reference, { onPress: openPopover }) : reference} {children || actions.map(renderAction)} ); }); export default Popover;