Compare commits

..

No commits in common. "bbbc8cffaa84ea08d5f64f367ed84a19496feb14" and "5e4b22cdffd09396caa889ff9477a1a9c3990c33" have entirely different histories.

View File

@ -23,82 +23,79 @@ export const onlyNumberWithDotInputChange = (e, callback) => {
// ============================= // =============================
// Number normalization utilities // Number normalization utilities
// ============================= // =============================
// 마지막으로 유효했던 값 추적 // 1) Normalize any string to NFKC and keep only ASCII digits 0-9.
let lastValidDigits = ''; // 1) Normalize any string to keep only ASCII digits 0-9
let lastValidDecimal = ''; // IME composition state tracking
let isComposingDigits = false;
let lastDigitsValue = '';
let isComposingDecimal = false;
let lastDecimalValue = '';
/** /**
* 숫자만 포함된 문자열로 정규화 (0-9) * 숫자만 포함된 문자열로 정규화 (0-9)
* - 전각 숫자 -> 반각 * - 전각 숫자반각으로 변환
* - 숫자 제거 * - 숫자아닌 문자 제거
* - 결과가 유효하면 길이/증가폭과 무관하게 허용 * - IME 입력 대응
*/ */
export function normalizeDigits(value) { export function normalizeDigits(value) {
if (value == null || value === '') { if (value == null) return '';
lastValidDigits = ''; if (isComposingDigits) return value;
return '';
}
const converted = String(value).replace(/[-]/g, s => // 전각 숫자를 반각으로 변환
const normalized = String(value).replace(/[-]/g, s =>
String.fromCharCode(s.charCodeAt(0) - 0xFEE0) String.fromCharCode(s.charCodeAt(0) - 0xFEE0)
); );
const normalized = converted.replace(/\D/g, '');
if (normalized === '') { // IME 조합 중인지 확인
lastValidDigits = ''; if (lastDigitsValue && normalized.startsWith(lastDigitsValue) &&
return ''; normalized.length > lastDigitsValue.length + 1) {
isComposingDigits = true;
setTimeout(() => { isComposingDigits = false; }, 0);
return value;
} }
if (/^\d+$/.test(normalized)) { // 숫자만 남기기
lastValidDigits = normalized; const result = normalized.replace(/\D/g, '');
return normalized; lastDigitsValue = result;
} return result;
return lastValidDigits || '';
} }
/** /**
* 소수점이 포함된 숫자 문자열로 정규화 * 소수점이 포함된 숫자 문자열로 정규화
* - 전각 숫자/ -> 반각 * - 전각 숫자소수점을 반각으로 변환
* - 숫자/ 제거 * - 소수점은 개만 유지
* - 점은 번째만 허용 * - IME 입력 대응
*/ */
export function normalizeDecimal(value) { export function normalizeDecimal(value) {
if (value == null || value === '') { if (value == null) return '';
lastValidDecimal = ''; if (isComposingDecimal) return value;
return '';
}
let converted = String(value).replace(/[-]/g, s => // 전각 숫자와 소수점을 반각으로 변환
const normalized = String(value).replace(/[-]/g, s =>
s === '' ? '.' : String.fromCharCode(s.charCodeAt(0) - 0xFEE0) s === '' ? '.' : String.fromCharCode(s.charCodeAt(0) - 0xFEE0)
); );
converted = converted.replace(/[^0-9.]/g, '');
const firstDot = converted.indexOf('.'); // IME 조합 중인지 확인
let normalized; if (lastDecimalValue && normalized.startsWith(lastDecimalValue) &&
normalized.length > lastDecimalValue.length + 1) {
isComposingDecimal = true;
setTimeout(() => { isComposingDecimal = false; }, 0);
return value;
}
if (firstDot !== -1) { // 소수점 처리
const integerPart = converted.slice(0, firstDot).replace(/\D/g, ''); const parts = normalized.split('.');
const fractionPart = converted.slice(firstDot + 1).replace(/\D/g, ''); let result;
normalized = integerPart + '.' + fractionPart; if (parts.length > 1) {
result = parts[0].replace(/\D/g, '') + '.' + parts[1].replace(/\D/g, '');
} else { } else {
normalized = converted.replace(/\D/g, ''); result = normalized.replace(/\D/g, '');
} }
if (normalized === '') { lastDecimalValue = result;
lastValidDecimal = ''; return result;
return '';
} }
if (/^\d+(\.\d*)?$/.test(normalized) || /^\d+$/.test(normalized)) {
lastValidDecimal = normalized;
return normalized;
}
return lastValidDecimal || '';
}
// 2-1) Limit fractional digits for decimal numbers. Default to 2 digits. // 2-1) Limit fractional digits for decimal numbers. Default to 2 digits.
export function normalizeDecimalLimit(value, maxFractionDigits = 2) { export function normalizeDecimalLimit(value, maxFractionDigits = 2) {
const s = normalizeDecimal(value) const s = normalizeDecimal(value)