UNPKG

@fruits-chain/react-native-xiaoshu

Version:
178 lines (166 loc) 7.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _isNil = _interopRequireDefault(require("lodash/isNil")); var _isUndefined = _interopRequireDefault(require("lodash/isUndefined")); var _noop = _interopRequireDefault(require("lodash/noop")); var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _index = require("../helpers/index.js"); var _index2 = require("../hooks/index.js"); var _index3 = _interopRequireDefault(require("../text-input/index.js")); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const parserNumberToString = n => `${!(0, _isNil.default)(n) ? n : ''}`; const defaultFormatter = t => t; const defaultParser = t => Number(t); /** * 数字输入框 * @description 输入中过滤所有非数字类字符,输入结束结合外界的 parser 修正数据 */ const NumberInput = /*#__PURE__*/(0, _react.forwardRef)(({ type = 'number', min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER, formatter, parser, limitDecimals = -1, validateTrigger = 'onEndEditing', value, defaultValue, onEndEditing, onChange, ...restProps }, ref) => { if ((0, _isNil.default)(restProps.keyboardType)) { if (_reactNative.Platform.OS === 'ios') { restProps.keyboardType = 'numbers-and-punctuation'; } if (_reactNative.Platform.OS === 'android') { restProps.keyboardType = 'decimal-pad'; } } if (type === 'digit') { // restProps.keyboardType = 'number-pad' limitDecimals = -1; } const onEndEditingPersistFn = (0, _index2.usePersistFn)(onEndEditing || _noop.default); const onChangePersistFn = (0, _index2.usePersistFn)(onChange || _noop.default); const parserPersistFn = (0, _index2.usePersistFn)(parser || defaultParser); const formatterPersistFn = (0, _index2.usePersistFn)(formatter || defaultFormatter); const [localValue, setLocalValue] = (0, _react.useState)(formatterPersistFn(parserNumberToString(!(0, _isUndefined.default)(value) ? value : defaultValue))); /** 记录外部的数值 */ const LastValue = (0, _react.useRef)(!(0, _isUndefined.default)(value) ? value : defaultValue); // 同步数据 (0, _index2.useUpdateEffect)(() => { // 输入 10.00001 删除最后一位,输入框期望保持 10.0000 字样 if (value !== LastValue.current) { // 记录上次/当前外部的数字 LastValue.current = value; // 更新内部的值 setLocalValue(formatterPersistFn(parserNumberToString(value))); } }, [value]); /** 数据过滤,限制小数位,返回数字的字符串 */ const parserInputValue = (0, _index2.usePersistFn)(t => (0, _index.formatDecimal)(t, limitDecimals)); /** 计算数据 */ const computeValueStringify = (0, _react.useCallback)((t, validate, isEnd) => { // 部分数据开始格式化 // 允许输入正整数 const isNumber = type === 'number'; t = (0, _index.formatNumber)(t, isNumber, true); // 解析数据 let newValueStringify = parserInputValue(t); if (newValueStringify !== '') { if (validate) { const newValueNum = Number(newValueStringify); // 输入结束做最大、最小限制 if (newValueNum > max) { newValueStringify = String(max); } if (newValueNum < min) { newValueStringify = String(min); } } // 结束的时候限制最大最小值 if (isEnd) { if (t === '-') { newValueStringify = null; } } } return newValueStringify; }, [max, min, parserInputValue, type]); const triggerValueUpdate = (0, _react.useCallback)((t, validate, isEnd) => { // 输入 . 默认转换成 0. if (t === '.') { t = '0.'; } // 当 min >= 0 就不能输入 - if (min >= 0) { t = t.replace(/-/g, ''); } let newValueStringify = computeValueStringify(t || '', validate, isEnd); let finallyValue = newValueStringify; // 同步更新到组件状态 // 第一个字符串非数字,newValueStringify 是 null,setLocalValue(null) 不能触发更新,导致限制其他字符输入失败 setLocalValue(formatterPersistFn(newValueStringify) || ''); // 1. 空字符串 + 非 null // 2. 空字符串 + null // 3. 非空字符串 + null // 4. 非空字符串 + 非 null if (newValueStringify === '' && LastValue.current !== null) { // 状态 1 触发 onChange onChangePersistFn(null); finallyValue = null; LastValue.current = null; } else if (newValueStringify) { // 状态 3 和 状态 4 if (isEnd) { // 按照提供的解析函数转成数字 const returnValue = parserPersistFn(newValueStringify); finallyValue = parserNumberToString(returnValue); // 新数字转成字符串 setLocalValue(formatterPersistFn(finallyValue)); if (returnValue !== LastValue.current) { // 当最终值和上次值不同时触发 onChange onChangePersistFn(returnValue); LastValue.current = returnValue; } } else { // 聚焦输入中 // 字符串有数字 // 格式化后的值和最新值不相同 // '1.' 和 1 在 Number 后是一致的 // '1.0' 和 1 在 Number 后是一致的 const newValueNum = Number(newValueStringify); if (newValueStringify && newValueStringify !== '-' && newValueNum !== LastValue.current) { onChangePersistFn(newValueNum); LastValue.current = newValueNum; } } } return finallyValue; }, [computeValueStringify, formatterPersistFn, min, onChangePersistFn, parserPersistFn]); const onChangeTextTextInput = (0, _react.useCallback)(t => { triggerValueUpdate(t, validateTrigger === 'onChangeText', false); }, [triggerValueUpdate, validateTrigger]); const onEndEditingTextInput = (0, _react.useCallback)(e => { e.nativeEvent.text = triggerValueUpdate(e.nativeEvent.text, validateTrigger === 'onEndEditing', true) || ''; onEndEditingPersistFn(e); }, [onEndEditingPersistFn, triggerValueUpdate, validateTrigger]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.default, { ...restProps, ref: ref, type: "text", value: localValue, onChangeText: onChangeTextTextInput, onEndEditing: onEndEditingTextInput }); }); var _default = exports.default = /*#__PURE__*/(0, _react.memo)(NumberInput); //# sourceMappingURL=index.js.map