직원이 같은 입력을 반복한다면 클릭 수뿐 아니라 잘못 입력했을 때 어디에 머무는지도 중요하다. Enter를 누를 때마다 무조건 다음 칸으로 보내면 편해 보이지만 틀린 수량을 지나칠 수 있다.

이번에는 실제 주문서를 처리하지 않는 독립 합성 입력 모델을 만들었다. row와 field는 포커스를 보낼 목표이지 실제 브라우저 포커스가 아니다.

입력값과 이동 목표를 함께 보관한다

상태에는 행 목록, 현재 행 번호, 필드, 검색창 열림과 메시지가 있다. 입력은 선택된 필드만 바꾸고 이동은 별도 행동으로 계산한다. 어떤 값이 남았고 어디로 가야 하는지 테스트에서 함께 비교할 수 있다. 직접 DOM을 읽어 다음 목표를 추측하는 대신 작고 명시적인 규칙을 만들었다.

실제 화면의 Tab 순서를 이 함수로 모두 가로채려는 의도는 아니다. 기본 키보드 동작을 보존할지, 반복 입력에 필요한 일부 키만 추가할지 실제 화면에서 검토해야 한다. 이번 모델에는 DOM, 이벤트 바인딩과 스크린리더 동작이 없다. 계산된 목표가 있다는 사실을 접근성 검수 통과로 바꾸어 보고하지 않는다.

검색을 닫아도 입력한 단어를 잃지 않게 했다

품목 필드에서 search를 실행하면 popup만 열린다. escape는 popup을 닫으며 입력값을 지우지 않는다. choose는 유효한 합성 품목을 고른 뒤 수량 필드를 목표로 삼는다. 검색이 열려 있을 때 Enter는 임의 선택을 확정하지 않고 선택하거나 닫으라는 메시지를 돌려준다.

실제 검색창에는 결과 선택, 방향키 이동과 현재 선택 안내가 필요하다. 이번 함수는 검색 결과를 가져오거나 여러 항목을 탐색하지 않는다. choose에 전달되는 값도 운영 품목 코드가 아니라 합성 문자열이다. 닫기와 선택의 차이를 작은 코드로 확인하고 실제 검색 위젯의 추가 책임을 드러내는 데 집중했다.

잘못된 수량은 같은 위치에서 고친다

수량은 ASCII 숫자 문자열의 1부터 99까지로 제한한다. 0이나 빈 문자열은 Enter와 행 추가를 통과하지 못한다. 오류가 있으면 현재 행과 필드를 그대로 두고 메시지를 바꾼다. 새 빈 행으로 넘어가서 방금 입력을 잃어버린 것처럼 느끼지 않게 하는 판단이다.

이 규칙을 모든 업무의 수량 정책으로 쓰지는 않는다. 실제 ERP는 소수 단위, 반품과 취소 등 다른 계약이 필요할 수 있다. 이번 공유 예제는 그 값을 추정하지 않고 정수 합성 입력으로 한정했다. 문구도 invalid_quantity 같은 상태 키이며 실제 사용자 언어와 오류 연결 표시는 화면에서 따로 구현해야 한다.

행 추가는 현재 행이 완성됐을 때만

품목과 수량이 유효하면 add가 새 행을 만들고 그 품목 필드를 목표로 한다. 이전 행은 보존한다. 현재 행이 미완성이거나 20행 한도에 닿으면 새 행을 만들지 않는다. 합성 실험의 크기 한도를 운영 제품의 최대 주문 수로 설명하지 않고 코드가 다루는 범위로만 적었다.

입력 모델은 저장과 전송을 수행하지 않는다. 마지막 수량에서 Enter를 눌러 row_complete가 나와도 주문이 서버에 등록됐다는 뜻이 아니다. 사용자가 확인한 입력의 완료와 서버 저장 확인을 연결할 때는 별도 상태가 필요하다. 앞서 만든 저장 응답 모델과도 이 구분을 유지한 채 적용해야 한다.

모델 검증 다음에 실제 화면 검증을 둔다

테스트는 오류에서 이동하지 않음, 검색 취소 뒤 단어 보존, 품목 선택 뒤 수량 이동, 유효한 행 추가와 이전 객체 불변을 확인했다. 합성 실행 기록에는 두 번째 행을 목표로 하면서 첫 수량이 남는 모습을 담았다. 실제 키보드를 누르거나 모바일 화면을 검수했다는 증거는 아니다.

실제 적용에서는 이벤트 중복 등록, 한글 조합 중 Enter, 검색창의 포커스 복귀, 오류 안내와 Tab 이동을 추가로 확인해야 한다. 그 부분을 시험하지 않았다면 미확인으로 남겨야 한다. 나는 빠르게 입력할 수 있다는 약속을 입력 보존·검증·이동 목표로 나누고, 각 책임을 실제로 확인할 수 있게 공개했다.