diff --git a/assets/js/base/hocs/with-scroll-to-top/index.js b/assets/js/base/hocs/with-scroll-to-top/index.js deleted file mode 100644 index 134f113a0d1..00000000000 --- a/assets/js/base/hocs/with-scroll-to-top/index.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * External dependencies - */ -import { useRef, useCallback } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import './style.scss'; - -const ScrollToTopComponent = ( { OriginalComponent, ...props } ) => { - const scrollPointRef = useRef( null ); - - const scrollToTopIfNeeded = useCallback( () => { - if ( scrollPointRef.current === null ) { - return; - } - const scrollPointRefYPosition = scrollPointRef.current.getBoundingClientRect() - .bottom; - const isScrollPointRefVisible = - scrollPointRefYPosition >= 0 && - scrollPointRefYPosition <= window.innerHeight; - if ( ! isScrollPointRefVisible ) { - scrollPointRef.current.scrollIntoView(); - } - }, [] ); - - const moveFocusToTop = useCallback( ( focusableSelector ) => { - if ( scrollPointRef.current === null ) { - return; - } - const focusableElements = scrollPointRef.current.parentElement.querySelectorAll( - focusableSelector - ); - if ( focusableElements.length ) { - focusableElements[ 0 ].focus(); - } - }, [] ); - - const scrollToTop = useCallback( - ( args ) => { - if ( ! window || ! Number.isFinite( window.innerHeight ) ) { - return; - } - - scrollToTopIfNeeded(); - - if ( args && args.focusableSelector ) { - moveFocusToTop( args.focusableSelector ); - } - }, - [ scrollToTopIfNeeded, moveFocusToTop ] - ); - - return ( - <> -
- - - ); -}; - -/** - * HOC that provides a function to scroll to the top of the component. - * - * @param {Function} OriginalComponent Component being wrapped. - */ -const withScrollToTop = ( OriginalComponent ) => { - return ( props ) => { - return ( - - ); - }; -}; - -export default withScrollToTop; diff --git a/assets/js/base/hocs/with-scroll-to-top/index.tsx b/assets/js/base/hocs/with-scroll-to-top/index.tsx new file mode 100644 index 00000000000..c9b9f8c513e --- /dev/null +++ b/assets/js/base/hocs/with-scroll-to-top/index.tsx @@ -0,0 +1,77 @@ +/** + * External dependencies + */ +import { useRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import './style.scss'; + +interface ScrollToTopProps { + focusableSelector?: string; +} + +const maybeScrollToTop = ( scrollPoint: HTMLElement ): void => { + const yPos = scrollPoint.getBoundingClientRect().bottom; + const isScrollPointVisible = yPos >= 0 && yPos <= window.innerHeight; + + if ( ! isScrollPointVisible ) { + scrollPoint.scrollIntoView(); + } +}; + +const moveFocusToTop = ( + scrollPoint: HTMLElement, + focusableSelector: string +): void => { + const focusableElements = + scrollPoint.parentElement?.querySelectorAll( focusableSelector ) || []; + + if ( focusableElements.length ) { + ( focusableElements[ 0 ] as HTMLElement )?.focus(); + } +}; + +const scrollToHTMLElement = ( + scrollPoint: HTMLElement, + { focusableSelector }: ScrollToTopProps +): void => { + if ( ! window || ! Number.isFinite( window.innerHeight ) ) { + return; + } + + maybeScrollToTop( scrollPoint ); + + if ( focusableSelector ) { + moveFocusToTop( scrollPoint, focusableSelector ); + } +}; + +/** + * HOC that provides a function to scroll to the top of the component. + */ +const withScrollToTop = ( + OriginalComponent: React.FunctionComponent< Record< string, unknown > > +) => { + return ( props: Record< string, unknown > ): JSX.Element => { + const scrollPointRef = useRef< HTMLDivElement >( null ); + const scrollToTop = ( args: ScrollToTopProps ) => { + if ( scrollPointRef.current !== null ) { + scrollToHTMLElement( scrollPointRef.current, args ); + } + }; + return ( + <> +
+ + + ); + }; +}; + +export default withScrollToTop;