UNPKG

@bytedance/mona-client-web

Version:

web for mona

194 lines 9.77 kB
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; }; // 参考arco Mobile import React, { useCallback, useEffect, useMemo, useRef, useState, useLayoutEffect } from 'react'; import { PickerCellMovingStatus } from '../Picker/type'; import { useRefState } from '../Picker/hooks'; import { getStyleWithVendor } from '../../utils/style'; import styles from '../PickerView/index.module.less'; var PickerCell = function (props) { var data = props.data, itemHeight = props.itemHeight, wrapperHeight = props.wrapperHeight, selectedValue = props.selectedValue, onValueChange = props.onValueChange, _a = props.rows, rows = _a === void 0 ? 5 : _a, restProps = __rest(props, ["data", "itemHeight", "wrapperHeight", "selectedValue", "onValueChange", "rows"]); var _b = useState(''), transitionDuration = _b[0], setTransitionDuration = _b[1]; var _c = useState(''), bezier = _c[0], setBezier = _c[1]; var _d = useState(0), currentIndex = _d[0], setCurrentIndex = _d[1]; var _e = useState(selectedValue), currentValue = _e[0], setCurrentValue = _e[1]; var _f = useRefState(0), transformY = _f[0], transformYRef = _f[1], setTransformY = _f[2]; var lastTransformYRef = useRef(0); var touchStartTimeRef = useRef(0); var latestCallbackTimer = useRef(0); var touchStartYRef = useRef(0); var touchingRef = useRef(false); var wrapRef = useRef(null); var movingStatusRef = useRef(PickerCellMovingStatus.normal); var rowCount = Math.max(rows % 2 === 0 ? rows + 1 : rows, 3); var colStyle = useMemo(function () { return getStyleWithVendor(__assign(__assign({ transform: "translate3d(0px, ".concat(transformY || 0, "px, 0px)") }, (transitionDuration ? { transitionDuration: transitionDuration } : {})), { transitionTimingFunction: bezier, paddingBottom: "".concat(((rowCount - 1) / 2) * itemHeight, "px"), paddingTop: "".concat(((rowCount - 1) / 2) * itemHeight, "px") })); }, [transitionDuration, transformY, bezier, itemHeight, rowCount]); function scrollingComplete(nowItemIndex) { var _a; if (currentIndex !== nowItemIndex) { setCurrentIndex(nowItemIndex); var newValue = (_a = data[nowItemIndex]) === null || _a === void 0 ? void 0 : _a.value; if (newValue !== currentValue) { setCurrentValue(newValue); onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(newValue); } } } var scrollTo = useCallback(function (transY, transDuration, cb) { if (transDuration === void 0) { transDuration = 0; } if (cb === void 0) { cb = function () { }; } setTransitionDuration(transDuration ? "".concat(transDuration, "ms") : ''); setTransformY(transY); if (latestCallbackTimer.current) { clearTimeout(latestCallbackTimer.current); } latestCallbackTimer.current = window.setTimeout(function () { movingStatusRef.current = PickerCellMovingStatus.normal; setTransitionDuration(''); cb(); }, transDuration); }, []); function scrollToIndex(itemIndex, transDuration) { if (transDuration === void 0) { transDuration = 0; } scrollTo(-1 * itemIndex * itemHeight, transDuration, function () { scrollingComplete(itemIndex); }); } var handleColumnTouchStart = useCallback(function (e) { movingStatusRef.current = PickerCellMovingStatus.moving; var y = e.touches[0].screenY; touchStartTimeRef.current = Number(new Date()); touchingRef.current = true; touchStartYRef.current = y; lastTransformYRef.current = transformYRef.current; }, []); var handleColumnTouchMove = useCallback(function (e) { if (!touchingRef.current) { return; } e.cancelable && e.preventDefault(); var lastTransformY = lastTransformYRef.current; var touchMoveY = e.touches[0].screenY; var distance = touchMoveY - touchStartYRef.current; var newPos = lastTransformY + distance; var maxPos = -1 * (data.length - 1) * itemHeight; setTransformY((lastTransformY >= 0 && distance > 0) || (lastTransformY <= maxPos && distance < 0) ? lastTransformY + distance / 4 : newPos); }, [data.length, itemHeight]); useEffect(function () { var _a, _b; (_a = wrapRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener('touchstart', handleColumnTouchStart); (_b = wrapRef.current) === null || _b === void 0 ? void 0 : _b.addEventListener('touchmove', handleColumnTouchMove); return function () { var _a, _b; (_a = wrapRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('touchstart', handleColumnTouchStart); (_b = wrapRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('touchmove', handleColumnTouchMove); }; }, [handleColumnTouchStart, handleColumnTouchMove]); function handleScrollEnd() { var maxIndex = data.length - 1; var nowIndex = Math.max(0, Math.min(maxIndex, Math.round((-1 * transformY) / itemHeight))); scrollToIndex(nowIndex, 100); } // 参考:https://juejin.im/post/6844904185121488910 //@ts-ignore function momentum(current, start, duration, minY, maxY) { var durationMap = { noBounce: 800, weekBounce: 800, strongBounce: 400, }; var bezierMap = { noBounce: 'cubic-bezier(.17, .89, .45, 1)', weekBounce: 'cubic-bezier(.25, .46, .45, .94)', strongBounce: 'cubic-bezier(.25, .46, .45, .94)', }; var type = 'noBounce'; var deceleration = 0.003; var bounceRate = 5; var bounceThreshold = 300; var maxOverflowY = wrapperHeight / 6; var overflowY; var distance = current - start; var speed = (2 * Math.abs(distance)) / duration; var destination = current + (speed / deceleration) * (distance < 0 ? -1 : 1); if (destination < minY) { overflowY = minY - destination; type = overflowY > bounceThreshold ? 'strongBounce' : 'weekBounce'; destination = Math.max(minY - maxOverflowY, minY - overflowY / bounceRate); } else if (destination > maxY) { overflowY = destination - maxY; type = overflowY > bounceThreshold ? 'strongBounce' : 'weekBounce'; destination = Math.min(maxY + maxOverflowY, maxY + overflowY / bounceRate); } return { destination: destination, duration: durationMap[type], bezier: bezierMap[type], }; } function handleColumnTouchEnd() { movingStatusRef.current = PickerCellMovingStatus.normal; var lastTransformY = lastTransformYRef.current; if (transformY === lastTransformY) { return; } touchingRef.current = false; var endTime = Number(new Date()); var scrollerHeight = (data.length + rowCount - 1) * itemHeight; var duration = endTime - touchStartTimeRef.current; var absDistY = Math.abs(transformY - lastTransformY); if (duration < 300 && absDistY > 30) { var momentumY = momentum(transformY, lastTransformY, duration, wrapperHeight - scrollerHeight, 0); var newItemIndex = Math.max(0, Math.min(data.length - 1, Math.round((-1 * momentumY.destination) / itemHeight))); setBezier(momentumY.bezier); movingStatusRef.current = PickerCellMovingStatus.scrolling; scrollToIndex(newItemIndex, momentumY.duration); } else { handleScrollEnd(); } } function handleItemClick(itemIndex) { scrollToIndex(itemIndex, 100); } useLayoutEffect(function () { if ('selectedValue' in props) { var curIndex = data.findIndex(function (item) { return item.value === selectedValue; }); setCurrentIndex(curIndex); if (curIndex >= 0) { scrollToIndex(curIndex, 0); } } //@ts-ignore }, [selectedValue, itemHeight]); return (data === null || data === void 0 ? void 0 : data.length) ? (React.createElement("div", __assign({ className: styles.pickerViewColumn }, restProps), React.createElement("div", { className: styles.pickerViewColumnItemWrap, style: colStyle, ref: wrapRef, onTouchEnd: handleColumnTouchEnd, onTouchCancel: handleColumnTouchEnd }, data.map(function (item, index) { return (React.createElement("div", { key: "".concat(item.value).concat(index), style: { height: itemHeight }, onClick: function () { return handleItemClick(index); } }, item.label)); })))) : null; }; export default PickerCell; //# sourceMappingURL=pickerCell.js.map