@bytedance/mona-client-web
Version:
web for mona
152 lines • 7.58 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import React, { useLayoutEffect, useMemo, useRef } from 'react';
import styles from './index.module.less';
import { useHandlers } from '../hooks';
import { formatSyntheticEvent } from '../utils';
//t = current time
//b = start value
//c = change in value
//d = duration
function easeInOutQuad(t, b, c, d) {
t /= d / 2;
if (t < 1)
return c / 2 * t * t + b;
t--;
return -c / 2 * (t * (t - 2) - 1) + b;
}
;
function scrollToWithAnimation(element, to, duration, vertical) {
var start = vertical ? element.scrollTop : element.scrollLeft;
var change = to - start;
var currentTime = 0;
var increment = 20;
var animateScroll = function () {
currentTime += increment;
var val = easeInOutQuad(currentTime, start, change, duration);
if (vertical) {
element.scrollTop = val;
}
else {
element.scrollLeft = val;
}
if (currentTime < duration) {
setTimeout(animateScroll, increment);
}
};
animateScroll();
}
export var ScrollViewContext = React.createContext(null);
var ScrollView = function (props) {
var children = props.children, scrollIntoView = props.scrollIntoView, upperThreshold = props.upperThreshold, lowerThreshold = props.lowerThreshold, scrollWithAnimation = props.scrollWithAnimation, scrollTop = props.scrollTop, scrollLeft = props.scrollLeft, scrollX = props.scrollX, scrollY = props.scrollY, onScroll = props.onScroll, onScrollToUpper = props.onScrollToUpper, onScrollToLower = props.onScrollToLower, restProps = __rest(props, ["children", "scrollIntoView", "upperThreshold", "lowerThreshold", "scrollWithAnimation", "scrollTop", "scrollLeft", "scrollX", "scrollY", "onScroll", "onScrollToUpper", "onScrollToLower"]);
var _a = useHandlers(restProps), handleClassName = _a.handleClassName, handleProps = __rest(_a, ["handleClassName"]);
var scrollRef = useRef(null);
var topPreRef = useRef(0);
var leftPreRef = useRef(0);
var cbRefs = useRef([]);
var context = useMemo(function () { return ({
registerScrollCallback: function (callback) {
cbRefs.current.push(callback);
},
unregisterScrollCallback: function (callback) {
var index = cbRefs.current.indexOf(callback);
cbRefs.current.splice(index, 1);
}
}); }, []);
var overflow = "".concat(scrollX ? 'auto' : 'hidden', " ").concat(scrollY ? 'auto' : 'hidden');
var handleScroll = function (e) {
if (typeof onScroll === 'function') {
onScroll(formatSyntheticEvent({ event: e }));
}
if (scrollRef.current) {
cbRefs.current.forEach(function (cb) { return cb(scrollRef.current); });
var top_1 = scrollRef.current.scrollTop;
var left = scrollRef.current.scrollLeft;
var currentUpperThreshold = upperThreshold || 0;
var currentLowerThreshold = lowerThreshold || 0;
if (typeof onScrollToUpper === 'function') {
if (scrollY && ((currentUpperThreshold > topPreRef.current && currentUpperThreshold <= top_1) || (currentUpperThreshold < topPreRef.current && currentUpperThreshold >= top_1))) {
onScrollToUpper(formatSyntheticEvent({ event: e, type: 'scrolltoupper' }));
}
if (scrollX && ((currentUpperThreshold > leftPreRef.current && currentUpperThreshold <= left) || (currentUpperThreshold < leftPreRef.current && currentUpperThreshold >= left))) {
onScrollToUpper(formatSyntheticEvent({ event: e, type: 'scrolltoupper' }));
}
}
if (typeof onScrollToLower === 'function') {
if (scrollY) {
var clientHeight = scrollRef.current.clientHeight;
var scrollHeight = scrollRef.current.scrollHeight;
var currentLower = scrollHeight - clientHeight - top_1;
var prevLower = scrollHeight - clientHeight - topPreRef.current;
if ((currentLowerThreshold > prevLower && currentLowerThreshold <= currentLower) || (currentLowerThreshold < prevLower && currentLowerThreshold >= currentLower)) {
onScrollToLower(formatSyntheticEvent({ event: e, type: 'scrolltolower' }));
}
}
if (scrollX) {
var clientWidth = scrollRef.current.clientWidth;
var scrollWidth = scrollRef.current.scrollWidth;
var currentLower = scrollWidth - clientWidth - left;
var prevLower = scrollWidth - clientWidth - leftPreRef.current;
if ((currentLowerThreshold > prevLower && currentLowerThreshold <= currentLower) || (currentLowerThreshold < prevLower && currentLowerThreshold >= currentLower)) {
onScrollToLower(formatSyntheticEvent({ event: e, type: 'scrolltolower' }));
}
}
}
topPreRef.current = top_1;
leftPreRef.current = left;
}
};
useLayoutEffect(function () {
if (scrollY && scrollRef.current && scrollTop != null) {
if (scrollWithAnimation) {
scrollToWithAnimation(scrollRef.current, scrollTop, 300, true);
}
else {
scrollRef.current.scrollTop = scrollTop;
}
}
}, [scrollTop, scrollY, scrollWithAnimation]);
useLayoutEffect(function () {
if (scrollX && scrollRef.current && scrollLeft != null) {
if (scrollWithAnimation) {
scrollToWithAnimation(scrollRef.current, scrollLeft, 300, false);
}
else {
scrollRef.current.scrollLeft = scrollLeft;
}
}
}, [scrollLeft, scrollX, scrollWithAnimation]);
useLayoutEffect(function () {
if (scrollRef.current && scrollIntoView) {
var $target = scrollRef.current.querySelector("#".concat(scrollIntoView));
if ($target) {
$target.scrollIntoView({ behavior: scrollWithAnimation ? 'smooth' : 'auto', block: 'start', inline: 'start' });
}
}
}, [scrollIntoView, scrollWithAnimation]);
return (React.createElement("div", __assign({}, handleProps, { className: handleClassName(styles.container) }),
React.createElement("div", { ref: scrollRef, className: styles.container, onScroll: handleScroll, style: { overflow: overflow } },
React.createElement(ScrollViewContext.Provider, { value: context }, children))));
};
export default ScrollView;
//# sourceMappingURL=index.js.map