UNPKG

@vnmfify/core

Version:

```shell npm i @vnmfify/core -S ```

286 lines (248 loc) 11 kB
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