- Deleted the outdated `PageGroupNav` component and its related documentation. - Introduced a new document for the direct input navigation feature in pagination, detailing the rationale for the change and the new user experience. - Updated the checklist to reflect the completion of the new pagination input feature and its implementation steps. These changes enhance the clarity and usability of the pagination system in the project.
129 lines
5.6 KiB
Markdown
129 lines
5.6 KiB
Markdown
# [계획서] 페이징 - 페이지 번호 직접 입력 네비게이션
|
|
|
|
> 관련 문서: [맥락노트](./PGN[맥락]-페이징-직접입력.md) | [체크리스트](./PGN[체크]-페이징-직접입력.md)
|
|
|
|
## 개요
|
|
|
|
v2-table-list 컴포넌트의 하단 페이지네이션 중앙 영역에서, 현재 페이지 번호를 **읽기 전용 텍스트**에서 **입력 가능한 필드**로 변경합니다.
|
|
사용자가 원하는 페이지 번호를 키보드로 직접 입력하여 빠르게 이동할 수 있게 합니다.
|
|
|
|
### 이전 설계(10개 번호 버튼 그룹) 폐기 사유
|
|
|
|
- 10개 버튼은 공간을 많이 차지하고, 모바일에서 렌더링이 어려움
|
|
- 고정 슬롯/고정 너비 등 복잡한 레이아웃 제약이 발생
|
|
- 입력 필드 방식이 더 직관적이고 공간 효율적
|
|
|
|
---
|
|
|
|
## 변경 전 → 변경 후
|
|
|
|
### 페이지네이션 UI
|
|
|
|
```
|
|
변경 전: [<<] [<] 1 / 38 [>] [>>] ← 읽기 전용 텍스트
|
|
변경 후: [<<] [<] [ 15 ] / 49 [>] [>>] ← 입력 가능 필드
|
|
```
|
|
|
|
| 버튼 | 동작 (변경 없음) |
|
|
|------|-----------------|
|
|
| `<<` | 첫 페이지(1)로 이동 |
|
|
| `<` | 이전 페이지(`currentPage - 1`)로 이동 |
|
|
| 중앙 | **입력 필드** `/` **총 페이지** — 사용자가 원하는 페이지 번호를 직접 입력 |
|
|
| `>` | 다음 페이지(`currentPage + 1`)로 이동 |
|
|
| `>>` | 마지막 페이지(`totalPages`)로 이동 |
|
|
|
|
### 입력 필드 동작 규칙
|
|
|
|
| 동작 | 설명 |
|
|
|------|------|
|
|
| 클릭 | 입력 필드에 포커스, 기존 숫자 전체 선택(select all) |
|
|
| 숫자 입력 | 자유롭게 타이핑 가능 (입력 중에는 페이지 이동 안 함) |
|
|
| Enter | 입력한 페이지로 이동 + 포커스 해제 |
|
|
| 포커스 아웃 (blur) | 입력한 페이지로 이동 |
|
|
| 유효 범위 보정 | 1 미만 → 1, totalPages 초과 → totalPages, 빈 값/비숫자 → 현재 페이지 유지 |
|
|
| `< >` 클릭 | 기존대로 한 페이지씩 이동 (입력 필드 값도 갱신) |
|
|
| `<< >>` 클릭 | 기존대로 첫/끝 페이지 이동 (입력 필드 값도 갱신) |
|
|
|
|
### 비활성화 조건 (기존과 동일)
|
|
|
|
- `<<` `<` : `currentPage === 1`
|
|
- `>` `>>` : `currentPage >= totalPages`
|
|
|
|
---
|
|
|
|
## 시각적 동작 예시
|
|
|
|
총 49페이지 기준:
|
|
|
|
| 사용자 동작 | 입력 필드 표시 | 결과 |
|
|
|------------|---------------|------|
|
|
| 초기 상태 | `1 / 49` | 1페이지 표시 |
|
|
| 입력 필드 클릭 | `[1]` 전체 선택됨 | 타이핑 대기 |
|
|
| `28` 입력 후 Enter | `28 / 49` | 28페이지로 이동 |
|
|
| `0` 입력 후 Enter | `1 / 49` | 1로 보정 |
|
|
| `999` 입력 후 Enter | `49 / 49` | 49로 보정 |
|
|
| 빈 값으로 blur | `28 / 49` | 이전 페이지(28) 유지 |
|
|
| `abc` 입력 후 Enter | `28 / 49` | 이전 페이지(28) 유지 |
|
|
| `>` 클릭 | `29 / 49` | 29페이지로 이동 |
|
|
|
|
---
|
|
|
|
## 아키텍처
|
|
|
|
### 데이터 흐름
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A["currentPage (state, 단일 소스)"] --> B["입력 필드 표시값 (pageInputValue)"]
|
|
B -->|"사용자 타이핑"| C["pageInputValue 갱신 (표시만)"]
|
|
C -->|"Enter 또는 blur"| D["유효 범위 보정 (1~totalPages)"]
|
|
D -->|"보정된 값"| E[handlePageChange]
|
|
E --> F["setCurrentPage → useEffect → fetchTableDataDebounced"]
|
|
F --> G[백엔드 API 호출]
|
|
G --> H[데이터 갱신]
|
|
H --> A
|
|
|
|
I["<< < > >> 클릭"] --> E
|
|
J["페이지크기 변경"] --> K["setCurrentPage(1) + setLocalPageSize + onConfigChange"]
|
|
K --> F
|
|
```
|
|
|
|
### 페이징 바 레이아웃
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────┐
|
|
│ [페이지크기 입력] │ << < [__입력__] / n > >> │ [내보내기][새로고침] │
|
|
│ 좌측(유지) │ 중앙(입력필드 교체) │ 우측(유지) │
|
|
└──────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 변경 대상 파일
|
|
|
|
| 구분 | 파일 | 변경 내용 |
|
|
|------|------|----------|
|
|
| 수정 | `TableListComponent.tsx` | (1) `pageInputValue` 상태 + `useEffect` 동기화 + `commitPageInput` 핸들러 추가 |
|
|
| | | (2) paginationJSX 중앙 `<span>` → `<input>` + `/` + `<span>` 교체 |
|
|
| | | (3) `handlePageSizeChange`에 `onConfigChange` 호출 추가 |
|
|
| | | (4) `fetchTableDataInternal`에서 `currentPage`를 단일 소스로 사용 |
|
|
| | | (5) `useMemo` 의존성에 `pageInputValue` 추가 |
|
|
| 삭제 | `PageGroupNav.tsx` | 이전 설계 산출물 삭제 (이미 삭제됨) |
|
|
|
|
- 신규 파일 생성 없음
|
|
- 백엔드 변경 없음, DB 변경 없음
|
|
- v2-table-list를 사용하는 **모든 동적 화면**에 자동 적용
|
|
|
|
---
|
|
|
|
## 설계 원칙
|
|
|
|
- **최소 변경**: `<span>` 1개를 `<input>` + 유효성 검증으로 교체. 나머지 전부 유지
|
|
- **기존 버튼 동작 무변경**: `<< < > >>` 4개 버튼의 onClick/disabled 로직은 그대로
|
|
- **`handlePageChange` 재사용**: 기존 함수를 그대로 호출
|
|
- **입력 중 페이지 이동 안 함**: onChange는 표시만 변경, Enter/blur로 실제 적용
|
|
- **유효 범위 자동 보정**: 1 미만 → 1, totalPages 초과 → totalPages, 비숫자 → 현재 값 유지
|
|
- **포커스 시 전체 선택**: 클릭하면 바로 타이핑 가능
|
|
- **`currentPage`가 단일 소스**: fetch 시 `tableConfig.pagination?.currentPage` 대신 로컬 `currentPage`만 사용 (비동기 전파 문제 방지)
|
|
- **페이지크기 변경 시 1페이지로 리셋**: `handlePageSizeChange`가 `onConfigChange`를 호출하여 부모/백엔드 동기화
|