임동욱 임동욱 08-13
fix: 전화번호는 숫자만 받는다
칸에 들어오는 값에서 숫자가 아닌 글자를 걸러낸 뒤 자릿수를 자른다. 붙여넣기로
하이픈·공백이 섞여 와도 걸리고, 한 칸에 `010-1234`를 붙여도 넘치지 않는다.

밖에서 받은 value도 같은 방식으로 읽는다 — `010-1234-5678`처럼 꾸며진 값을
넣어도 칸이 맞게 갈리고, 내보낼 때는 숫자만 남는다.

Co-Authored-By: Claude Opus 5 
@90169d163db93fe99b57466ee86a26ab34d42ffe
@fox/core/components/fox-phone-number/fox-phone-number.tsx
--- @fox/core/components/fox-phone-number/fox-phone-number.tsx
+++ @fox/core/components/fox-phone-number/fox-phone-number.tsx
@@ -24,7 +24,7 @@
   type?: FoxPhoneNumberType;
   /**
    * 숫자만 담긴 값. 하이픈은 화면에만 있고 값에는 들어가지 않는다 — `"01012345678"`.
-   * 주면 제어 컴포넌트가 된다.
+   * 꾸며진 값을 넣어도 숫자만 남겨 읽는다. 주면 제어 컴포넌트가 된다.
    */
   value?: string;
   defaultValue?: string;
@@ -63,6 +63,11 @@
 const DEFAULT_MAX_LENGTHS: Lengths = [3, 4, 4];
 const SEGMENT_LABELS: Parts = ["전화번호 앞자리", "전화번호 가운데자리", "전화번호 뒷자리"];
 
+/** 숫자가 아닌 글자는 버린다 — 붙여넣기로 들어온 하이픈·공백도 여기서 걸린다. */
+function onlyDigits(text: string): string {
+  return text.replace(/\D/g, "");
+}
+
 /**
  * 숫자만 담긴 값을 화면의 세 칸으로 나눈다.
  *
@@ -71,7 +76,8 @@
  * 둘 다 맞게 갈린다. 남은 글자가 그보다 짧으면 아직 입력 중이라 보고 가운데에 둔다.
  */
 function splitValue(value: string, prefixOptions: string[], maxLengths: Lengths): Parts {
-  const digits = value ?? "";
+  // 밖에서 `010-1234-5678`처럼 꾸며진 값이 와도 받아 준다 — 내보낼 때는 숫자만 남는다.
+  const digits = onlyDigits(value ?? "");
   const matched = prefixOptions
     .filter((option) => option && digits.startsWith(option))
     .sort((a, b) => b.length - a.length)[0];
@@ -151,9 +157,12 @@
     tailRefs.current[index]?.focus();
   };
 
+  // 숫자가 아닌 입력은 아예 들어오지 못한다. 붙여넣기로 하이픈이 섞여 와도 여기서 걸리고,
+  // 그 뒤에 자릿수를 자르므로 `010-1234`를 한 칸에 붙여도 넘치지 않는다.
   const handleSegmentChange = (index: number) => (next: string) => {
-    commit(index, next);
-    if (autoAdvance && index < 2 && next.length >= maxLengths[index]) {
+    const digits = onlyDigits(next).slice(0, maxLengths[index]);
+    commit(index, digits);
+    if (autoAdvance && index < 2 && digits.length >= maxLengths[index]) {
       focusSegment(index + 1);
     }
   };
Add a comment
List