2024-08-20 23:25:37 +04:00

375 lines
13 KiB
JavaScript

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _classnames = _interopRequireDefault(require("classnames"));
var _rcUtil = require("rc-util");
var _useLayoutEffect = _interopRequireDefault(require("rc-util/lib/hooks/useLayoutEffect"));
var _raf = _interopRequireDefault(require("rc-util/lib/raf"));
var React = _interopRequireWildcard(require("react"));
var _miscUtil = require("../../utils/miscUtil");
var _context = _interopRequireDefault(require("../context"));
var _useLockEffect = _interopRequireDefault(require("../hooks/useLockEffect"));
var _Icon = _interopRequireDefault(require("./Icon"));
var _MaskFormat = _interopRequireDefault(require("./MaskFormat"));
var _util = require("./util");
var _excluded = ["active", "showActiveCls", "suffixIcon", "format", "validateFormat", "onChange", "onInput", "helped", "onHelp", "onSubmit", "onKeyDown", "preserveInvalidOnBlur", "invalid", "clearIcon"];
// Format logic
//
// First time on focus:
// 1. check if the text is valid, if not fill with format
// 2. set highlight cell to the first cell
// Cells
// 1. Selection the index cell, set inner `cacheValue` to ''
// 2. Key input filter non-number char, patch after the `cacheValue`
// 1. Replace the `cacheValue` with input align the cell length
// 2. Re-selection the mask cell
// 3. If `cacheValue` match the limit length or cell format (like 1 ~ 12 month), go to next cell
var Input = /*#__PURE__*/React.forwardRef(function (props, ref) {
var active = props.active,
_props$showActiveCls = props.showActiveCls,
showActiveCls = _props$showActiveCls === void 0 ? true : _props$showActiveCls,
suffixIcon = props.suffixIcon,
format = props.format,
validateFormat = props.validateFormat,
onChange = props.onChange,
onInput = props.onInput,
helped = props.helped,
onHelp = props.onHelp,
onSubmit = props.onSubmit,
onKeyDown = props.onKeyDown,
_props$preserveInvali = props.preserveInvalidOnBlur,
preserveInvalidOnBlur = _props$preserveInvali === void 0 ? false : _props$preserveInvali,
invalid = props.invalid,
clearIcon = props.clearIcon,
restProps = (0, _objectWithoutProperties2.default)(props, _excluded);
var value = props.value,
onFocus = props.onFocus,
onBlur = props.onBlur,
onMouseUp = props.onMouseUp;
var _React$useContext = React.useContext(_context.default),
prefixCls = _React$useContext.prefixCls,
_React$useContext$inp = _React$useContext.input,
Component = _React$useContext$inp === void 0 ? 'input' : _React$useContext$inp;
var inputPrefixCls = "".concat(prefixCls, "-input");
// ======================== Value =========================
var _React$useState = React.useState(false),
_React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
focused = _React$useState2[0],
setFocused = _React$useState2[1];
var _React$useState3 = React.useState(value),
_React$useState4 = (0, _slicedToArray2.default)(_React$useState3, 2),
internalInputValue = _React$useState4[0],
setInputValue = _React$useState4[1];
var _React$useState5 = React.useState(''),
_React$useState6 = (0, _slicedToArray2.default)(_React$useState5, 2),
focusCellText = _React$useState6[0],
setFocusCellText = _React$useState6[1];
var _React$useState7 = React.useState(null),
_React$useState8 = (0, _slicedToArray2.default)(_React$useState7, 2),
focusCellIndex = _React$useState8[0],
setFocusCellIndex = _React$useState8[1];
var _React$useState9 = React.useState(null),
_React$useState10 = (0, _slicedToArray2.default)(_React$useState9, 2),
forceSelectionSyncMark = _React$useState10[0],
forceSelectionSync = _React$useState10[1];
var inputValue = internalInputValue || '';
// Sync value if needed
React.useEffect(function () {
setInputValue(value);
}, [value]);
// ========================= Refs =========================
var holderRef = React.useRef();
var inputRef = React.useRef();
React.useImperativeHandle(ref, function () {
return {
nativeElement: holderRef.current,
inputElement: inputRef.current,
focus: function focus(options) {
inputRef.current.focus(options);
},
blur: function blur() {
inputRef.current.blur();
}
};
});
// ======================== Format ========================
var maskFormat = React.useMemo(function () {
return new _MaskFormat.default(format || '');
}, [format]);
var _React$useMemo = React.useMemo(function () {
if (helped) {
return [0, 0];
}
return maskFormat.getSelection(focusCellIndex);
}, [maskFormat, focusCellIndex, helped]),
_React$useMemo2 = (0, _slicedToArray2.default)(_React$useMemo, 2),
selectionStart = _React$useMemo2[0],
selectionEnd = _React$useMemo2[1];
// ======================== Modify ========================
// When input modify content, trigger `onHelp` if is not the format
var onModify = function onModify(text) {
if (text && text !== format && text !== value) {
onHelp();
}
};
// ======================== Change ========================
/**
* Triggered by paste, keyDown and focus to show format
*/
var triggerInputChange = (0, _rcUtil.useEvent)(function (text) {
if (validateFormat(text)) {
onChange(text);
}
setInputValue(text);
onModify(text);
});
// Directly trigger `onChange` if `format` is empty
var onInternalChange = function onInternalChange(event) {
// Hack `onChange` with format to do nothing
if (!format) {
var text = event.target.value;
onModify(text);
setInputValue(text);
onChange(text);
}
};
var onFormatPaste = function onFormatPaste(event) {
// Get paste text
var pasteText = event.clipboardData.getData('text');
if (validateFormat(pasteText)) {
triggerInputChange(pasteText);
}
};
// ======================== Mouse =========================
// When `mouseDown` get focus, it's better to not to change the selection
// Since the up position maybe not is the first cell
var mouseDownRef = React.useRef(false);
var onFormatMouseDown = function onFormatMouseDown() {
mouseDownRef.current = true;
};
var onFormatMouseUp = function onFormatMouseUp(event) {
var _ref = event.target,
start = _ref.selectionStart;
var closeMaskIndex = maskFormat.getMaskCellIndex(start);
setFocusCellIndex(closeMaskIndex);
// Force update the selection
forceSelectionSync({});
onMouseUp === null || onMouseUp === void 0 || onMouseUp(event);
mouseDownRef.current = false;
};
// ====================== Focus Blur ======================
var onFormatFocus = function onFormatFocus(event) {
setFocused(true);
setFocusCellIndex(0);
setFocusCellText('');
onFocus(event);
};
var onSharedBlur = function onSharedBlur(event) {
onBlur(event);
};
var onFormatBlur = function onFormatBlur(event) {
setFocused(false);
onSharedBlur(event);
};
// ======================== Active ========================
// Check if blur need reset input value
(0, _useLockEffect.default)(active, function () {
if (!active && !preserveInvalidOnBlur) {
setInputValue(value);
}
});
// ======================= Keyboard =======================
var onSharedKeyDown = function onSharedKeyDown(event) {
if (event.key === 'Enter' && validateFormat(inputValue)) {
onSubmit();
}
onKeyDown === null || onKeyDown === void 0 || onKeyDown(event);
};
var onFormatKeyDown = function onFormatKeyDown(event) {
onSharedKeyDown(event);
var key = event.key;
// Save the cache with cell text
var nextCellText = null;
// Fill in the input
var nextFillText = null;
var maskCellLen = selectionEnd - selectionStart;
var cellFormat = format.slice(selectionStart, selectionEnd);
// Cell Index
var offsetCellIndex = function offsetCellIndex(offset) {
setFocusCellIndex(function (idx) {
var nextIndex = idx + offset;
nextIndex = Math.max(nextIndex, 0);
nextIndex = Math.min(nextIndex, maskFormat.size() - 1);
return nextIndex;
});
};
// Range
var offsetCellValue = function offsetCellValue(offset) {
var _getMaskRange = (0, _util.getMaskRange)(cellFormat),
_getMaskRange2 = (0, _slicedToArray2.default)(_getMaskRange, 3),
rangeStart = _getMaskRange2[0],
rangeEnd = _getMaskRange2[1],
rangeDefault = _getMaskRange2[2];
var currentText = inputValue.slice(selectionStart, selectionEnd);
var currentTextNum = Number(currentText);
if (isNaN(currentTextNum)) {
return String(rangeDefault ? rangeDefault : offset > 0 ? rangeStart : rangeEnd);
}
var num = currentTextNum + offset;
var range = rangeEnd - rangeStart + 1;
return String(rangeStart + (range + num - rangeStart) % range);
};
switch (key) {
// =============== Remove ===============
case 'Backspace':
case 'Delete':
nextCellText = '';
nextFillText = cellFormat;
break;
// =============== Arrows ===============
// Left key
case 'ArrowLeft':
nextCellText = '';
offsetCellIndex(-1);
break;
// Right key
case 'ArrowRight':
nextCellText = '';
offsetCellIndex(1);
break;
// Up key
case 'ArrowUp':
nextCellText = '';
nextFillText = offsetCellValue(1);
break;
// Down key
case 'ArrowDown':
nextCellText = '';
nextFillText = offsetCellValue(-1);
break;
// =============== Number ===============
default:
if (!isNaN(Number(key))) {
nextCellText = focusCellText + key;
nextFillText = nextCellText;
}
break;
}
// Update cell text
if (nextCellText !== null) {
setFocusCellText(nextCellText);
if (nextCellText.length >= maskCellLen) {
// Go to next cell
offsetCellIndex(1);
setFocusCellText('');
}
}
// Update the input text
if (nextFillText !== null) {
// Replace selection range with `nextCellText`
var nextFocusValue =
// before
inputValue.slice(0, selectionStart) +
// replace
(0, _miscUtil.leftPad)(nextFillText, maskCellLen) +
// after
inputValue.slice(selectionEnd);
triggerInputChange(nextFocusValue.slice(0, format.length));
}
// Always trigger selection sync after key down
forceSelectionSync({});
};
// ======================== Format ========================
var rafRef = React.useRef();
(0, _useLayoutEffect.default)(function () {
if (!focused || !format || mouseDownRef.current) {
return;
}
// Reset with format if not match
if (!maskFormat.match(inputValue)) {
triggerInputChange(format);
return;
}
// Match the selection range
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
// Chrome has the bug anchor position looks not correct but actually correct
rafRef.current = (0, _raf.default)(function () {
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
});
return function () {
_raf.default.cancel(rafRef.current);
};
}, [maskFormat, format, focused, inputValue, focusCellIndex, selectionStart, selectionEnd, forceSelectionSyncMark, triggerInputChange]);
// ======================== Render ========================
// Input props for format
var inputProps = format ? {
onFocus: onFormatFocus,
onBlur: onFormatBlur,
onKeyDown: onFormatKeyDown,
onMouseDown: onFormatMouseDown,
onMouseUp: onFormatMouseUp,
onPaste: onFormatPaste
} : {};
return /*#__PURE__*/React.createElement("div", {
ref: holderRef,
className: (0, _classnames.default)(inputPrefixCls, (0, _defineProperty2.default)((0, _defineProperty2.default)({}, "".concat(inputPrefixCls, "-active"), active && showActiveCls), "".concat(inputPrefixCls, "-placeholder"), helped))
}, /*#__PURE__*/React.createElement(Component, (0, _extends2.default)({
ref: inputRef,
"aria-invalid": invalid,
autoComplete: "off"
}, restProps, {
onKeyDown: onSharedKeyDown,
onBlur: onSharedBlur
// Replace with format
}, inputProps, {
// Value
value: inputValue,
onChange: onInternalChange
})), /*#__PURE__*/React.createElement(_Icon.default, {
type: "suffix",
icon: suffixIcon
}), clearIcon);
});
if (process.env.NODE_ENV !== 'production') {
Input.displayName = 'Input';
}
var _default = exports.default = Input;