@cainiaofe/cn-ui-m
Version:
162 lines (161 loc) • 7.41 kB
JavaScript
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';