zent
Version:
一套前端设计语言和基于React的实现
228 lines (227 loc) • 10.1 kB
JavaScript
import { __extends } from "tslib";
import { jsx as _jsx } from "react/jsx-runtime";
import { Children, cloneElement, createRef, PureComponent } from 'react';
import { addEventListener } from '../utils/component/event-handler';
import { isForwardRef } from 'react-is';
import { computeOffsetPixels } from './offset';
import isDOMElement from '../utils/isDOMElement';
import { getCurrentPosition } from './position';
import isBrowser from '../utils/isBrowser';
import defer from '../utils/defer';
import { parseBorderWidth, parseFontSize } from './cssom';
var DEFAULT_OFFSET = 0;
var Waypoint = (function (_super) {
__extends(Waypoint, _super);
function Waypoint() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.refElement = createRef();
_this.previousPosition = 4;
_this.handleScroll = function (event) {
if (!_this.refElement.current) {
return;
}
var bounds = _this.getBounds();
var currentPosition = getCurrentPosition(bounds);
var previousPosition = _this.previousPosition;
var _a = _this.props, onPositionChange = _a.onPositionChange, onEnter = _a.onEnter, onLeave = _a.onLeave, fireOnRapidScroll = _a.fireOnRapidScroll;
_this.previousPosition = currentPosition;
if (previousPosition === currentPosition) {
return;
}
var callbackArg = {
currentPosition: currentPosition,
previousPosition: previousPosition,
event: event,
waypointTop: bounds.waypointTop,
waypointBottom: bounds.waypointBottom,
viewportTop: bounds.viewportTop,
viewportBottom: bounds.viewportBottom,
};
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(callbackArg);
if (currentPosition === 1) {
onEnter === null || onEnter === void 0 ? void 0 : onEnter(callbackArg);
}
else if (previousPosition === 1 ||
previousPosition === 4) {
onLeave === null || onLeave === void 0 ? void 0 : onLeave(callbackArg);
}
var isRapidScrollDown = previousPosition === 2 &&
currentPosition === 0;
var isRapidScrollUp = previousPosition === 0 &&
currentPosition === 2;
if (fireOnRapidScroll && (isRapidScrollDown || isRapidScrollUp)) {
onEnter === null || onEnter === void 0 ? void 0 : onEnter({
currentPosition: 1,
previousPosition: previousPosition,
event: event,
waypointTop: bounds.waypointTop,
waypointBottom: bounds.waypointBottom,
viewportTop: bounds.viewportTop,
viewportBottom: bounds.viewportBottom,
});
onLeave === null || onLeave === void 0 ? void 0 : onLeave({
currentPosition: currentPosition,
previousPosition: 1,
event: event,
waypointTop: bounds.waypointTop,
waypointBottom: bounds.waypointBottom,
viewportTop: bounds.viewportTop,
viewportBottom: bounds.viewportBottom,
});
}
};
return _this;
}
Waypoint.prototype.componentDidMount = function () {
var _this = this;
if (!isBrowser) {
return;
}
this.cancelOnNextTick = defer(function () {
_this.cancelOnNextTick = null;
var children = _this.props.children;
ensureRefIsUsedByChild(children, _this.refElement.current);
_this.scrollableAncestor = _this.findScrollableAncestor();
_this.scrollEventListenerUnsubscribe = addEventListener(_this.scrollableAncestor, 'scroll', _this.handleScroll, { passive: true });
_this.resizeEventListenerUnsubscribe = addEventListener(window, 'resize', _this.handleScroll, { passive: true });
_this.handleScroll(null);
});
};
Waypoint.prototype.componentDidUpdate = function () {
var _this = this;
if (!isBrowser) {
return;
}
if (!this.scrollableAncestor) {
return;
}
if (this.cancelOnNextTick) {
return;
}
this.cancelOnNextTick = defer(function () {
_this.cancelOnNextTick = null;
_this.handleScroll(null);
});
};
Waypoint.prototype.componentWillUnmount = function () {
var _a, _b, _c;
if (!isBrowser) {
return;
}
(_a = this.scrollEventListenerUnsubscribe) === null || _a === void 0 ? void 0 : _a.call(this);
(_b = this.resizeEventListenerUnsubscribe) === null || _b === void 0 ? void 0 : _b.call(this);
(_c = this.cancelOnNextTick) === null || _c === void 0 ? void 0 : _c.cancel();
};
Waypoint.prototype.findScrollableAncestor = function () {
var _a = this.props, horizontal = _a.horizontal, scrollableAncestor = _a.scrollableAncestor;
if (scrollableAncestor) {
return scrollableAncestor;
}
var node = this.refElement.current;
while (node.parentNode) {
node = node.parentNode;
if (node === document.body) {
return window;
}
var style = getComputedStyle(node);
var overflowDirec = horizontal
? style.getPropertyValue('overflow-x')
: style.getPropertyValue('overflow-y');
var overflow = overflowDirec || style.getPropertyValue('overflow');
if (overflow === 'auto' || overflow === 'scroll') {
return node;
}
}
return window;
};
Waypoint.prototype.getBounds = function () {
var horizontal = this.props.horizontal;
var _a = this.refElement.current.getBoundingClientRect(), left = _a.left, top = _a.top, right = _a.right, bottom = _a.bottom;
var waypointTop = horizontal ? left : top;
var waypointBottom = horizontal ? right : bottom;
var contextHeight;
var contextScrollTop;
if (this.scrollableAncestor === window) {
contextHeight = horizontal ? window.innerWidth : window.innerHeight;
contextScrollTop = 0;
}
else {
var node = this.scrollableAncestor;
var boundingBox = node.getBoundingClientRect();
contextHeight = horizontal ? boundingBox.width : boundingBox.height;
contextScrollTop = horizontal ? boundingBox.left : boundingBox.top;
}
var topOffsetPx = this.getOffset('top', contextHeight);
var bottomOffsetPx = this.getOffset('bottom', contextHeight);
var contextBottom = contextScrollTop + contextHeight;
return {
waypointTop: waypointTop,
waypointBottom: waypointBottom,
viewportTop: contextScrollTop + topOffsetPx,
viewportBottom: contextBottom - bottomOffsetPx,
};
};
Waypoint.prototype.getOffset = function (pos, contextHeight) {
var _a, _b;
var horizontal = this.props.horizontal;
var prop = pos + "Offset";
var border = pos === 'top'
? "border" + (horizontal ? 'Left' : 'Top') + "Width"
: "border" + (horizontal ? 'Right' : 'Bottom') + "Width";
var propOffset = this.props[prop];
if (propOffset !== 'auto') {
return computeOffsetPixels(propOffset, contextHeight);
}
if (this.scrollableAncestor === window) {
var styles_1 = getComputedStyle(document.documentElement);
var getFontSize = function () { return parseFontSize(styles_1.fontSize); };
return ((_a = parseBorderWidth(styles_1[border], getFontSize, getFontSize)) !== null && _a !== void 0 ? _a : DEFAULT_OFFSET);
}
else {
var styles_2 = getComputedStyle(this.scrollableAncestor);
var getFontSize = function () { return parseFontSize(styles_2.fontSize); };
var getRootFontSize = function () {
return parseFontSize(getComputedStyle(document.documentElement).fontSize);
};
return ((_b = parseBorderWidth(styles_2[border], getFontSize, getRootFontSize)) !== null && _b !== void 0 ? _b : DEFAULT_OFFSET);
}
};
Waypoint.prototype.render = function () {
var _this = this;
var children = this.props.children;
if (!children) {
return (_jsx("span", { ref: this.refElement, style: { fontSize: 0 }, className: "zent-waypoint-marker", "data-zv": '10.0.17' }, void 0));
}
var child = Children.only(children);
if (isDOMElement(child) || isForwardRef(child)) {
var ref = function (node) {
_this.refElement.current = node;
var chRef = child.ref;
if (chRef) {
if (typeof chRef === 'function') {
chRef(node);
}
else {
chRef.current = node;
}
}
};
return cloneElement(child, { ref: ref });
}
return cloneElement(child, { innerRef: this.refElement });
};
Waypoint.defaultProps = {
topOffset: DEFAULT_OFFSET,
bottomOffset: DEFAULT_OFFSET,
horizontal: false,
fireOnRapidScroll: true,
};
return Waypoint;
}(PureComponent));
export { Waypoint };
function ensureRefIsUsedByChild(children, ref) {
if (children && !isDOMElement(children) && !ref) {
throw new Error('<Waypoint> needs a DOM element to compute boundaries. The child you passed is neither a ' +
'DOM element (e.g. <div>) nor does it use the innerRef prop.\n');
}
}