import * as React from 'react' ; import * as ReactDOM from 'react-dom' ; import * as PopperJS from '@popperjs/core' ; export type Placement = PopperJS . Placement ; export type PopperOptions = PopperJS . Options ; import { usePopupStack } from './hooks' ; export interface PopperProps { /**
     * The reference element used to position the Popper. Popper content will try to follow the
     * `anchorElement` if it moves and will reposition itself if there is no longer room in the
     * window.
     */ anchorElement ? : React . RefObject < Element > | Element | null ; /**
     * The content of the Popper. If a function is provided, it will be treated as a Render Prop and
     * pass the `placement` chosen by PopperJS. This `placement` value is useful if your popup needs
     * to animate and that animation depends on the direction of the content in relation to the
     * `anchorElement`.
     */ children : ( ( props : { placement : Placement ; } ) => React . ReactNode ) | React . ReactNode ; /**
     * The element that contains the portal children when `portal` is true. It is best to not define
     * this unless you know what you're doing. Popper works with a PopupStack and in order for
     * z-indexes to work correctly, all Popups on your page should live on the same root element
     * otherwise you risk running into rendering issues:
     * https://philipwalton.com/articles/what-no-one-told-you-about-z-index/
     */ containerElement ? : Element | null ; /**
     * When provided, this optional callback will be used to determine positioning for the Popper element
     * instead of calling `getBoundingClientRect` on the `anchorElement` prop. Use this when you need
     * complete control over positioning. When this prop is specified, it is safe to pass `null` into the
     * `anchorElement` prop. If `null` is passed into the `anchorElement` prop, an `owner` will not be
     * provided for the `PopupStack`.
     */ getAnchorClientRect ? : ( ) => DOMRect ; default open ? : boolean ; default placement ? : Placement ; /**
     * A callback function that will be called whenever PopperJS chooses a placement that is different
     * from the provided `placement` preference. If a `placement` preference doesn't fit, PopperJS
     * will choose a new one and call this callback.
     */ onPlacementChange ? : ( placement : Placement ) => void ; /**
     * The additional options passed to the Popper's `popper.js` instance.
     */ popperOptions ? : Partial < PopperOptions > ; default portal ? : boolean ; } export const Popper = React . forwardRef < HTMLDivElement , PopperProps > ( ( { portal = true , open = true , ... elemProps } , ref ) => { if ( ! open ) { return null ; } return < OpenPopper ref = { ref } portal = { portal } { ... elemProps } />; } ) ; const getElementFromRefOrElement = ( input ) : Element | undefined => { if ( input === null ) { return undefined ; } else if ( 'current' in input ) { return input . current || undefined ; } else { return input ; } } ; const defaultPopperOptions = { } ; const OpenPopper = React . forwardRef < HTMLDivElement , PopperProps > ( ( { anchorElement , getAnchorClientRect , popperOptions = defaultPopperOptions , placement : popperPlacement = 'bottom' , onPlacementChange , children , portal , containerElement , } , ref ) => { const firstRender = React . useRef ( true ) ; const popperInstance = React . useRef < PopperJS . Instance > ( ) ; const [ placement , setPlacement ] = React . useState ( popperPlacement ) ; const stackRef = usePopupStack ( ref , anchorElement as HTMLElement ) ; const placementModifier = React . useMemo ( ( ) : PopperJS . Modifier < any , any > => { return { name : 'setPlacement' , enabled : true , phase : 'main' , fn ( { state } ) { setPlacement ( state . placement ) ; onPlacementChange ?. ( state . placement ) ; } , } ; } , [ setPlacement , onPlacementChange ] ) ; React . useLayoutEffect ( ( ) => { const anchorEl = getAnchorClientRect ? { getBoundingClientRect : getAnchorClientRect } : getElementFromRefOrElement ( anchorElement ?? null ) ; if ( ! anchorEl ) { console . warn ( `Popper: neither anchorElement or getAnchorClientRect was defined. A valid anchorElement or getAnchorClientRect callback must be provided to render a Popper` ) ; return undefined ; } if ( stackRef . current ) { popperInstance . current = PopperJS . createPopper ( anchorEl , stackRef . current , { placement : popperPlacement , ... popperOptions , modifiers : [ ... ( popperOptions . modifiers || [ ] ) , placementModifier ] , } ) ; return ( ) => { popperInstance . current ?. destroy ( ) ; } ; } return undefined ; } , [ anchorElement , getAnchorClientRect , stackRef ] ) ; React . useLayoutEffect ( ( ) => { if ( ! firstRender . current ) { popperInstance . current ?. setOptions ( { placement : popperPlacement , ... popperOptions , modifiers : [ ... ( popperOptions . modifiers || [ ] ) , placementModifier ] , } ) ; } firstRender . current = false ; } , [ popperOptions , popperPlacement , placementModifier ] ) ; const contents = < > { isRenderProp ( children ) ? children ( { placement } ) : children } < />; if ( ! portal ) { return contents ; } return ReactDOM . createPortal ( contents , containerElement || stackRef . current ! ) ; } ) ; function isRenderProp ( children ) { if ( typeof children === 'function' ) { return true ; } return false ; }