UNPKG

rv-window-scroller

Version:

Window scroller component for react-virtualized and react-window

358 lines (357 loc) 23.8 kB
!function(global, factory) { "object" == typeof exports && "undefined" != typeof module ? factory(exports, require("react"), require("react-dom")) : "function" == typeof define && define.amd ? define([ "exports", "react", "react-dom" ], factory) : factory((global = global || self).ReactVirtualized = {}, global.React, global.ReactDOM); }(this, function(exports, React, ReactDOM) { "use strict"; function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); } } function _defineProperty(obj, key, value) { return key in obj ? Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }) : obj[key] = value, obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function(sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _getPrototypeOf(o) { return (_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function(o) { return o.__proto__ || Object.getPrototypeOf(o); })(o); } function _setPrototypeOf(o, p) { return (_setPrototypeOf = Object.setPrototypeOf || function(o, p) { return o.__proto__ = p, o; })(o, p); } function _assertThisInitialized(self) { if (void 0 === self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return self; } var win, request = (win = "undefined" != typeof window ? window : "undefined" != typeof self ? self : {}).requestAnimationFrame || win.webkitRequestAnimationFrame || win.mozRequestAnimationFrame || win.oRequestAnimationFrame || win.msRequestAnimationFrame || function(callback) { return win.setTimeout(callback, 1e3 / 60); }, cancel = win.cancelAnimationFrame || win.webkitCancelAnimationFrame || win.mozCancelAnimationFrame || win.oCancelAnimationFrame || win.msCancelAnimationFrame || function(id) { win.clearTimeout(id); }, raf = request, caf = cancel, cancelAnimationTimeout = function(frame) { return caf(frame.id); }, requestAnimationTimeout = function(callback, delay) { var start; Promise.resolve().then(function() { start = Date.now(); }); var frame = { id: raf(function timeout() { Date.now() - start >= delay ? callback.call() : frame.id = raf(timeout); }) }; return frame; }, mountedInstances = [], originalBodyPointerEvents = null, disablePointerEventsTimeoutId = null, registeredScrollListeners = new WeakMap(); function enablePointerEventsIfDisabled() { disablePointerEventsTimeoutId && (disablePointerEventsTimeoutId = null, document.body && null != originalBodyPointerEvents && (document.body.style.pointerEvents = originalBodyPointerEvents), originalBodyPointerEvents = null); } function enablePointerEventsAfterDelayCallback() { enablePointerEventsIfDisabled(), mountedInstances.forEach(function(instance) { return instance.__resetIsScrolling(); }); } function onScrollWindow(event) { event.currentTarget === window && null == originalBodyPointerEvents && document.body && (originalBodyPointerEvents = document.body.style.pointerEvents, document.body.style.pointerEvents = "none"), function() { disablePointerEventsTimeoutId && cancelAnimationTimeout(disablePointerEventsTimeoutId); var maximumTimeout = 0; mountedInstances.forEach(function(instance) { maximumTimeout = Math.max(maximumTimeout, instance.props.scrollingResetTimeInterval); }), disablePointerEventsTimeoutId = requestAnimationTimeout(enablePointerEventsAfterDelayCallback, maximumTimeout); }(), mountedInstances.forEach(function(instance) { instance.props.scrollElement === event.currentTarget && instance.__handleWindowScrollEvent(); }); } function registerScrollListener(component, element) { registeredScrollListeners.has(element) || (element.addEventListener("scroll", onScrollWindow), registeredScrollListeners.set(element, onScrollWindow)), mountedInstances.push(component); } function unregisterScrollListener(component, element) { (mountedInstances = mountedInstances.filter(function(instance) { return instance !== component; })).length || (element.removeEventListener("scroll", onScrollWindow), element.removeEventListener("scroll", registeredScrollListeners.get(element)), registeredScrollListeners.delete(element), disablePointerEventsTimeoutId && (cancelAnimationTimeout(disablePointerEventsTimeoutId), enablePointerEventsIfDisabled())); } var isWindow = function(element) { return element === window; }, getBoundingBox = function(element) { return element.getBoundingClientRect(); }; function getDimensions(scrollElement, props) { if (scrollElement) { if (isWindow(scrollElement)) { var _window = window, innerHeight = _window.innerHeight, innerWidth = _window.innerWidth; return { height: "number" == typeof innerHeight ? innerHeight : 0, width: "number" == typeof innerWidth ? innerWidth : 0 }; } return getBoundingBox(scrollElement); } return { height: props.serverHeight, width: props.serverWidth }; } function getScrollOffset(element) { return isWindow(element) && document.documentElement ? { top: "scrollY" in window ? window.scrollY : document.documentElement.scrollTop, left: "scrollX" in window ? window.scrollX : document.documentElement.scrollLeft } : { top: element.scrollTop, left: element.scrollLeft }; } var scrollEventsMap = new WeakMap(); function createDetectElementResize(nonce, hostWindow) { var _window, cancel, raf, attachEvent = void 0 !== (_window = void 0 !== hostWindow ? hostWindow : "undefined" != typeof window ? window : "undefined" != typeof self ? self : global).document && _window.document.attachEvent; if (!attachEvent) { var requestFrame = (raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame || function(fn) { return _window.setTimeout(fn, 20); }, function(fn) { return raf(fn); }), cancelFrame = (cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame || _window.clearTimeout, function(id) { return cancel(id); }), resetTriggers = function(element) { var triggers = element.__resizeTriggers__, expand = triggers.firstElementChild, contract = triggers.lastElementChild, expandChild = expand.firstElementChild; contract.scrollLeft = contract.scrollWidth, contract.scrollTop = contract.scrollHeight, expandChild.style.width = expand.offsetWidth + 1 + "px", expandChild.style.height = expand.offsetHeight + 1 + "px", expand.scrollLeft = expand.scrollWidth, expand.scrollTop = expand.scrollHeight; }, scrollListener = function(e) { if (!(e.target.className && "function" == typeof e.target.className.indexOf && e.target.className.indexOf("contract-trigger") < 0 && e.target.className.indexOf("expand-trigger") < 0)) { var element = this; resetTriggers(this), this.__resizeRAF__ && cancelFrame(this.__resizeRAF__), this.__resizeRAF__ = requestFrame(function() { !function(element) { return element.offsetWidth != element.__resizeLast__.width || element.offsetHeight != element.__resizeLast__.height; }(element) || (element.__resizeLast__.width = element.offsetWidth, element.__resizeLast__.height = element.offsetHeight, element.__resizeListeners__.forEach(function(fn) { fn.call(element, e); })); }); } }, animation = !1, keyframeprefix = "", animationstartevent = "animationstart", domPrefixes = "Webkit Moz O ms".split(" "), startEvents = "webkitAnimationStart animationstart oAnimationStart MSAnimationStart".split(" "), elm = _window.document.createElement("fakeelement"); if (void 0 !== elm.style.animationName && (animation = !0), !1 === animation) for (var i = 0; i < domPrefixes.length; i++) if (void 0 !== elm.style[domPrefixes[i] + "AnimationName"]) { keyframeprefix = "-" + domPrefixes[i].toLowerCase() + "-", animationstartevent = startEvents[i], animation = !0; break; } var animationName = "resizeanim", animationKeyframes = "@" + keyframeprefix + "keyframes " + animationName + " { from { opacity: 0; } to { opacity: 0; } } ", animationStyle = keyframeprefix + "animation: 1ms " + animationName + "; "; } return { addResizeListener: function(element, fn) { if (attachEvent) element.attachEvent("onresize", fn); else { if (!element.__resizeTriggers__) { var doc = element.ownerDocument, elementStyle = _window.getComputedStyle(element); elementStyle && "static" == elementStyle.position && (element.style.position = "relative"), function(doc) { if (!doc.getElementById("detectElementResize")) { var css = (animationKeyframes || "") + ".resize-triggers { " + (animationStyle || "") + 'visibility: hidden; opacity: 0; } .resize-triggers, .resize-triggers > div, .contract-trigger:before { content: " "; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; z-index: -1; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }', head = doc.head || doc.getElementsByTagName("head")[0], style = doc.createElement("style"); style.id = "detectElementResize", style.type = "text/css", null != nonce && style.setAttribute("nonce", nonce), style.styleSheet ? style.styleSheet.cssText = css : style.appendChild(doc.createTextNode(css)), head.appendChild(style); } }(doc), element.__resizeLast__ = {}, element.__resizeListeners__ = [], (element.__resizeTriggers__ = doc.createElement("div")).className = "resize-triggers"; var expandTrigger = doc.createElement("div"); expandTrigger.className = "expand-trigger", expandTrigger.appendChild(doc.createElement("div")); var contractTrigger = doc.createElement("div"); contractTrigger.className = "contract-trigger", element.__resizeTriggers__.appendChild(expandTrigger), element.__resizeTriggers__.appendChild(contractTrigger), element.appendChild(element.__resizeTriggers__), resetTriggers(element), element.addEventListener("scroll", scrollListener, !0), scrollEventsMap.set(element, scrollListener), animationstartevent && (element.__resizeTriggers__.__animationListener__ = function(e) { e.animationName == animationName && resetTriggers(element); }, element.__resizeTriggers__.addEventListener(animationstartevent, element.__resizeTriggers__.__animationListener__)); } element.__resizeListeners__.push(fn); } }, removeResizeListener: function(element, fn) { if (attachEvent) element.detachEvent("onresize", fn); else if (element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1), !element.__resizeListeners__.length) { element.removeEventListener("scroll", scrollEventsMap.get(element), !0), scrollEventsMap.delete(element), element.__resizeTriggers__.__animationListener__ && (element.__resizeTriggers__.removeEventListener(animationstartevent, element.__resizeTriggers__.__animationListener__), element.__resizeTriggers__.__animationListener__ = null); try { element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__); } catch (e) {} } } }; } var getWindow = function() { return "undefined" != typeof window ? window : void 0; }, WindowScroller = function() { function WindowScroller() { var _getPrototypeOf2, _this; !function(instance, Constructor) { if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); }(this, WindowScroller); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key]; return _this = function(self, call) { return !call || "object" != typeof call && "function" != typeof call ? _assertThisInitialized(self) : call; }(this, (_getPrototypeOf2 = _getPrototypeOf(WindowScroller)).call.apply(_getPrototypeOf2, [ this ].concat(args))), _defineProperty(_assertThisInitialized(_this), "_window", getWindow()), _defineProperty(_assertThisInitialized(_this), "_isMounted", !1), _defineProperty(_assertThisInitialized(_this), "_positionFromTop", 0), _defineProperty(_assertThisInitialized(_this), "_positionFromLeft", 0), _defineProperty(_assertThisInitialized(_this), "_detectElementResize", void 0), _defineProperty(_assertThisInitialized(_this), "_child", void 0), _defineProperty(_assertThisInitialized(_this), "state", function(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(source, !0).forEach(function(key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(source).forEach(function(key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }({}, getDimensions(_this.props.scrollElement, _this.props), { isScrolling: !1, scrollLeft: 0, scrollTop: 0 })), _defineProperty(_assertThisInitialized(_this), "_registerChild", function(element) { !element || element instanceof Element || console.warn("WindowScroller registerChild expects to be passed Element or null"), _this._child = element, _this.updatePosition(); }), _defineProperty(_assertThisInitialized(_this), "_onChildScroll", function(_ref) { var scrollTop = _ref.scrollTop; if (_this.state.scrollTop !== scrollTop) { var scrollElement = _this.props.scrollElement; scrollElement && ("function" == typeof scrollElement.scrollTo ? scrollElement.scrollTo(0, scrollTop + _this._positionFromTop) : scrollElement.scrollTop = scrollTop + _this._positionFromTop); } }), _defineProperty(_assertThisInitialized(_this), "_registerResizeListener", function(element) { element === window ? window.addEventListener("resize", _this._onResize, !1) : _this._detectElementResize.addResizeListener(element, _this._onResize); }), _defineProperty(_assertThisInitialized(_this), "_unregisterResizeListener", function(element) { element === window ? window.removeEventListener("resize", _this._onResize, !1) : element && _this._detectElementResize.removeResizeListener(element, _this._onResize); }), _defineProperty(_assertThisInitialized(_this), "_onResize", function() { _this.updatePosition(); }), _defineProperty(_assertThisInitialized(_this), "__handleWindowScrollEvent", function() { if (_this._isMounted) { var onScroll = _this.props.onScroll, scrollElement = _this.props.scrollElement; if (scrollElement) { var scrollOffset = getScrollOffset(scrollElement), scrollLeft = Math.max(0, scrollOffset.left - _this._positionFromLeft), scrollTop = Math.max(0, scrollOffset.top - _this._positionFromTop); _this.setState({ isScrolling: !0, scrollLeft: scrollLeft, scrollTop: scrollTop }), onScroll({ scrollLeft: scrollLeft, scrollTop: scrollTop }); } } }), _defineProperty(_assertThisInitialized(_this), "__resetIsScrolling", function() { _this.setState({ isScrolling: !1 }); }), _this; } return function(subClass, superClass) { if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function"); subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: !0, configurable: !0 } }), superClass && _setPrototypeOf(subClass, superClass); }(WindowScroller, React.PureComponent), function(Constructor, protoProps, staticProps) { protoProps && _defineProperties(Constructor.prototype, protoProps), staticProps && _defineProperties(Constructor, staticProps); }(WindowScroller, [ { key: "updatePosition", value: function(argument_0) { var scrollElement = 0 < arguments.length && void 0 !== argument_0 ? argument_0 : this.props.scrollElement, onResize = this.props.onResize, _this$state = this.state, height = _this$state.height, width = _this$state.width, thisNode = this._child || ReactDOM.findDOMNode(this); if (thisNode instanceof Element && scrollElement) { var offset = function(element, container) { if (isWindow(container) && document.documentElement) { var containerElement = document.documentElement, elementRect = getBoundingBox(element), containerRect = getBoundingBox(containerElement); return { top: elementRect.top - containerRect.top, left: elementRect.left - containerRect.left }; } var scrollOffset = getScrollOffset(container), _elementRect = getBoundingBox(element), _containerRect = getBoundingBox(container); return { top: _elementRect.top + scrollOffset.top - _containerRect.top, left: _elementRect.left + scrollOffset.left - _containerRect.left }; }(thisNode, scrollElement); this._positionFromTop = offset.top, this._positionFromLeft = offset.left; } var dimensions = getDimensions(scrollElement, this.props); height === dimensions.height && width === dimensions.width || (this.setState({ height: dimensions.height, width: dimensions.width }), onResize({ height: dimensions.height, width: dimensions.width })), !0 === this.props.updateScrollTopOnUpdatePosition && (this.__handleWindowScrollEvent(), this.__resetIsScrolling()); } }, { key: "componentDidMount", value: function() { var scrollElement = this.props.scrollElement; this._detectElementResize = createDetectElementResize(), this.updatePosition(scrollElement), scrollElement && (registerScrollListener(this, scrollElement), this._registerResizeListener(scrollElement)), this._isMounted = !0; } }, { key: "componentDidUpdate", value: function(prevProps) { var scrollElement = this.props.scrollElement, prevScrollElement = prevProps.scrollElement; prevScrollElement !== scrollElement && null != prevScrollElement && null != scrollElement && (this.updatePosition(scrollElement), unregisterScrollListener(this, prevScrollElement), registerScrollListener(this, scrollElement), this._unregisterResizeListener(prevScrollElement), this._registerResizeListener(scrollElement)); } }, { key: "componentWillUnmount", value: function() { var scrollElement = this.props.scrollElement; scrollElement && (unregisterScrollListener(this, scrollElement), this._unregisterResizeListener(scrollElement)), this._isMounted = !1; } }, { key: "render", value: function() { var children = this.props.children, _this$state2 = this.state, isScrolling = _this$state2.isScrolling, scrollTop = _this$state2.scrollTop, scrollLeft = _this$state2.scrollLeft, height = _this$state2.height, width = _this$state2.width; return children({ onChildScroll: this._onChildScroll, registerChild: this._registerChild, height: height, isScrolling: isScrolling, scrollLeft: scrollLeft, scrollTop: scrollTop, width: width }); } } ]), WindowScroller; }(); _defineProperty(WindowScroller, "defaultProps", { onResize: function() {}, onScroll: function() {}, scrollingResetTimeInterval: 150, scrollElement: getWindow(), serverHeight: 0, serverWidth: 0 }), exports.IS_SCROLLING_TIMEOUT = 150, exports.WindowScroller = WindowScroller, exports.default = WindowScroller, Object.defineProperty(exports, "__esModule", { value: !0 }); });