UNPKG

@react-vant-next/campaign

Version:

React Mobile UI Components based on Vant UI - Next Generation

99 lines (94 loc) 4.22 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var tslib = require('tslib'); var jsxRuntime = require('react/jsx-runtime'); var web = require('@react-spring/web'); var hooks = require('@react-vant-next/hooks'); var utils = require('@react-vant-next/utils'); var cls = require('clsx'); var React = require('react'); const [bem] = utils.createNamespace("floating-panel"); /** Check if EL is scrolling reach its bottom */ function scrollReachBottom(el) { const scrollTop = utils.getScrollTop(el); return scrollTop >= el.scrollHeight - utils.getVisibleHeight(el); } function FloatingPanel(_a) { var { ref } = _a, props = tslib.__rest(_a, ["ref"]); const { className, style, onHeightChange, anchors = [100] } = props; const sortAnchors = React.useMemo(() => anchors.sort((a, b) => a - b), [anchors]); const [minAnchor, maxAnchor] = [ sortAnchors[0], sortAnchors[Math.max(0, sortAnchors.length - 1)], ]; const root = React.useRef(void 0); const header = React.useRef(void 0); const body = React.useRef(void 0); const dragging = React.useRef(false); const draggingStartAt = React.useRef(null); const touch = hooks.useTouch(); const [{ visibleH }, api] = web.useSpring(() => ({ visibleH: minAnchor, config: { tension: 300 }, onChange: () => onHeightChange === null || onHeightChange === void 0 ? void 0 : onHeightChange(visibleH.get()), }), [minAnchor]); React.useImperativeHandle(ref, () => ({ moveTo: height => api.start({ visibleH: height }), })); const onTouchStart = (event) => { touch.start(event); draggingStartAt.current = visibleH.get(); dragging.current = true; }; const onTouchMove = (event) => { const [headerEL, bodyEL] = [header.current, body.current]; touch.move(event); if (visibleH.goal >= maxAnchor && bodyEL) { if (touch.firstMove.current // try going up to body top && ((touch.deltaY.current > 0 && utils.getScrollTop(bodyEL) > 0) // try going down to body bottom || (touch.deltaY.current < 0 && !scrollReachBottom(bodyEL)))) { dragging.current = false; } } if (headerEL && headerEL.contains(event.target)) { dragging.current = true; } if (!dragging.current) return; utils.preventDefault(event, true); api.start({ visibleH: utils.bound(draggingStartAt.current + -touch.deltaY.current, minAnchor, maxAnchor), }); }; const onTouchEnd = () => { const memoDraggingStartAt = draggingStartAt.current; dragging.current = false; draggingStartAt.current = null; touch.reset(); if (memoDraggingStartAt) { const nearestAnchor = findNearestAnchor(sortAnchors, visibleH.get()); api.start({ visibleH: nearestAnchor, from: { visibleH: visibleH.get() }, }); } }; hooks.useEventListener("touchstart", onTouchStart, { target: root, passive: false, }); hooks.useEventListener("touchmove", onTouchMove, { target: root, passive: false }); hooks.useEventListener("touchend", onTouchEnd, { target: root, passive: false }); // 使用类型断言解决 animated.div 不接受 children 属性的问题 const AnimatedDiv = web.animated.div; return (jsxRuntime.jsxs(AnimatedDiv, { ref: root, className: cls(bem(), className), style: Object.assign({ height: maxAnchor, transform: visibleH.to(h => `translateY(calc(100% - ${h}px))`) }, style), children: [jsxRuntime.jsx("div", { ref: header, className: cls(bem("header")), children: jsxRuntime.jsx("div", { className: cls(bem("thumb")) }) }), jsxRuntime.jsx(AnimatedDiv, { ref: body, className: cls(bem("body")), children: props.children })] })); } function findNearestAnchor(anchors, target) { return anchors.reduce((pre, cur) => { return Math.abs(target - pre) < Math.abs(target - cur) ? pre : cur; }); } exports.default = FloatingPanel; //# sourceMappingURL=FloatingPanel.js.map