UNPKG

@cainiaofe/cn-ui-m

Version:
292 lines (291 loc) 14.1 kB
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 };