UNPKG

@cainiaofe/cn-ui-m

Version:
162 lines (161 loc) 7.41 kB
import $i18n from "../../locales/i18n"; import React, { useCallback, useLayoutEffect, useRef, useState, } from 'react'; import { animated, useSpring } from '@react-spring/web'; import { useDrag, useWheel, } from '@use-gesture/react'; import { rubberbandIfOutOfBounds } from "../cn-picker/rubberband"; import { bound } from '../../utils/bound'; import { useLatest } from 'ahooks'; import { measureCSSLength } from "../cn-picker/measure-css-length"; import { supportsPassive } from "../cn-picker/supports-passive"; var classPrefix = 'cn-ui-m-picker-view'; export var Wheel = function (props) { var value = props.value, column = props.column, renderLabel = props.renderLabel; var columnRef = useLatest(column); var onSelectRef = useLatest(props.onSelect); var onSelect = useCallback(function (val) { onSelectRef.current(val, props.index); }, [onSelectRef, props.index]); var _a = useSpring(function () { return ({ from: { y: 0 }, config: { tension: 400, mass: 0.8, }, }); }), y = _a[0].y, api = _a[1]; var draggingRef = useRef(false); var rootRef = useRef(null); var itemHeightMeasureRef = useRef(null); var _b = useState(34), itemHeight = _b[0], setItemHeight = _b[1]; // eslint-disable-next-line react-hooks/exhaustive-deps useLayoutEffect(function () { var itemHeightMeasure = itemHeightMeasureRef.current; if (!itemHeightMeasure) return; var _itemHeight = measureCSSLength(window.getComputedStyle(itemHeightMeasure).getPropertyValue('height')); if (!_itemHeight) return; setItemHeight(_itemHeight); }); useLayoutEffect(function () { if (draggingRef.current) return; if (value === null) return; var targetIndex = columnRef.current.findIndex(function (item) { return item.value === value; }); if (targetIndex < 0) return; var finalPosition = targetIndex * -itemHeight; api.start({ y: finalPosition, immediate: y.goal !== finalPosition }); }, [value, columnRef, itemHeight, api, y.goal]); useLayoutEffect(function () { if (columnRef.current.length === 0) { if (value !== null) { onSelect(null); } } else if (!columnRef.current.some(function (item) { return item.value === value; })) { var firstItem = columnRef.current[0]; onSelect(firstItem.value); } }, [value, columnRef, onSelect]); function scrollSelect(index) { var finalPosition = index * -itemHeight; api.start({ y: finalPosition }); var item = column[index]; if (!item) return; onSelect(item.value); } var handleDrag = function (state) { draggingRef.current = true; var min = -((column.length - 1) * itemHeight); var max = 0; if (state.last) { draggingRef.current = false; var position = state.offset[1] + state.velocity[1] * state.direction[1] * 50; var targetIndex = min < max ? -Math.round(bound(position, min, max) / itemHeight) : 0; scrollSelect(targetIndex); } else { var position = state.offset[1]; api.start({ y: rubberbandIfOutOfBounds(position, min, max, itemHeight * 50, 0.2), }); } }; useDrag(function (state) { state.event.stopPropagation(); handleDrag(state); }, { axis: 'y', from: function () { return [0, y.get()]; }, filterTaps: true, pointer: { touch: true }, target: rootRef, }); useWheel(function (state) { state.event.stopPropagation(); handleDrag(state); }, { axis: 'y', from: function () { return [0, y.get()]; }, preventDefault: true, target: props.mouseWheel ? rootRef : undefined, eventOptions: supportsPassive ? { passive: false } : false, }); var selectedIndex = null; function renderAccessible() { if (selectedIndex === null) return null; var current = column[selectedIndex]; var previousIndex = selectedIndex - 1; var nextIndex = selectedIndex + 1; var previous = column[previousIndex]; var next = column[nextIndex]; return (React.createElement("div", { className: "".concat(classPrefix, "-column-accessible") }, React.createElement("div", { className: "".concat(classPrefix, "-column-accessible-current"), role: "button", "aria-label": current ? $i18n.get({ id: 'TheCurrentSelectionIscurrentLabe_682773133', dm: '当前选择的是:{currentLabel}', }, { currentLabel: current.label }) : $i18n.get({ id: 'NotCurrentlySelected', dm: '当前未选择' }) }, "-"), React.createElement("div", { className: "".concat(classPrefix, "-column-accessible-button"), onClick: function () { if (!previous) return; scrollSelect(previousIndex); }, role: previous ? 'button' : 'text', "aria-label": !previous ? $i18n.get({ id: 'NoPreviousItem', dm: '没有上一项' }) : $i18n.get({ id: 'SelectPreviouspreviousLabel', dm: '选择上一项:{previousLabel}', }, { previousLabel: previous.label }) }, "-"), React.createElement("div", { className: "".concat(classPrefix, "-column-accessible-button"), onClick: function () { if (!next) return; scrollSelect(nextIndex); }, role: next ? 'button' : 'text', "aria-label": !next ? $i18n.get({ id: 'NoNextItem', dm: '没有下一项' }) : $i18n.get({ id: 'SelectTheNextItemnextLabel', dm: '选择下一项:{nextLabel}', }, { nextLabel: next.label }) }, "-"))); } return (React.createElement("div", { className: "".concat(classPrefix, "-column") }, React.createElement("div", { className: "".concat(classPrefix, "-item-height-measure"), ref: itemHeightMeasureRef }), React.createElement(animated.div, { ref: rootRef, style: { translateY: y }, className: "".concat(classPrefix, "-column-wheel"), "aria-hidden": true }, column.map(function (item, index) { var _a; var selected = props.value === item.value; if (selected) selectedIndex = index; function handleClick() { draggingRef.current = false; scrollSelect(index); } return (React.createElement("div", { key: (_a = item.key) !== null && _a !== void 0 ? _a : item.value, "data-selected": item.value === value, className: "".concat(classPrefix, "-column-item"), onClick: handleClick, "aria-hidden": !selected, "aria-label": selected ? 'active' : '' }, React.createElement("div", { className: "".concat(classPrefix, "-column-item-label") }, renderLabel(item)))); })), renderAccessible())); }; Wheel.displayName = 'Wheel';