import React from 'react' ; import { useOverlayPosition } from '@react-native-aria/overlays' ; import { StyleSheet , View , ViewStyle } from 'react-native' ; import type { IPopperProps , IScrollContentStyle , IArrowStyles , IPopoverArrowProps , } from './types' ; import { createContext } from '../../../utils' ; import Box , { IBoxProps } from '../../primitives/Box' ; import { useHasResponsiveProps } from '../../../hooks/useHasResponsiveProps' ; const defaultArrowHeight = 15 ; const defaultArrowWidth = 15 ; const getDiagonalLength = ( height , width ) => { return Math . pow ( height * height + width * width , 0.5 ) ; } ; type PopperContext = IPopperProps & { triggerRef : any ; onClose : any ; setOverlayRef ? : ( overlayRef : any ) => void ; } ; const [ PopperProvider , usePopperContext ] = createContext < PopperContext > ( 'PopperContext' ) ; const Popper = ( props ) => { return < PopperProvider { ... props } > { props . children } < /PopperProvider>; } ; const PopperContent = React . forwardRef ( ( { children , style , ... rest } , ref ) => { const { triggerRef , shouldFlip , crossOffset , offset , placement : placementProp , onClose , shouldOverlapWithTrigger , setOverlayRef , } = usePopperContext ( 'PopperContent' ) ; const overlayRef = React . useRef ( null ) ; const { overlayProps , rendered , arrowProps , placement , } = useOverlayPosition ( { targetRef : triggerRef , overlayRef , shouldFlip : shouldFlip , crossOffset : crossOffset , isOpen : true , offset : offset , placement : placementProp as any , containerPadding : 0 , onClose : onClose , shouldOverlapWithTrigger , } ) ; let restElements = [ ] ; let arrowElement = null ; React . useEffect ( ( ) => { setOverlayRef && setOverlayRef ( overlayRef ) ; } , [ overlayRef , setOverlayRef ] ) ; React . Children . forEach ( children , ( child ) => { if ( React . isValidElement ( child ) && child . type . displayName === 'PopperArrow' ) { arrowElement = React . cloneElement ( child , { arrowProps , actualPlacement : placement , } ) ; } else { restElements . push ( child ) ; } } ) ; let arrowHeight = 0 ; let arrowWidth = 0 ; if ( arrowElement ) { arrowHeight = defaultArrowHeight ; arrowWidth = defaultArrowWidth ; if ( arrowElement . props . height ) { arrowHeight = arrowElement . props . height ; } if ( arrowElement . props . width ) { arrowWidth = arrowElement . props . width ; } } const containerStyle = React . useMemo ( ( ) => getContainerStyle ( { placement , arrowHeight , arrowWidth , } ) , [ arrowHeight , arrowWidth , placement ] ) ; const overlayStyle = React . useMemo ( ( ) => StyleSheet . create ( { overlay : { ... overlayProps . style , opacity : rendered ? 1 : 0 , position : 'absolute' , } , } ) , [ rendered , overlayProps . style ] ) ; if ( useHasResponsiveProps ( rest ) ) { return null ; } return ( < View ref = { overlayRef } collapsable = { false } style = { overlayStyle . overlay } > { arrowElement } < Box style = { StyleSheet . flatten ( [ containerStyle , style ] ) } { ... rest } ref = { ref } > { restElements } < /Box> < /View>); } ) ; const PopperArrow = React . forwardRef ( ( { height = defaultArrowHeight , width = defaultArrowWidth , arrowProps , actualPlacement , style , borderColor = '#52525b' , backgroundColor = 'black' , ... rest } , ref ) => { const additionalStyles = React . useMemo ( ( ) => getArrowStyles ( { placement : actualPlacement , height , width } ) , [ actualPlacement , height , width ] ) ; let triangleStyle = React . useMemo ( ( ) => ( { position : 'absolute' , width , height , } ) , [ width , height ] ) ; let arrowStyles = React . useMemo ( ( ) => [ arrowProps . style , triangleStyle , additionalStyles , style ] , [ triangleStyle , additionalStyles , arrowProps . style , style ] ) ; return ( < Box ref = { ref } style = { arrowStyles } borderColor = { borderColor } backgroundColor = { backgroundColor } zIndex = { 1 } { ... rest } />); } ) ; const getArrowStyles = ( props ) => { let additionalStyles = { transform : [ ] , } ; const diagonalLength = getDiagonalLength ( defaultArrowHeight , defaultArrowHeight ) ; if ( props . placement === 'top' && props . width ) { additionalStyles . transform . push ( { translateX : - props . width / 2 } ) ; additionalStyles . transform . push ( { rotate : '45deg' } ) ; additionalStyles . bottom = Math . ceil ( ( diagonalLength - defaultArrowHeight ) / 2 ) ; additionalStyles . borderBottomWidth = 1 ; additionalStyles . borderRightWidth = 1 ; } if ( props . placement === 'bottom' && props . width ) { additionalStyles . transform . push ( { translateX : - props . width / 2 } ) ; additionalStyles . transform . push ( { rotate : '45deg' } ) ; additionalStyles . top = Math . ceil ( ( diagonalLength - defaultArrowHeight ) / 2 ) ; additionalStyles . borderTopWidth = 1 ; additionalStyles . borderLeftWidth = 1 ; } if ( props . placement === 'left' && props . height ) { additionalStyles . transform . push ( { translateY : - props . height / 2 } ) ; additionalStyles . transform . push ( { rotate : '45deg' } ) ; additionalStyles . right = Math . ceil ( ( diagonalLength - defaultArrowHeight ) / 2 ) ; additionalStyles . borderTopWidth = 1 ; additionalStyles . borderRightWidth = 1 ; } if ( props . placement === 'right' && props . height ) { additionalStyles . transform . push ( { translateY : - props . height / 2 } ) ; additionalStyles . transform . push ( { rotate : '45deg' } ) ; additionalStyles . left = Math . ceil ( ( diagonalLength - defaultArrowHeight ) / 2 ) ; additionalStyles . borderBottomWidth = 1 ; additionalStyles . borderLeftWidth = 1 ; } return additionalStyles ; } ; const getContainerStyle = ( { placement , arrowHeight } ) => { const diagonalLength = getDiagonalLength ( arrowHeight , arrowHeight ) / 2 ; if ( placement === 'top' ) { return { marginBottom : diagonalLength } ; } if ( placement === 'bottom' ) { return { marginTop : diagonalLength } ; } if ( placement === 'left' ) { return { marginRight : diagonalLength } ; } if ( placement === 'right' ) { return { marginLeft : diagonalLength } ; } return { } ; } ; PopperArrow . displayName = 'PopperArrow' ; Popper . Content = PopperContent ; Popper . Arrow = PopperArrow ; export { Popper } ;