@vnmfify/core
Version:
```shell npm i @vnmfify/core -S ```
283 lines (242 loc) • 11.8 kB
JavaScript
import _omit from "lodash/omit";
import _map from "lodash/map";
import _findIndex from "lodash/findIndex";
import _clamp from "lodash/clamp";
import _size from "lodash/size";
var _excluded = ["value", "className", "readonly", "children", "onChange", "onTouchStart", "onTouchMove", "onTouchEnd", "onTouchCancel"];
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; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
import { View } from "@vnxjs/components";
import classNames from "classnames";
import * as React from "react";
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
import { prefixClassname } from "../styles";
import { getComputedStyle } from "../utils/dom/computed-style";
import { preventDefault } from "../utils/dom/event";
import { addUnitPx } from "../utils/format/unit";
import { fulfillPromise } from "../utils/promisify";
import { useRendered, useRenderedRef, useToRef } from "../utils/state";
import { useTouch } from "../utils/touch";
import PickerOption from "./picker-option";
import { getPickerOptionKey } from "./picker.shared";
var MOMENTUM_LIMIT_TIME = 300;
var MOMENTUM_LIMIT_DISTANCE = 15;
function getElementTranslateY(_x) {
return _getElementTranslateY.apply(this, arguments);
}
function _getElementTranslateY() {
_getElementTranslateY = _asyncToGenerator(function* (element) {
var style = yield getComputedStyle(element, ["transform", "webkitTransform"]);
var transform = style.transform || style.webkitTransform;
var translateY = transform.slice(7, transform.length - 1).split(", ")[5];
return Number(translateY);
});
return _getElementTranslateY.apply(this, arguments);
}
var PickerColumn = /*#__PURE__*/forwardRef((props, ref) => {
var {
value,
className,
readonly,
children: childrenProp = [],
onChange,
onTouchStart: _onTouchStart,
onTouchMove: _onTouchMove,
onTouchEnd: _onTouchEnd,
onTouchCancel: _onTouchCancel
} = props,
restProps = _objectWithoutProperties(props, _excluded);
var childrenRef = useToRef(childrenProp);
var wrapperRef = useRef();
var movingRef = useRef();
var startOffsetRef = useRef(0);
var momentumOffsetRef = useRef(0);
var touchStartTimeRef = useRef(0);
var transitionEndTriggerRef = useRef();
var touch = useTouch();
var itemHeight = 44;
var activeIndexRef = useRef(-1);
var [activeOffset, setActiveOffset] = useState(0);
var activeOffsetRef = useToRef(activeOffset);
var [duration, setDuration] = useState("zero");
var baseOffset = useMemo(() => itemHeight * (6 - 1) / 2, []);
var countRef = useRenderedRef(() => _size(childrenProp));
var adjustIndex = useCallback(index => {
index = _clamp(index, 0, countRef.current);
for (var i = index; i < countRef.current; i++) {
if (!childrenRef.current[i].disabled) return i;
}
for (var _i = index - 1; _i >= 0; _i--) {
if (!childrenRef.current[_i].disabled) return _i;
}
return index;
}, [countRef, childrenRef]);
var setIndex = useCallback((index, emitChange) => {
index = adjustIndex(index) || 0;
var offset = -index * itemHeight;
var trigger = () => {
if (index !== activeIndexRef.current) {
activeIndexRef.current = index;
var option = childrenRef.current[index];
onChange === null || onChange === void 0 ? void 0 : onChange(option, emitChange);
}
};
if (movingRef.current && offset !== activeOffsetRef.current) {
transitionEndTriggerRef.current = trigger;
} else {
trigger();
}
setActiveOffset(offset);
}, [adjustIndex, activeOffsetRef, childrenRef, onChange]);
var getIndexByValue = useCallback(aValue => {
var index = _findIndex(childrenRef.current, _ref => {
var {
value: iValue
} = _ref;
return iValue === aValue;
});
return index === -1 ? 0 : index;
}, [childrenRef]);
var childrenChanged = useRendered(() => JSON.stringify(_map(childrenProp, _ref2 => {
var {
value
} = _ref2;
return value;
})));
useEffect(() => {
var valueIndex = getIndexByValue(value);
if (valueIndex !== activeIndexRef.current) {
setIndex(valueIndex);
}
}, [value, childrenChanged]);
var getIndexByOffset = useCallback(offset => _clamp(Math.round(-offset / itemHeight), 0, countRef.current - 1), [countRef]);
var momentum = useCallback((distance, duration) => {
var speed = Math.abs(distance / duration);
distance = activeOffset + speed / 0.003 * (distance < 0 ? -1 : 1);
var index = getIndexByOffset(distance);
setDuration("momentum");
setIndex(index, true);
}, [activeOffset, getIndexByOffset, setIndex]);
var stopMomentum = useCallback(() => {
movingRef.current = false;
setDuration("zero");
if (transitionEndTriggerRef.current) {
var _transitionEndTrigger;
(_transitionEndTrigger = transitionEndTriggerRef.current) === null || _transitionEndTrigger === void 0 ? void 0 : _transitionEndTrigger.call(transitionEndTriggerRef);
transitionEndTriggerRef.current = undefined;
}
}, []);
var onItemClick = useCallback(index => {
if (movingRef.current || readonly) {
return;
}
transitionEndTriggerRef.current = undefined;
setDuration("switch");
setIndex(index, true);
}, [readonly, setIndex]);
var handleTouchStart = /*#__PURE__*/function () {
var _ref3 = _asyncToGenerator(function* (event) {
if (readonly) {
return;
}
touch.start(event);
if (movingRef.current) {
var translateY = yield getElementTranslateY(wrapperRef.current);
var offset = Math.min(0, translateY - baseOffset);
setActiveOffset(offset);
startOffsetRef.current = offset;
} else {
startOffsetRef.current = activeOffset;
}
touchStartTimeRef.current = Date.now();
momentumOffsetRef.current = startOffsetRef.current;
setDuration("zero");
});
return function handleTouchStart(_x2) {
return _ref3.apply(this, arguments);
};
}();
var handleTouchMove = event => {
if (readonly) {
return;
}
touch.move(event);
if (touch.isVertical()) {
movingRef.current = true;
preventDefault(event, true);
}
var now = Date.now();
if (now - touchStartTimeRef.current > MOMENTUM_LIMIT_TIME) {
touchStartTimeRef.current = now;
momentumOffsetRef.current = activeOffset;
}
setActiveOffset(_clamp(startOffsetRef.current + touch.deltaY, -(countRef.current * itemHeight), itemHeight));
};
var handleTouchEnd = () => {
if (readonly) {
return;
}
var distance = activeOffset - momentumOffsetRef.current;
var duration = Date.now() - touchStartTimeRef.current;
var allowMomentum = duration < MOMENTUM_LIMIT_TIME && Math.abs(distance) > MOMENTUM_LIMIT_DISTANCE;
if (allowMomentum) {
momentum(distance, duration);
return;
}
var index = getIndexByOffset(activeOffset);
setDuration("switch");
setIndex(index, true);
setTimeout(() => {
movingRef.current = false;
}, 0);
};
var wrapperStyle = useMemo(() => ({
transform: "translate3d(0, ".concat(addUnitPx(activeOffset + baseOffset), ", 0)")
}), [activeOffset, baseOffset]);
useImperativeHandle(ref, () => ({
stopMomentum
}), [stopMomentum]);
return /*#__PURE__*/React.createElement(View, _objectSpread({
className: classNames(prefixClassname("picker-column"), className),
catchMove: true,
onTouchStart: event => {
fulfillPromise(handleTouchStart(event));
_onTouchStart === null || _onTouchStart === void 0 ? void 0 : _onTouchStart(event);
},
onTouchMove: event => {
handleTouchMove(event);
_onTouchMove === null || _onTouchMove === void 0 ? void 0 : _onTouchMove(event);
},
onTouchEnd: event => {
handleTouchEnd();
_onTouchEnd === null || _onTouchEnd === void 0 ? void 0 : _onTouchEnd(event);
},
onTouchCancel: event => {
handleTouchEnd();
_onTouchCancel === null || _onTouchCancel === void 0 ? void 0 : _onTouchCancel(event);
}
}, _omit(restProps, "label")), /*#__PURE__*/React.createElement(View, {
ref: wrapperRef,
style: wrapperStyle,
className: classNames(prefixClassname("picker-column__wrapper"), {
[prefixClassname("picker-column__wrapper--zero")]: duration === "zero",
[prefixClassname("picker-column__wrapper--momentum")]: duration === "momentum",
[prefixClassname("picker-column__wrapper--switch")]: duration === "switch"
}),
onTransitionEnd: stopMomentum
}, _map(childrenProp, (option, index) => {
var _getPickerOptionKey;
return /*#__PURE__*/React.createElement(PickerOption, _objectSpread(_objectSpread({
key: (_getPickerOptionKey = getPickerOptionKey(option)) !== null && _getPickerOptionKey !== void 0 ? _getPickerOptionKey : index
}, option), {}, {
onClick: () => onItemClick(index)
}));
})));
});
export default PickerColumn;
//# sourceMappingURL=picker-column.js.map