import raf from 'raf' ; import { StringPropertyNames } from './utilityTypes' ; export type ContainerType = HTMLElement | ( ( ) => HTMLElement ) | Window ; export const getTop = ( ele ) : number => { let offset = ele . offsetTop ; if ( ele . offsetParent != null ) { offset += getTop ( ele . offsetParent as HTMLElement ) ; } return offset ; } ; export const getLeft = ( ele ) => { let offset = ele . offsetLeft ; if ( ele . offsetParent != null ) { offset += getLeft ( ele . offsetParent as HTMLElement ) ; } return offset ; } ; export const getBoundingClientRect = ( ele ) : Omit < DOMRectReadOnly , 'x' | 'y' | 'toJSON' > => { const rect = ele . getBoundingClientRect ( ) ; const isIE = navigator . userAgent . indexOf ( 'MSIE' ) !== - 1 ; const rectTop = isIE && ele . tagName === 'HTML' ? - ele . scrollTop : rect . top ; return { left : rect . left , top : rectTop , right : rect . right , bottom : rect . bottom , width : rect . right - rect . left , height : rect . bottom - rectTop , } ; } ; export const isNumeric = ( n ) : boolean => { return n !== '' && ! Number . isNaN ( parseFloat ( n ) ) && Number . isFinite ( n ) ; } ; export const setStyle = ( ele , styles ) => { Object . keys ( styles ) . forEach ( ( prop ) => { let unit = '' ; if ( [ 'width' , 'height' , 'top' , 'right' , 'bottom' , 'left' ] . indexOf ( prop ) !== - 1 && isNumeric ( styles [ prop ] ) ) { unit = 'px' ; } ele . style [ prop ] = styles [ prop ] + unit ; } ) ; } ; type Property = StringPropertyNames < CSSStyleDeclaration > ; export const getStyleComputedProperty = ( ele , property ) : string => { const css = window . getComputedStyle ( ele , null ) ; return css [ property ] ; } ; export const isFixed = ( ele ) : boolean => { if ( ele === window . document . body ) { return false ; } if ( getStyleComputedProperty ( ele , 'position' ) === 'fixed' ) { return true ; } if ( ele . parentNode ) { return isFixed ( ele . parentNode ) ; } return false ; } ; export const getOuterSizes = ( ele ) => { const _display = ele . style . display ; const _visibility = ele . style . visibility ; ele . style . display = 'block' ; ele . style . visibility = 'hidden' ; const styles = window . getComputedStyle ( ele ) ; const x = parseFloat ( styles . marginTop as string ) + parseFloat ( styles . marginBottom as string ) ; const y = parseFloat ( styles . marginLeft as string ) + parseFloat ( styles . marginRight as string ) ; const result = { width : ele . offsetWidth + y , height : ele . offsetHeight + x , } ; ele . style . display = _display ; ele . style . visibility = _visibility ; return result ; } ; export const getOffsetParent = ( ele ) => { const { offsetParent } = ele ; return offsetParent === window . document . body || ! offsetParent ? window . document . documentElement : offsetParent ; } ; export const getScrollParent = ( ele ) : HTMLElement => { const parent = ele . parentNode ; if ( ! parent ) { return ele ; } if ( parent === window . document ) { if ( window . document . body . scrollTop ) { return window . document . body ; } return window . document . documentElement ; } const overflowValues = [ 'scroll' , 'auto' ] ; if ( overflowValues . indexOf ( getStyleComputedProperty ( parent , 'overflow' ) ) !== - 1 || overflowValues . indexOf ( getStyleComputedProperty ( parent , 'overflowX' ) ) !== - 1 || overflowValues . indexOf ( getStyleComputedProperty ( parent , 'overflowY' ) ) !== - 1 ) { return parent ; } return getScrollParent ( ele . parentNode ) ; } ; export const getSupportedPropertyName = ( property ) => { const prefixes = [ '' , 'ms' , 'webkit' , 'moz' , 'o' ] ; for ( let i = 0 ; i < prefixes . length ; i ++ ) { const toCheck = prefixes [ i ] ? prefixes [ i ] + property . charAt ( 0 ) . toUpperCase ( ) + property . slice ( 1 ) : property ; if ( typeof window . document . body . style [ toCheck ] !== 'undefined' ) { return toCheck ; } } return null ; } ; export const getScrollTop = ( ele ) : number => { if ( ele === document . documentElement ) { return ( document . scrollingElement || document . documentElement ) . scrollTop ; } if ( ele === window ) { return Math . max ( window . pageYOffset , document . documentElement . scrollTop , document . body . scrollTop ) ; } return ( ele as HTMLElement ) . scrollTop ; } ; export const getScrollLeft = ( ele ) : number => { if ( ele === document . documentElement ) { return ( document . scrollingElement || document . documentElement ) . scrollLeft ; } if ( ele === window ) { return Math . max ( window . pageYOffset , document . documentElement . scrollLeft , document . body . scrollLeft ) ; } return ( ele as HTMLElement ) . scrollLeft ; } ; export const getMountContainer = ( mountContainer ? ) : HTMLElement => { if ( mountContainer ) { if ( typeof mountContainer === 'function' ) { return mountContainer ( ) ; } if ( typeof mountContainer === 'object' && mountContainer instanceof HTMLElement ) { return mountContainer ; } } return document . body ; } ; export const getScrollContainer = ( mountContainer ? ) : HTMLElement | Window => { const container = getMountContainer ( mountContainer ) ; return container === document . body ? window : container ; } ; let scrollRafId ; const scrollList = { } ; export function scrollTo ( scrollContainer , top , left , duration ) { if ( scrollList ?. [ scrollRafId ] === scrollContainer ) { raf . cancel ( scrollRafId ) ; } let count = 0 ; let fromLeft = 0 ; let fromTop = 0 ; if ( scrollContainer === window ) { fromLeft = getScrollLeft ( scrollContainer ) ; fromTop = getScrollTop ( scrollContainer ) ; } else { fromLeft = ( scrollContainer as HTMLElement ) . scrollLeft ; fromTop = ( scrollContainer as HTMLElement ) . scrollTop ; } const frames = duration === 0 ? 1 : Math . round ( ( duration * 1000 ) / 16 ) ; function animate ( ) { if ( scrollContainer === window ) { const x = getScrollLeft ( scrollContainer ) + ( left - fromLeft ) / frames ; const y = getScrollTop ( scrollContainer ) + ( top - fromTop ) / frames ; scrollContainer . scrollTo ( x , y ) ; } else { ( scrollContainer as HTMLElement ) . scrollLeft += ( left - fromLeft ) / frames ; ( scrollContainer as HTMLElement ) . scrollTop += ( top - fromTop ) / frames ; } count += 1 ; if ( count < frames ) { scrollRafId = raf ( animate ) ; scrollList [ scrollRafId ] = scrollContainer ; } } animate ( ) ; } export const canUseDOM = ! ! ( typeof window !== 'undefined' && window . document && window . document . createElement ) ;