@vnmfify/core
Version:
```shell npm i @vnmfify/core -S ```
286 lines (248 loc) • 11 kB
JavaScript
import _throttle from "lodash/throttle";
var _excluded = ["className", "loading", "disabled", "headHeight", "reachTop", "pullDistance", "duration", "children", "onRefresh"];
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
import { View } from "@vnxjs/components";
import { nextTick } from "@vnxjs/vnmf";
import classNames from "classnames";
import * as React from "react";
import { Children, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
import Loading from "../loading";
import { prefixClassname } from "../styles";
import { preventDefault } from "../utils/dom/event";
import { addUnitPx } from "../utils/format/unit";
import { usePreviousRef, useToRef } from "../utils/state";
import { useTouch } from "../utils/touch";
import { PullRefreshCompleted, PullRefreshLoading, PullRefreshLoosing, PullRefreshPulling } from "./pull-refresh-children";
import PullRefreshContext from "./pull-refresh.context";
var lodashRoot = require("lodash/_root");
if (typeof lodashRoot.Date === "undefined") {
lodashRoot.Date = Date;
}
var PullRefreshStatus;
(function (PullRefreshStatus) {
PullRefreshStatus["Awaiting"] = "awaiting";
PullRefreshStatus["Pulling"] = "pulling";
PullRefreshStatus["Loosing"] = "loosing";
PullRefreshStatus["Loading"] = "loading";
PullRefreshStatus["Completed"] = "completed";
})(PullRefreshStatus || (PullRefreshStatus = {}));
var TEXT_STATUS = ["pulling", "loosing", "success"];
function usePullRefreshChildren(children) {
return useMemo(() => {
var __children__ = {
content: []
};
Children.forEach(children, child => {
if ( /*#__PURE__*/isValidElement(child)) {
var element = child;
var elementType = element.type;
if (elementType === PullRefreshPulling) {
__children__.pulling = element;
} else if (elementType === PullRefreshLoosing) {
__children__.loosing = element;
} else if (elementType === PullRefreshLoading) {
__children__.loading = element;
} else if (elementType === PullRefreshCompleted) {
__children__.completed = element;
} else {
var _children__$content;
(_children__$content = __children__.content) === null || _children__$content === void 0 ? void 0 : _children__$content.push(child);
}
} else {
var _children__$content2;
(_children__$content2 = __children__.content) === null || _children__$content2 === void 0 ? void 0 : _children__$content2.push(child);
}
});
return __children__;
}, [children]);
}
function getCompletedProps(node) {
if ( /*#__PURE__*/isValidElement(node)) {
var element = node;
return element.props;
}
return {};
}
function PullRefresh(props) {
var {
className,
loading,
disabled = false,
headHeight = 50,
reachTop: reachTopProp = true,
pullDistance: pullDistanceProp,
duration: durationProp = 300,
children: childrenProp,
onRefresh
} = props,
restProps = _objectWithoutProperties(props, _excluded);
var children = usePullRefreshChildren(childrenProp);
var {
completed: completedElement,
content
} = children;
var {
duration: completedDuration = 500
} = getCompletedProps(completedElement);
var statusRef = useRef(PullRefreshStatus.Awaiting);
var [distance, setDistance] = useState(0);
var reachTopPreviousRef = usePreviousRef(reachTopProp);
var reachTopRef = useToRef(reachTopProp);
var durationRef = useRef(0);
var touch = useTouch();
function resetDuration() {
durationRef.current = 0;
}
var isTouchable = useCallback(() => PullRefreshStatus.Loading !== statusRef.current && PullRefreshStatus.Completed !== statusRef.current && !disabled, [disabled]);
var easeDistance = useCallback(distance => {
var pullDistance = +(pullDistanceProp || headHeight);
if (distance > pullDistance) {
if (distance < pullDistance * 2) {
distance = pullDistance + (distance - pullDistance) / 2;
} else {
distance = pullDistance * 1.5 + (distance - pullDistance * 2) / 4;
}
}
return Math.round(distance);
}, [headHeight, pullDistanceProp]);
var checkPosition = useCallback(event => {
if (reachTopRef.current) {
resetDuration();
touch.start(event);
}
}, [reachTopRef, touch]);
var onTouchStart = useCallback(event => {
if (isTouchable()) {
checkPosition(event);
}
}, [checkPosition, isTouchable]);
var updateStatus = useCallback((distance, isLoading) => {
var pullDistance = +(pullDistanceProp || headHeight);
if (isLoading) {
statusRef.current = PullRefreshStatus.Loading;
} else if (distance === 0) {
statusRef.current = PullRefreshStatus.Awaiting;
} else if (distance < pullDistance) {
statusRef.current = PullRefreshStatus.Pulling;
} else {
statusRef.current = PullRefreshStatus.Loosing;
}
setDistance(distance);
}, [headHeight, pullDistanceProp]);
var onTouchMove = useMemo(() => _throttle(event => {
if (isTouchable()) {
if (!reachTopPreviousRef.current) {
checkPosition(event);
}
var {
deltaY
} = touch;
touch.move(event);
if (reachTopRef.current && deltaY >= 0 && touch.isVertical()) {
preventDefault(event);
updateStatus(easeDistance(deltaY));
}
}
}, 16.7), [checkPosition, easeDistance, isTouchable, reachTopPreviousRef, reachTopRef, touch, updateStatus]);
var onTouchEnd = useCallback(() => {
if (reachTopRef.current && isTouchable()) {
durationRef.current = durationProp;
if (statusRef.current === PullRefreshStatus.Loosing) {
updateStatus(headHeight, true);
onRefresh === null || onRefresh === void 0 ? void 0 : onRefresh();
} else {
updateStatus(0);
}
}
}, [durationProp, headHeight, isTouchable, onRefresh, reachTopRef, updateStatus]);
var showCompleted = useCallback(() => {
statusRef.current = PullRefreshStatus.Completed;
resetDuration();
setTimeout(() => nextTick(() => updateStatus(0)), +completedDuration);
}, [completedDuration, updateStatus]);
useEffect(() => {
if (loading) {
updateStatus(headHeight, true);
}
}, [headHeight, loading, updateStatus]);
useEffect(() => {
if (!loading && !isTouchable() && !completedElement) {
durationRef.current = durationProp;
updateStatus(0, false);
}
}, [completedElement, durationProp, isTouchable, loading, updateStatus]);
useEffect(() => {
if (!loading && completedElement) {
showCompleted();
}
}, [completedElement, loading, showCompleted]);
var getStatusText = useCallback(() => {
if (statusRef.current === PullRefreshStatus.Pulling) {
return "Drop it and it'll be refreshed....";
}
if (statusRef.current === PullRefreshStatus.Loosing) {
return "Release and refresh....";
}
if (statusRef.current === PullRefreshStatus.Loading) {
return "Loading...";
}
return "";
}, []);
var renderStatus = useCallback(() => {
var statusSlot = children[statusRef.current];
if (statusSlot) {
return statusSlot;
}
var nodes = [];
if (TEXT_STATUS.includes(statusRef.current)) {
nodes.push( /*#__PURE__*/React.createElement(View, {
key: "text",
className: prefixClassname("pull-refresh__text"),
children: getStatusText()
}));
}
if (statusRef.current === PullRefreshStatus.Loading) {
nodes.push( /*#__PURE__*/React.createElement(Loading, {
key: "loading",
className: prefixClassname("pull-refresh__loading"),
children: getStatusText()
}));
}
return nodes;
}, [children, getStatusText]);
var trackStyle = {
transitionDuration: "".concat(durationRef.current, "ms"),
transform: distance ? "translate3d(0,".concat(addUnitPx(distance), ", 0)") : ""
};
var headStyle = useMemo(() => {
if (headHeight !== 50) {
return {
height: addUnitPx(headHeight)
};
}
}, [headHeight]);
return /*#__PURE__*/React.createElement(PullRefreshContext.Provider, {
value: {
distance
}
}, /*#__PURE__*/React.createElement(View, _objectSpread({
className: classNames(prefixClassname("pull-refresh"), className)
}, restProps), /*#__PURE__*/React.createElement(View, {
className: prefixClassname("pull-refresh__track"),
style: trackStyle,
onTouchStart: onTouchStart,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd,
onTouchCancel: onTouchEnd
}, /*#__PURE__*/React.createElement(View, {
className: prefixClassname("pull-refresh__head"),
style: headStyle,
children: renderStatus()
}), content)));
}
export default PullRefresh;
//# sourceMappingURL=pull-refresh.js.map