woocommerce/plugins/woocommerce-blocks/assets/js/base/hocs/with-scroll-to-top/index.js

78 lines
1.7 KiB
JavaScript

/**
* External dependencies
*/
import { Component, createRef, Fragment } from 'react';
/**
* Internal dependencies
*/
import './style.scss';
/**
* HOC that provides a function to scroll to the top of the component.
*
* @param {Function} OriginalComponent Component being wrapped.
*/
const withScrollToTop = ( OriginalComponent ) => {
class WrappedComponent extends Component {
constructor() {
super();
this.scrollPointRef = createRef();
}
scrollToTopIfNeeded = () => {
const scrollPointRefYPosition = this.scrollPointRef.current.getBoundingClientRect()
.bottom;
const isScrollPointRefVisible =
scrollPointRefYPosition >= 0 &&
scrollPointRefYPosition <= window.innerHeight;
if ( ! isScrollPointRefVisible ) {
this.scrollPointRef.current.scrollIntoView();
}
};
moveFocusToTop = ( focusableSelector ) => {
const focusableElements = this.scrollPointRef.current.parentElement.querySelectorAll(
focusableSelector
);
if ( focusableElements.length ) {
focusableElements[ 0 ].focus();
}
};
scrollToTop = ( args ) => {
if ( ! window || ! Number.isFinite( window.innerHeight ) ) {
return;
}
this.scrollToTopIfNeeded();
if ( args && args.focusableSelector ) {
this.moveFocusToTop( args.focusableSelector );
}
};
render() {
return (
<Fragment>
<div
className="with-scroll-to-top__scroll-point"
ref={ this.scrollPointRef }
aria-hidden
/>
<OriginalComponent
{ ...this.props }
scrollToTop={ this.scrollToTop }
/>
</Fragment>
);
}
}
WrappedComponent.displayName = 'withScrollToTop';
return WrappedComponent;
};
export default withScrollToTop;