UNPKG

react-horizontal-scrolling

Version:

react horizontal scroll component

304 lines (268 loc) 10.8 kB
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 };