react-router-hash-link-offset
Version:
Hash link scroll functionality for React Router v4
129 lines (107 loc) • 4.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.genericHashLink = genericHashLink;
exports.HashLink = HashLink;
exports.NavHashLink = NavHashLink;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _reactRouterDom = require('react-router-dom');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var hashFragment = '';
var observer = null;
var asyncTimerId = null;
var scrollFunction = null;
function reset() {
hashFragment = '';
if (observer !== null) observer.disconnect();
if (asyncTimerId !== null) {
window.clearTimeout(asyncTimerId);
asyncTimerId = null;
}
}
function getElAndScroll(scrollOffset) {
var element = document.getElementById(hashFragment);
if (element !== null) {
scrollFunction(element);
// now account for the optional scroll offset
var scrolledY = window.scrollY;
if (scrolledY) {
window.scrollTo(0, scrolledY + scrollOffset);
}
reset();
return true;
}
return false;
}
function hashLinkScroll(scrollOffset) {
// Push onto callback queue so it runs after the DOM is updated
window.setTimeout(function () {
if (getElAndScroll(scrollOffset) === false) {
if (observer === null) {
observer = new MutationObserver(getElAndScroll.bind(scrollOffset));
}
observer.observe(document, {
attributes: true,
childList: true,
subtree: true
});
// if the element doesn't show up in 10 seconds, stop checking
asyncTimerId = window.setTimeout(function () {
reset();
}, 10000);
}
}, 0);
}
function genericHashLink(props, As) {
var scrollOffset = props.scrollOffset,
scroll = props.scroll,
smooth = props.smooth,
otherProps = _objectWithoutProperties(props, ['scrollOffset', 'scroll', 'smooth']);
function handleClick(e) {
reset();
if (otherProps.onClick) otherProps.onClick(e);
if (typeof otherProps.to === 'string') {
hashFragment = otherProps.to.split('#').slice(1).join('#');
} else if (_typeof(otherProps.to) === 'object' && typeof otherProps.to.hash === 'string') {
hashFragment = otherProps.to.hash.replace('#', '');
}
if (hashFragment !== '') {
scrollFunction = scroll || function (el) {
return smooth ? el.scrollIntoView({ behavior: 'smooth' }) : el.scrollIntoView();
};
hashLinkScroll();
}
}
return _react2.default.createElement(
As,
_extends({}, otherProps, { onClick: handleClick }),
props.children
);
}
function HashLink(props) {
return genericHashLink(props, _reactRouterDom.Link);
}
function NavHashLink(props) {
return genericHashLink(props, _reactRouterDom.NavLink);
}
var propTypes = {
onClick: _propTypes2.default.func,
children: _propTypes2.default.node,
scrollOffset: _propTypes2.default.number,
scroll: _propTypes2.default.func,
smooth: _propTypes2.default.bool,
to: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object])
};
HashLink.defaultProps = {
scrollOffset: 0,
smooth: false
};
HashLink.propTypes = propTypes;
NavHashLink.propTypes = propTypes;