react-horizontal-scrolling
Version:
react horizontal scroll component
304 lines (268 loc) • 10.8 kB
JavaScript
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
import _inherits from "@babel/runtime/helpers/inherits";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _regeneratorRuntime from "@babel/runtime/regenerator";
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types';
/* CSS */
import cssStyle from './style';
var HorizontalScroll = /*#__PURE__*/function (_Component) {
_inherits(HorizontalScroll, _Component);
var _super = _createSuper(HorizontalScroll);
function HorizontalScroll(props) {
var _this;
_classCallCheck(this, HorizontalScroll);
_this = _super.call(this, props);
_this.state = {
outerWidth: 0,
innerWidth: 0,
trackWidth: 0,
trackLeftMax: 0
};
_this.outerId = 'horizontalScrollOuter' + Math.random().toFixed(5).replace('0.', '');
_this.innerId = 'horizontalScrollInner' + Math.random().toFixed(5).replace('0.', '');
_this.trackId = 'horizontalScrollTrack' + Math.random().toFixed(5).replace('0.', '');
_this.wrapperRef = /*#__PURE__*/createRef();
_this.onGlobalWheel = _this.onGlobalWheel.bind(_assertThisInitialized(_this));
_this.progress = 0;
_this.delay = 1000 / 60;
return _this;
}
_createClass(HorizontalScroll, [{
key: "componentDidMount",
value: function componentDidMount() {
this.setStyleHeader(); // Set the style to the <link>
this.setupConfigBasedOnHTML();
document.body.addEventListener('wheel', this.onGlobalWheel, {
passive: false
});
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
document.body.removeEventListener('wheel', this.onGlobalWheel);
}
}, {
key: "setupConfigBasedOnHTML",
value: function setupConfigBasedOnHTML() {
var _this2 = this;
setTimeout(function () {
var outerElement = document.getElementById(_this2.outerId);
var innerElement = document.getElementById(_this2.innerId);
if (!outerElement || !innerElement) return _this2.setupConfigBasedOnHTML();
var outerWidth = outerElement.offsetWidth;
var innerWidth = innerElement.offsetWidth;
var trackWidth = (outerWidth / innerWidth).toFixed(2);
_this2.setState({
outerWidth: outerWidth,
innerWidth: innerWidth,
trackWidth: trackWidth,
trackLeftMax: (1 - parseFloat(trackWidth)) * outerWidth
});
}, 500);
}
}, {
key: "onGlobalWheel",
value: function onGlobalWheel(e) {
if (this.wrapperRef && this.wrapperRef.current && this.wrapperRef.current.contains(e.target)) {
e.preventDefault();
}
}
}, {
key: "updateTrackLeft",
value: function updateTrackLeft(trackLeft) {
var _this$state = this.state,
trackLeftMax = _this$state.trackLeftMax,
outerWidth = _this$state.outerWidth,
innerWidth = _this$state.innerWidth;
trackLeft = Math.max(trackLeft, 0);
trackLeft = Math.min(trackLeft, trackLeftMax);
document.getElementById(this.trackId).style.left = trackLeft + 'px';
var innerTransformFrom = parseFloat(document.getElementById(this.innerId).style.transform.replace(/[^\d.]/g, '')) || 0;
var innerTransformTo = (trackLeft / outerWidth * innerWidth).toFixed(2);
this.updateInnerTransform(innerTransformFrom, innerTransformTo);
}
}, {
key: "updateInnerTransform",
value: function updateInnerTransform(from, to) {
var _this3 = this;
if (from === to) return;
var diff = to - from;
var duration = 950;
var startTime = new Date();
var delay = 1000 / 60;
var progress = 0;
var time = delay;
if (this.animationFrameId) {
window.cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
var step = function step() {
progress = new Date() - startTime;
var tweenValue = _this3.tween({
from: from,
time: time,
duration: duration,
diff: diff
});
document.getElementById(_this3.innerId).style.transform = "translateX(-".concat(tweenValue, "px)");
if (progress >= time) {
time = progress > time ? progress + delay - (progress - time) : progress + delay - 1;
if (time < progress + 1) {
time = progress + 1;
}
}
if (time < duration) {
_this3.animationFrameId = window.requestAnimationFrame(step);
}
};
this.animationFrameId = window.requestAnimationFrame(step);
}
}, {
key: "tween",
value: function tween(_ref) {
var from = _ref.from,
time = _ref.time,
duration = _ref.duration,
diff = _ref.diff;
var myTime = time / duration;
var ts = myTime * myTime;
var tc = ts * myTime;
return from + diff * (0.499999999999997 * tc * ts + -2.5 * ts * ts + 5.5 * tc + -6.5 * ts + 4 * myTime);
}
}, {
key: "onWheel",
value: function onWheel(e) {
var currentTrack = document.getElementById(this.trackId);
if (currentTrack) {
var delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY;
var currentTrackLeft = currentTrack.style.left || '0px';
this.updateTrackLeft(parseFloat(currentTrackLeft.replace('px', '')) + delta * 0.45);
}
}
}, {
key: "onTrackMouseDown",
value: function onTrackMouseDown(e) {
e.stopPropagation();
e.preventDefault();
this.prePosX = null;
document.onmousemove = this.onTrackMouseMove.bind(this);
document.onmouseup = this.onTrackMouseUp.bind(this);
}
}, {
key: "onTrackMouseMove",
value: function onTrackMouseMove(e) {
e.preventDefault();
var element = document.getElementById(this.trackId);
var pos1 = !this.prePosX ? 0 : this.prePosX - e.clientX;
this.prePosX = e.clientX;
this.updateTrackLeft(element.offsetLeft - pos1);
}
}, {
key: "onTrackMouseUp",
value: function () {
var _onTrackMouseUp = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
document.onmouseup = null;
document.onmousemove = null;
case 2:
case "end":
return _context.stop();
}
}
}, _callee);
}));
function onTrackMouseUp() {
return _onTrackMouseUp.apply(this, arguments);
}
return onTrackMouseUp;
}()
}, {
key: "onTouchMove",
value: function onTouchMove(e) {
var element = document.getElementById(this.trackId);
var pos1 = !this.prePosX ? 0 : this.prePosX - e.touches[0].clientX;
this.prePosX = e.touches[0].clientX;
this.updateTrackLeft(element.offsetLeft - pos1);
}
/**
* Set style tag in header
* in this way we can insert default css
*/
}, {
key: "setStyleHeader",
value: function setStyleHeader() {
var head = document.getElementsByTagName('head')[0];
if (!head.querySelector('style[id="react-horizontal-scrolling"]')) {
var tag = document.createElement('style');
tag.id = 'react-horizontal-scrolling';
tag.innerHTML = cssStyle;
/* eslint-disable */
if (typeof __webpack_nonce__ !== 'undefined' && __webpack_nonce__) {
tag.setAttribute('nonce', __webpack_nonce__);
}
/* eslint-enable */
head.insertBefore(tag, head.firstChild);
}
}
}, {
key: "render",
value: function render() {
var _this$props = this.props,
className = _this$props.className,
children = _this$props.children,
disabled = _this$props.disabled;
var trackWidth = this.state.trackWidth;
var isArrayChild = Array.isArray(children);
if (disabled) {
return /*#__PURE__*/React.createElement("div", {
className: className
}, children);
}
return /*#__PURE__*/React.createElement("div", {
className: "HorizontalScroll ".concat(className || ''),
ref: this.wrapperRef
}, /*#__PURE__*/React.createElement("div", {
className: "HorizontalScrollOuter",
id: this.outerId,
onWheel: this.onWheel.bind(this)
}, /*#__PURE__*/React.createElement("div", {
id: this.innerId,
className: "HorizontalScrollInner",
onTouchMove: this.onTouchMove.bind(this)
}, !isArrayChild && /*#__PURE__*/React.createElement("div", {
className: "HorizontalScrollInnerChildren"
}, children), isArrayChild && children.map(function (child, idx) {
return /*#__PURE__*/React.createElement("div", {
key: idx,
className: "HorizontalScrollInnerChildren"
}, child);
}))), trackWidth > 0 && trackWidth < 1 && /*#__PURE__*/React.createElement("div", {
className: "HorizontalScrollTrack"
}, /*#__PURE__*/React.createElement("div", {
id: this.trackId,
className: "HorizontalScrollTrackInner",
style: {
width: parseFloat(trackWidth) * 100 + '%'
},
onMouseDown: this.onTrackMouseDown.bind(this)
})));
}
}]);
return HorizontalScroll;
}(Component);
_defineProperty(HorizontalScroll, "propTypes", {
className: PropTypes.string,
disabled: PropTypes.bool
});
export { HorizontalScroll as default };