import { getScroll } from '@uiw/utils' ; import getBoundingClientRect , { IBoundingClientRect } from './util/getBoundingClientRect' ; import getOuterSizes from './util/getOuterSizes' ; import { OverlayStyl , OverlayTriggerProps , Placement } from './' ; type GetStyleOptions = { trigger : HTMLElement | IBoundingClientRect ; popup : HTMLElement | IBoundingClientRect ; placement : OverlayStyl [ 'placement' ] ; usePortal : OverlayTriggerProps [ 'usePortal' ] ; autoAdjustOverflow : OverlayTriggerProps [ 'autoAdjustOverflow' ] ; } ; export function getStyle ( options ) { let { trigger : triggerDom , popup : popupDom , placement , usePortal , autoAdjustOverflow } = options || { } ; const sty = { } as OverlayStyl ; if ( ! triggerDom || ! popupDom || ! document ) { return sty ; } const winSizeHeight = Math . max ( document . documentElement . clientHeight , window . innerHeight || 0 ) ; const winSizeWidth = Math . max ( document . documentElement . clientWidth , window . innerWidth || 0 ) ; sty . placement = placement ; const scrollTop = getScroll ( ( triggerDom as HTMLElement ) . ownerDocument ! . documentElement , true ) ; const scrollLeft = getScroll ( ( triggerDom as HTMLElement ) . ownerDocument ! . documentElement ) ; const trigger = { ... getBoundingClientRect ( triggerDom as HTMLElement ) , ... getOuterSizes ( triggerDom as HTMLElement ) , } ; const popup = { ... getBoundingClientRect ( popupDom as HTMLElement ) , ... getOuterSizes ( popupDom as HTMLElement ) , } ; const bottom = winSizeHeight - trigger . bottom ; const right = winSizeWidth - trigger . left - trigger . width ; sty . top = trigger . top + scrollTop ; sty . left = trigger . left ; if ( ! usePortal ) { sty . top = trigger . offsetTop as number ; sty . left = trigger . offsetLeft as number ; } if ( placement && /^(top)/ . test ( placement ) ) { sty . top -= popup . height ; } if ( placement && /^(right)/ . test ( placement ) ) { sty . left += trigger . width ; } if ( placement && /^(bottom)/ . test ( placement ) ) { sty . top += trigger . height ; } if ( placement && /^(left)/ . test ( placement ) ) { sty . left -= popup . width ; } switch ( sty . placement ) { case 'bottomLeft' : case 'topLeft' : break ; case 'bottom' : case 'top' : sty . left = sty . left - ( popup . width - trigger . width ) / 2 ; break ; case 'bottomRight' : case 'topRight' : sty . left = sty . left + scrollLeft + trigger . width - popup . width ; break ; case 'rightTop' : case 'leftTop' : break ; case 'right' : case 'left' : sty . top = sty . top - ( popup . height - trigger . height ) / 2 ; break ; case 'rightBottom' : case 'leftBottom' : sty . top = sty . top - popup . height + trigger . height ; break ; default : break ; } if ( autoAdjustOverflow ) { if ( placement && /^(top)/ . test ( placement ) && trigger . top < popup . height && bottom > popup . height ) { sty . placement = placement . replace ( /^top/ , 'bottom' ) as Placement ; sty . top = sty . top + popup . height + trigger . height ; } if ( placement && /^(bottom)/ . test ( placement ) && bottom < popup . height && trigger . top > popup . height ) { sty . placement = placement . replace ( /^bottom/ , 'top' ) as Placement ; sty . top = sty . top - popup . height - trigger . height ; } if ( placement && /^(right)/ . test ( placement ) && right < popup . width ) { sty . placement = placement . replace ( /^right/ , 'left' ) as Placement ; sty . left = sty . left - trigger . width - popup . width ; } if ( placement && /^(left)/ . test ( placement ) && trigger . left < popup . width ) { sty . placement = placement . replace ( /^left/ , 'right' ) as Placement ; sty . left = sty . left + trigger . width + popup . width ; } if ( placement && /^(left|right)/ . test ( placement ) && usePortal ) { if ( ( /(Top)$/ . test ( placement ) && trigger . top < 0 ) || ( /(right|left)$/ . test ( placement ) && trigger . top + trigger . height / 2 < popup . height / 2 ) || ( /(Bottom)$/ . test ( placement ) && trigger . top + trigger . height < popup . height ) ) { sty . top = scrollTop ; } } else { if ( placement && /(Top)$/ . test ( placement ) && trigger . top < 0 ) { sty . top -= trigger . top ; } if ( placement && /(Bottom)$/ . test ( placement ) && trigger . bottom < popup . height ) { sty . top = sty . top + ( popup . height - trigger . bottom ) ; } if ( placement && /(right|left)$/ . test ( placement ) && trigger . bottom - trigger . height / 2 < popup . height / 2 ) { sty . top = sty . top + popup . height / 2 - ( trigger . bottom - trigger . height / 2 ) ; } } if ( placement && /^(left|right)/ . test ( placement ) ) { if ( /(Top)$/ . test ( placement ) && bottom + trigger . height < popup . height ) { sty . top = sty . top - ( popup . height - bottom - trigger . height ) ; } if ( /(right|left)$/ . test ( placement ) && bottom + trigger . height / 2 < popup . height / 2 ) { sty . top = sty . top - ( popup . height / 2 - bottom - trigger . height / 2 ) ; } if ( /(Bottom)$/ . test ( placement ) && bottom < 0 ) { sty . top = sty . top + bottom ; } } if ( placement && /^(top|bottom)/ . test ( placement ) && usePortal ) { if ( ( /(Left)$/ . test ( placement ) && trigger . left < 0 ) || ( /(top|bottom)$/ . test ( placement ) && trigger . left + trigger . width / 2 < popup . width / 2 ) || ( /(Right)$/ . test ( placement ) && trigger . left + trigger . width < popup . width ) ) { sty . left = scrollLeft ; } if ( /(top|bottom)$/ . test ( placement ) && right + trigger . width / 2 < popup . width / 2 ) { sty . left = trigger . left + trigger . width + right - popup . width ; } } else if ( placement && /(top|bottom)$/ . test ( placement ) && right + trigger . width / 2 < popup . width / 2 ) { sty . left = sty . left + ( right + trigger . width / 2 - popup . width / 2 ) ; } if ( placement && /^(top|bottom)/ . test ( placement ) ) { if ( /(Left)$/ . test ( placement ) && trigger . width + right < popup . width ) { sty . left = sty . left - ( popup . width - trigger . width - right ) ; } if ( /(Right)$/ . test ( placement ) && right < 0 ) { sty . left = sty . left + right ; } } } return sty ; }