found-scroll
Version:
Scroll management for found
93 lines (76 loc) • 2.6 kB
JavaScript
import StateStorage from 'farce/StateStorage';
import React, { Component, createContext } from 'react';
import ScrollBehavior from 'scroll-behavior';
const STORAGE_NAMESPACE = '@@scroll';
export const ScrollContext = /*#__PURE__*/createContext(null);
const defaultCreateScrollBehavior = config => new ScrollBehavior(config);
class ScrollManager extends Component {
constructor(props) {
super(props);
this.prevRenderArgs = null;
this.shouldUpdateScroll = (prevRenderArgs, renderArgs) => {
const {
shouldUpdateScroll
} = this.props;
if (!shouldUpdateScroll) {
return true;
} // Hack to allow access to ScrollBehavior internals (e.g. stateStorage).
return shouldUpdateScroll.call(this.scrollBehavior, prevRenderArgs, renderArgs);
};
this.registerScrollElement = (key, element) => {
const {
renderArgs
} = this.props;
this.scrollBehavior.registerElement(key, element, this.shouldUpdateScroll, renderArgs);
return () => {
this.scrollBehavior.unregisterElement(key);
};
};
const {
createScrollBehavior = defaultCreateScrollBehavior,
renderArgs: _renderArgs
} = props;
const {
router
} = _renderArgs;
this.scrollBehavior = createScrollBehavior({
addNavigationListener: router.addNavigationListener,
stateStorage: new StateStorage(router, STORAGE_NAMESPACE),
getCurrentLocation: () => this.props.renderArgs.location,
shouldUpdateScroll: this.shouldUpdateScroll
});
this.scrollContext = {
scrollBehavior: this.scrollBehavior,
registerScrollElement: this.registerScrollElement
};
this.prevRenderArgs = null;
}
componentDidMount() {
this.maybeUpdateScroll();
}
componentDidUpdate() {
this.maybeUpdateScroll();
}
componentWillUnmount() {
this.scrollBehavior.stop();
}
maybeUpdateScroll() {
const {
renderArgs
} = this.props;
const prevLocation = this.prevRenderArgs && this.prevRenderArgs.location;
if (renderArgs.location === prevLocation || !(renderArgs.elements || renderArgs.error)) {
// If the location hasn't actually changed, or if we're in a global
// pending state, don't update the scroll position.
return;
}
this.scrollBehavior.updateScroll(this.prevRenderArgs, renderArgs);
this.prevRenderArgs = renderArgs;
}
render() {
return /*#__PURE__*/React.createElement(ScrollContext.Provider, {
value: this.scrollContext
}, this.props.children);
}
}
export default ScrollManager;