@chatui/core
Version:
The React library for Chatbot UI
234 lines (233 loc) • 9.62 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PullToRefresh = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _clsx = _interopRequireDefault(require("clsx"));
var _style = require("../../utils/style");
var _Icon = require("../Icon");
var _Flex = require("../Flex");
var _Button = require("../Button");
var _canUse = _interopRequireDefault(require("../../utils/canUse"));
var _smoothScroll = _interopRequireDefault(require("../../utils/smoothScroll"));
var _useLatest = require("../../hooks/useLatest");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
var canPassive = (0, _canUse.default)('passiveListener');
var passiveOpts = canPassive ? {
passive: true
} : false;
var nonPassiveOpts = canPassive ? {
passive: false
} : false;
var PullToRefresh = exports.PullToRefresh = /*#__PURE__*/_react.default.forwardRef(function (props, ref) {
var _props$distance = props.distance,
oDistance = _props$distance === void 0 ? 20 : _props$distance,
_props$loadingDistanc = props.loadingDistance,
loadingDistance = _props$loadingDistanc === void 0 ? 30 : _props$loadingDistanc,
_props$maxDistance = props.maxDistance,
maxDistance = _props$maxDistance === void 0 ? 60 : _props$maxDistance,
_props$distanceRatio = props.distanceRatio,
distanceRatio = _props$distanceRatio === void 0 ? 2 : _props$distanceRatio,
_props$loadMoreText = props.loadMoreText,
loadMoreText = _props$loadMoreText === void 0 ? '点击加载更多' : _props$loadMoreText,
children = props.children,
onScroll = props.onScroll,
onRefresh = props.onRefresh,
_props$renderIndicato = props.renderIndicator,
renderIndicator = _props$renderIndicato === void 0 ? function (status) {
if (status === 'active' || status === 'loading') {
return /*#__PURE__*/_react.default.createElement(_Icon.Icon, {
className: "PullToRefresh-spinner",
type: "spinner",
spin: true
});
}
return null;
} : _props$renderIndicato;
var wrapperRef = (0, _react.useRef)(null);
var contentRef = (0, _react.useRef)(null);
var onRefreshRef = (0, _useLatest.useLatest)(onRefresh);
var _useState = (0, _react.useState)(0),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
distance = _useState2[0],
setDistance = _useState2[1];
var _useState3 = (0, _react.useState)('pending'),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
status = _useState4[0],
setStatus = _useState4[1];
var _useState5 = (0, _react.useState)(false),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
dropped = _useState6[0],
setDropped = _useState6[1];
var _useState7 = (0, _react.useState)(!props.onRefresh),
_useState8 = (0, _slicedToArray2.default)(_useState7, 2),
disabled = _useState8[0],
setDisabled = _useState8[1];
var sharedRef = (0, _react.useRef)({});
var statusRef = (0, _react.useRef)(status);
var timer1 = (0, _react.useRef)();
var timer2 = (0, _react.useRef)();
var useFallback = !(0, _canUse.default)('touch');
(0, _react.useEffect)(function () {
statusRef.current = status;
}, [status]);
var setContentStyle = function setContentStyle(y) {
var content = contentRef.current;
if (content) {
(0, _style.setTransform)(content, "translate3d(0px,".concat(y, "px,0)"));
}
};
var scrollTo = function scrollTo(_ref) {
var y = _ref.y,
_ref$animated = _ref.animated,
animated = _ref$animated === void 0 ? true : _ref$animated;
var scroller = wrapperRef.current;
if (!scroller) return;
var offsetTop = y === '100%' ? scroller.scrollHeight - scroller.offsetHeight : y;
if (animated) {
(0, _smoothScroll.default)({
el: scroller,
to: offsetTop,
x: false
});
} else {
scroller.scrollTop = offsetTop;
}
};
var scrollToEnd = (0, _react.useCallback)(function () {
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref2$animated = _ref2.animated,
animated = _ref2$animated === void 0 ? true : _ref2$animated;
scrollTo({
y: '100%',
animated: animated
});
}, []);
var reset = (0, _react.useCallback)(function () {
setDistance(0);
setStatus('pending');
setContentStyle(0);
}, []);
var handleLoadMore = (0, _react.useCallback)(function () {
var scroller = wrapperRef.current;
if (!scroller || !onRefreshRef.current) return;
setStatus('loading');
try {
var sh = scroller.scrollHeight;
onRefreshRef.current().then(function (res) {
var handleOffset = function handleOffset() {
scrollTo({
y: scroller.scrollHeight - sh - 50,
animated: false
});
};
clearTimeout(timer1.current);
clearTimeout(timer2.current);
handleOffset();
timer1.current = setTimeout(handleOffset, 150);
timer2.current = setTimeout(handleOffset, 250);
reset();
if (res && res.noMore) {
setDisabled(true);
}
});
} catch (ex) {
// eslint-disable-next-line no-console
console.error(ex);
reset();
}
}, [onRefreshRef, reset]);
var touchStart = function touchStart() {
sharedRef.current.startY = 0;
};
var touchMove = (0, _react.useCallback)(function (e) {
var _wrapperRef$current;
var currentY = e.touches[0].clientY;
var canPull = ((_wrapperRef$current = wrapperRef.current) === null || _wrapperRef$current === void 0 ? void 0 : _wrapperRef$current.scrollTop) <= 0;
if (canPull) {
if (!sharedRef.current.startY) {
sharedRef.current.startY = currentY;
setStatus('pull');
setDropped(false);
}
} else {
sharedRef.current.startY = 0;
}
var startY = sharedRef.current.startY;
if (!canPull || currentY < startY || statusRef.current === 'loading') return;
var dist = (currentY - startY) / distanceRatio;
if (maxDistance && dist > maxDistance) {
dist = maxDistance;
}
if (dist > 0) {
if (e.cancelable) {
e.preventDefault();
}
e.stopPropagation();
setContentStyle(dist);
setDistance(dist);
setStatus(dist >= oDistance ? 'active' : 'pull');
}
}, [distanceRatio, maxDistance, oDistance]);
var touchEnd = (0, _react.useCallback)(function () {
setDropped(true);
if (sharedRef.current.startY && statusRef.current === 'active') {
handleLoadMore();
} else {
reset();
}
}, [handleLoadMore, reset]);
(0, _react.useEffect)(function () {
var wrapper = wrapperRef.current;
if (!wrapper || useFallback) return;
if (disabled) {
wrapper.removeEventListener('touchstart', touchStart);
wrapper.removeEventListener('touchmove', touchMove);
wrapper.removeEventListener('touchend', touchEnd);
wrapper.removeEventListener('touchcancel', touchEnd);
} else {
wrapper.addEventListener('touchstart', touchStart, passiveOpts);
wrapper.addEventListener('touchmove', touchMove, nonPassiveOpts);
wrapper.addEventListener('touchend', touchEnd);
wrapper.addEventListener('touchcancel', touchEnd);
}
}, [disabled, touchEnd, touchMove, useFallback]);
(0, _react.useEffect)(function () {
if (status === 'loading' && !useFallback) {
setContentStyle(loadingDistance);
}
}, [loadingDistance, status, useFallback]);
(0, _react.useImperativeHandle)(ref, function () {
return {
scrollTo: scrollTo,
scrollToEnd: scrollToEnd,
wrapperRef: wrapperRef
};
}, [scrollToEnd]);
return /*#__PURE__*/_react.default.createElement("div", {
className: "PullToRefresh",
ref: wrapperRef,
onScroll: onScroll
}, /*#__PURE__*/_react.default.createElement("div", {
className: "PullToRefresh-inner"
}, /*#__PURE__*/_react.default.createElement("div", {
className: (0, _clsx.default)('PullToRefresh-content', {
'PullToRefresh-transition': dropped
}),
ref: contentRef
}, /*#__PURE__*/_react.default.createElement("div", {
className: "PullToRefresh-indicator"
}, renderIndicator(status, distance)), !disabled && useFallback && /*#__PURE__*/_react.default.createElement(_Flex.Flex, {
className: "PullToRefresh-fallback",
center: true
}, renderIndicator(status, oDistance), /*#__PURE__*/_react.default.createElement(_Button.Button, {
className: "PullToRefresh-loadMore",
variant: "text",
onClick: handleLoadMore
}, loadMoreText)), _react.default.Children.only(children))));
});