rv-window-scroller
Version:
Window scroller component for react-virtualized and react-window
358 lines (357 loc) • 23.8 kB
JavaScript
!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
});
});