import { RefCallback , useMemo , useRef , useState } from 'react' ; import useLayoutEffect from 'use-isomorphic-layout-effect' ; import usePrevious from 'use-previous' ; import { omitUndefined } from '@remirror/core' ; import { defaultAbsolutePosition , ElementsAddedProps , getPositioner , PositionerExtension , PositionerParam , PositionerPosition , } from '@remirror/extension-positioner' ; import { useExtension } from '@remirror/react-core' ; export interface UseMultiPositionerReturn extends PositionerPosition { /**
     * This ref must be applied to the component that is being positioned in order
     * to correctly obtain the position data.
     */ ref : RefCallback < HTMLElement > ; /**
     * The element that that the ref has found.
     */ element ? : HTMLElement ; /**
     * A key to uniquely identify this positioner. This can be applied to the
     * react element.
     */ key : string ; } param positioner param deps export function useMultiPositioner ( positioner , deps ) { interface CollectElementRef { ref : RefCallback < HTMLElement > ; id : string ; } const [ state , setState ] = useState < ElementsAddedProps [ ] > ( [ ] ) ; const [ memoizedPositioner , setMemoizedPositioner ] = useState ( ( ) => getPositioner ( positioner ) ) ; const [ collectRefs , setCollectRefs ] = useState < CollectElementRef [ ] > ( [ ] ) ; const positionerRef = useRef ( positioner ) ; const previousPositioner = usePrevious ( memoizedPositioner ) ; positionerRef . current = positioner ; useExtension ( PositionerExtension , ( { addCustomHandler } ) => { const positioner = getPositioner ( positionerRef . current ) ; const dispose = addCustomHandler ( 'positioner' , positioner ) ; setMemoizedPositioner ( positioner ) ; return dispose ; } , deps ) ; useLayoutEffect ( ( ) => { const disposeUpdate = memoizedPositioner . addListener ( 'update' , ( options ) => { const items = [ ] ; for ( const { id , setElement } of options ) { const ref = ( element ) => { if ( ! element ) { return ; } setElement ( element ) ; } ; items . push ( { id , ref } ) ; } setCollectRefs ( items ) ; } ) ; const disposeDone = memoizedPositioner . addListener ( 'done' , ( options ) => { setState ( options ) ; } ) ; if ( previousPositioner ?. recentUpdate ) { memoizedPositioner . onActiveChanged ( previousPositioner ?. recentUpdate ) ; } return ( ) => { disposeUpdate ( ) ; disposeDone ( ) ; } ; } , [ memoizedPositioner , previousPositioner ] ) ; return useMemo ( ( ) => { const positions = [ ] ; for ( const [ index , { ref , id : key } ] of collectRefs . entries ( ) ) { const stateValue = state [ index ] ; const { element , position = { } } = stateValue ?? { } ; const absolutePosition = { ... defaultAbsolutePosition , ... omitUndefined ( position ) } ; positions . push ( { ref , element , key , ... absolutePosition } ) ; } return positions ; } , [ collectRefs , state ] ) ; }