From 848f75bafa9743290d7107980621862aee4af44f Mon Sep 17 00:00:00 2001 From: ysCha Date: Fri, 22 Aug 2025 10:43:16 +0900 Subject: [PATCH] =?UTF-8?q?[1252]=20=EC=9D=BC=EB=B3=B8=EC=9D=98=20?= =?UTF-8?q?=EC=A0=84=EA=B0=81=20=EC=88=AB=EC=9E=90,=20=EB=B0=98=EA=B0=81?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/input-utils.js | 68 ++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/util/input-utils.js b/src/util/input-utils.js index 7578e95e..86c03fe4 100644 --- a/src/util/input-utils.js +++ b/src/util/input-utils.js @@ -25,37 +25,75 @@ export const onlyNumberWithDotInputChange = (e, callback) => { // ============================= // 1) Normalize any string to NFKC and keep only ASCII digits 0-9. // 1) Normalize any string to keep only ASCII digits 0-9 +// IME composition state tracking +let isComposingDigits = false; +let lastDigitsValue = ''; +let isComposingDecimal = false; +let lastDecimalValue = ''; + +/** + * 숫자만 포함된 문자열로 정규화 (0-9) + * - 전각 숫자를 반각으로 변환 + * - 숫자가 아닌 문자 제거 + * - IME 입력 대응 + */ export function normalizeDigits(value) { if (value == null) return ''; + if (isComposingDigits) return value; - // First convert full-width numbers to half-width - const str = String(value).replace(/[0-9]/g, s => + // 전각 숫자를 반각으로 변환 + const normalized = String(value).replace(/[0-9]/g, s => String.fromCharCode(s.charCodeAt(0) - 0xFEE0) ); - // Then remove all non-digit characters - return str.replace(/\D/g, ''); + // IME 조합 중인지 확인 + if (lastDigitsValue && normalized.startsWith(lastDigitsValue) && + normalized.length > lastDigitsValue.length + 1) { + isComposingDigits = true; + setTimeout(() => { isComposingDigits = false; }, 0); + return value; + } + + // 숫자만 남기기 + const result = normalized.replace(/\D/g, ''); + lastDigitsValue = result; + return result; } -// 2) Normalize decimal numbers (allow one dot) +/** + * 소수점이 포함된 숫자 문자열로 정규화 + * - 전각 숫자와 소수점을 반각으로 변환 + * - 소수점은 한 개만 유지 + * - IME 입력 대응 + */ export function normalizeDecimal(value) { if (value == null) return ''; + if (isComposingDecimal) return value; - // Convert full-width numbers and dot to half-width - let str = String(value).replace(/[0-9.]/g, s => + // 전각 숫자와 소수점을 반각으로 변환 + const normalized = String(value).replace(/[0-9.]/g, s => s === '.' ? '.' : String.fromCharCode(s.charCodeAt(0) - 0xFEE0) ); - // Handle multiple dots by keeping only the first one - const parts = str.split('.'); - if (parts.length > 1) { - str = parts[0] + '.' + parts.slice(1).join(''); + // IME 조합 중인지 확인 + if (lastDecimalValue && normalized.startsWith(lastDecimalValue) && + normalized.length > lastDecimalValue.length + 1) { + isComposingDecimal = true; + setTimeout(() => { isComposingDecimal = false; }, 0); + return value; } - // Remove any remaining non-digit and non-dot characters - // and ensure only one dot remains - return str.replace(/[^\d.]/g, '') - .replace(/^(\d*\.\d*).*$/, '$1'); + // 소수점 처리 + const parts = normalized.split('.'); + let result; + if (parts.length > 1) { + result = parts[0].replace(/\D/g, '') + '.' + parts[1].replace(/\D/g, ''); + } else { + result = normalized.replace(/\D/g, ''); + } + + lastDecimalValue = result; + return result; } // 2-1) Limit fractional digits for decimal numbers. Default to 2 digits.