@fruits-chain/react-native-xiaoshu
Version:
🌈 React Native UI library
178 lines (166 loc) • 7.39 kB
JavaScript
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
;