@cainiaofe/cn-ui-m
Version:
292 lines (291 loc) • 14.1 kB
JavaScript
import { __assign, __awaiter, __generator, __rest } from "tslib";
import React, { forwardRef, useEffect, useRef, useState, } from 'react';
import classNames from 'classnames';
import { isWeb } from '@uni/env';
import { CnButton } from "../cn-button";
import { CnIcon } from "../cn-icon";
import { CnReadOnly } from "../cn-read-only";
import { isUndef, isNil, isNumber } from "../../utils/func";
import { mergeProps } from "../../utils/with-default-props";
import isFunction from 'lodash/isFunction';
import get from 'lodash/get';
import { useDeprecated, useGuid } from './hooks';
import { clamp, getDefaultValue, toNumber } from './utils';
import { getFormattedValue } from './get-formatted-value';
import { convertLocaleToStandard, convertStandardToLocale, useLocalization, } from '@cainiaofe/cn-ui-common';
export function getValueFromEvents(e) {
if (!isUndef(e.value)) {
return e.value;
}
if (get(e, 'target.value')) {
return e.target.value;
}
if (get(e, 'detail.value')) {
return e.target.value;
}
if (get(e, 'originalEvent.detail.value')) {
return e.originalEvent.detail.value;
}
}
/**
* 用于表单中判断无效值
* eg:
* isInvalidValue('') : true
* isInvalidValue(undefined) : true
* isInvalidValue(null) : true
*/
export function isInvalidValue(val) {
return isNil(val) || val === '';
}
var MAX_NUMBER_PICKER_THRESHOLD = 9999999;
var isIOS_H5 = isWeb && window.navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
function getInitInputValue(props) {
var initialValue;
if ('value' in props) {
initialValue = props.value;
}
else if (!isUndef(props.defaultValue)) {
initialValue = props.defaultValue;
}
return !isInvalidValue(initialValue) ? toNumber(initialValue) : '';
}
function isDecreaseDisabled(value, min) {
if (!isNumber(value)) {
return false;
}
return min !== -Infinity && value <= min;
}
function isIncreaseDisabled(value, max) {
if (!isNumber(value)) {
return false;
}
return max !== Infinity && value >= max;
}
function getPrecision(precision, step) {
if (typeof precision !== 'number' || precision < 0) {
precision = 0;
}
var stepString = step.toString();
var pcs = 0;
if (stepString.indexOf('.') >= 0) {
pcs = stepString.length - stepString.indexOf('.') - 1;
}
return Math.max(pcs, precision);
}
function getPrecisionFactor(precision) {
return Math.pow(10, precision);
}
function hackChrome(value, precision) {
if (precision >= 0) {
return Number(Number(value).toFixed(precision));
}
return value;
}
var defaultProps = {
size: 'medium',
readOnly: false,
disabled: false,
precisionProp: 0,
label: '',
innerAfter: '',
controlled: false,
};
var NumberPicker = function (props, ref) {
var _a, _b, _c, _d, _e;
var _f = mergeProps(defaultProps, props), className = _f.className, _g = _f.prefix, prefix = _g === void 0 ? 'cn-ui-m-' : _g, value = _f.value, defaultValue = _f.defaultValue, _h = _f.max, max = _h === void 0 ? MAX_NUMBER_PICKER_THRESHOLD : _h, _j = _f.min, min = _j === void 0 ? -MAX_NUMBER_PICKER_THRESHOLD : _j, _k = _f.step, step = _k === void 0 ? 1 : _k, _k1 = _f.keybordType, _k2 = _f.keyboardType, precisionProp = _f.precision, hideButton = _f.hideButton, readOnly = _f.readOnly, size = _f.size, disabled = _f.disabled, label = _f.label, innerAfter = _f.innerAfter, _l = _f.inputStyle, inputStyle = _l === void 0 ? props.style : _l, _m = _f.onBeforeChange, onBeforeChange = _m === void 0 ? function () { return Promise.resolve(); } : _m, format = _f.format, _o = _f.onChange, onChange = _o === void 0 ? function () { } : _o, _p = _f.style, style = _p === void 0 ? {} : _p, onInput = _f.onInput, _q = _f.onFocus, onFocus = _q === void 0 ? function () { } : _q, _r = _f.onBlur, onBlur = _r === void 0 ? function () { } : _r, _s = _f.onCorrect, onCorrect = _s === void 0 ? function () { } : _s, others = __rest(_f, ["className", "prefix", "value", "defaultValue", "max", "min", "step", "keybordType", "keyboardType", "precision", "hideButton", "readOnly", "size", "disabled", "label", "innerAfter", "inputStyle", "onBeforeChange", "format", "onChange", "style", "onInput", "onFocus", "onBlur", "onCorrect"]);
var clsPrefix = "".concat(prefix, "numberpicker");
var isControlled = 'value' in props;
var precision = getPrecision(precisionProp, step);
var factor = getPrecisionFactor(precision);
var inputRef = useRef(null);
var adapterLocale = useLocalization('numAdapterLocale', props.adapterLocale);
// 输入框焦点
var _t = useState(!!props.focused), focused = _t[0], setFocused = _t[1];
// 输入框值
var _u = useState(getInitInputValue(props)), inputValue = _u[0], setInputValue = _u[1];
var inputId = useGuid('mt-np-input-');
// 按钮状态 disabled
var _v = useState(isDecreaseDisabled(inputValue, min)), decreaseDisabled = _v[0], setDecreaseDisabled = _v[1];
var _w = useState(isIncreaseDisabled(inputValue, max)), increaseDisabled = _w[0], setIncreaseDisabled = _w[1];
var keyboardType = useDeprecated('NumberPicker', props, 'keybordType', 'keyboardType', 'number');
useEffect(function () {
var fn = function () {
if (isControlled) {
if (isInvalidValue(value)) {
setInputValue('');
updateInputVal(getFormattedValue('', format, innerAfter, label, adapterLocale));
}
else {
setInputValue(toNumber(props.value));
updateInputVal(getFormattedValue(props.value, format, innerAfter, label, adapterLocale));
}
}
};
fn();
});
useEffect(function () {
updateInputVal(getFormattedValue(inputValue, format, innerAfter, label, adapterLocale));
}, [adapterLocale]);
// 当输入框的值改变时,修改按钮disabled状态
useEffect(function () {
setDecreaseDisabled(isDecreaseDisabled(inputValue, min));
setIncreaseDisabled(isIncreaseDisabled(inputValue, max));
}, [inputValue, max, min]);
function handleChange(numValue, e) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
// 只读
if (readOnly) {
return [2 /*return*/];
}
// 修改前的回调
return [4 /*yield*/, onBeforeChange(numValue)];
case 1:
// 修改前的回调
_a.sent();
doChange(numValue, e);
return [2 /*return*/];
}
});
});
}
function doChange(val, e) {
if (!isControlled) {
// 修改状态
setInputValue(val);
updateInputVal(getFormattedValue(val, format, innerAfter, label, adapterLocale));
}
onChange(val, e);
}
function handleFocus(e) {
updateInputVal(convertStandardToLocale(inputValue, adapterLocale));
setFocused(true);
if (isFunction(onFocus)) {
onFocus(e);
}
}
function updateInputVal(newVal) {
var cur = inputRef.current;
if (isWeb && cur) {
cur.value = '';
cur.value = newVal;
}
}
function handleBlur(e) {
var val = convertLocaleToStandard(getValueFromEvents(e), adapterLocale);
if (val && isNaN(val)) {
val = inputValue;
}
val = toNumber(val);
if (isFunction(onBlur)) {
onBlur(e);
}
// 如果重置了最小值,则保留用户的最小值
if (isInvalidValue(val)) {
setFocused(false);
if (inputValue === '') {
return;
}
handleChange('', __assign(__assign({}, e), { originalValue: convertLocaleToStandard(getValueFromEvents(e), adapterLocale) }));
return;
}
var limitedValue = clamp(val, min, max);
// notice: auto correct special input condition: `1.`
if (!isControlled) {
updateInputVal(getFormattedValue(limitedValue, format, innerAfter, label, adapterLocale));
}
var result = (factor * limitedValue) / factor;
result = hackChrome(result, precision);
if (val !== result) {
if (!isControlled) {
updateInputVal(getFormattedValue(result, format, innerAfter, label, adapterLocale));
}
onCorrect(result, val);
}
setFocused(false);
handleChange(result, __assign(__assign({}, e), { originalValue: convertLocaleToStandard(getValueFromEvents(e), adapterLocale) }));
}
function handleInput(e) {
if (isFunction(onInput)) {
var val = toNumber(convertLocaleToStandard(getValueFromEvents(e), adapterLocale));
var correctVal = val;
if (isInvalidValue(val)) {
correctVal = getDefaultValue(min, max, MAX_NUMBER_PICKER_THRESHOLD);
return;
}
var newValue = clamp(val, min, max);
var result = (factor * newValue) / factor;
correctVal = hackChrome(result, precision);
onInput(val, correctVal, e);
}
}
function handleDecrease(e) {
if (isInvalidValue(inputValue)) {
handleChange(getDefaultValue(min, max, MAX_NUMBER_PICKER_THRESHOLD, -1), e);
return;
}
var newValue = clamp(inputValue - step, min, max);
var result = (factor * newValue) / factor;
result = hackChrome(result, precision);
if (newValue !== result && isFunction(onCorrect)) {
onCorrect(result, newValue);
}
handleChange(result, e);
}
function handleIncrease(e) {
if (isInvalidValue(inputValue)) {
handleChange(getDefaultValue(min, max, MAX_NUMBER_PICKER_THRESHOLD, 1), e);
return;
}
var newValue = clamp(inputValue + step, min, max);
var result = (factor * newValue) / factor;
result = hackChrome(result, precision);
if (newValue !== result && isFunction(onCorrect)) {
onCorrect(result, newValue);
}
handleChange(result, e);
}
var classNameObj = {
numberPicker: classNames("".concat(clsPrefix), "".concat(clsPrefix, "--").concat(size)),
textInput: classNames("".concat(clsPrefix, "-input"), "".concat(clsPrefix, "-input--").concat(size), (_a = {},
_a["".concat(clsPrefix, "-input--focused")] = focused,
// note: there's rendering exception in safari, use `isIOSH5` to circumvent
_a["".concat(clsPrefix, "-input--disabled")] = !isIOS_H5 && disabled,
_a["".concat(clsPrefix, "-input--readonly")] = readOnly,
_a["".concat(clsPrefix, "-input--no-button")] = hideButton,
_a)),
decrease: classNames("".concat(clsPrefix, "-button"), "".concat(clsPrefix, "-button-decrease"), "".concat(clsPrefix, "-button--").concat(size), (_b = {},
_b["".concat(clsPrefix, "-button--disabled")] = disabled || decreaseDisabled,
_b)),
decreaseIcon: classNames("".concat(clsPrefix, "-button-icon"), "".concat(clsPrefix, "-button-icon--").concat(size), (_c = {},
_c["".concat(clsPrefix, "-button-icon--disabled")] = disabled || decreaseDisabled,
_c)),
increase: classNames("".concat(clsPrefix, "-button"), "".concat(clsPrefix, "-button-increase"), "".concat(clsPrefix, "-button--").concat(size), (_d = {},
_d["".concat(clsPrefix, "-button--disabled")] = disabled || increaseDisabled,
_d)),
increaseIcon: classNames("".concat(clsPrefix, "-button-icon"), "".concat(clsPrefix, "-button-icon--").concat(size), (_e = {},
_e["".concat(clsPrefix, "-button-icon--disabled")] = disabled || increaseDisabled,
_e)),
};
if (readOnly) {
return (React.createElement(CnReadOnly, { value: getFormattedValue(inputValue, format, innerAfter, label, adapterLocale) }));
}
return (React.createElement("div", __assign({ style: style, className: classNames(CN_UI_HASH_CLASS_NAME, classNameObj.numberPicker, className), ref: ref }, others),
!hideButton ? (React.createElement(CnButton, { disabled: disabled || decreaseDisabled, type: "normal", size: size, className: classNameObj.decrease, onClick: handleDecrease, "data-testid": "cn-number-picker-decrease-button" },
React.createElement(CnIcon, { type: "minus", className: classNameObj.decreaseIcon }))) : null,
React.createElement("input", { id: inputId, className: [
classNameObj.textInput,
(style === null || style === void 0 ? void 0 : style.width) ? "".concat(clsPrefix, "-input--no-width") : '',
].join(' '), ref: inputRef, defaultValue: getFormattedValue(inputValue, format, innerAfter, label, adapterLocale), placeholder: props.placeholder, disabled: !!(disabled || readOnly), type: ((label || format || innerAfter) && !focused) || adapterLocale
? 'text'
: keyboardType, onFocus: handleFocus, onBlur: handleBlur, onInput: handleInput, onChange: function (e) {
e.stopPropagation();
}, style: inputStyle, "data-testid": "cn-number-picker-input" }),
!hideButton ? (React.createElement(CnButton, { disabled: disabled || increaseDisabled, type: "normal", size: size, className: classNameObj.increase, onClick: handleIncrease, "data-testid": "cn-number-picker-increase-button" },
React.createElement(CnIcon, { type: "add", className: classNameObj.increaseIcon }))) : null));
};
NumberPicker.displayName = 'CnNumberPicker';
var CnNumberPicker = forwardRef(NumberPicker);
export { CnNumberPicker };