# 입력 위젯 가이드 Superport v2의 폼 UI는 shadcn_ui 구성 요소를 기반으로 하며, 아래 지침을 따를 때 레이아웃과 상호작용이 일관되게 유지된다. ## 1. 기본 컨테이너 — `SuperportFormField` - 라벨/필수 표시/보조 설명/에러 메시지를 하나의 빌딩 블록으로 묶는다. - 라벨은 좌측 정렬, 12pt, 필수 항목은 `*`(파괴색)으로 표시한다. - 자식 위젯은 `ShadInput`, `ShadSelect`, `SuperportDatePickerButton` 등 어떤 입력 요소든 가능하다. - 에러 문구는 상단 Validator에서 내려오는 한글 메시지를 그대로 사용한다. ```dart SuperportFormField( label: '창고', required: true, caption: '입고가 진행될 창고를 선택하세요.', errorText: state.errorMessage, child: ShadSelect( initialValue: controller.selectedWarehouse, options: warehouses.map((w) => ShadOption(value: w.id, child: Text(w.name))).toList(), onChanged: controller.onWarehouseChanged, ), ); ``` ## 2. 텍스트 입력 — `SuperportTextInput` - `ShadInput`에 공통 프리셋을 적용한 래퍼. - 플레이스홀더는 한글 문장형으로 작성하고, 검색 필드라면 돋보기 아이콘을 `leading`으로 배치한다. - 여러 줄 입력은 `maxLines` 변경만으로 처리한다. ```dart SuperportFormField( label: '비고', child: SuperportTextInput( controller: remarkController, placeholder: const Text('추가 설명을 입력하세요.'), maxLines: 3, ), ); ``` ## 3. 선택 컴포넌트 — `ShadSelect` - 단일 선택은 `ShadSelect`를 그대로 사용하고, `SuperportFormField`로 라벨만 감싼다. - 다중 선택이 필요한 경우 `ShadSelect.multiple` 과 토큰(UiChip) 스타일을 조합한다. - 최초 옵션은 `전체`/`선택하세요`처럼 명확한 기본값을 제공한다. ```dart SuperportFormField( label: '상태', required: true, child: ShadSelect( initialValue: controller.pendingStatus, selectedOptionBuilder: (_, value) => Text(value?.label ?? '전체 상태'), options: [ const ShadOption(value: null, child: Text('전체 상태')), for (final status in OrderStatus.values) ShadOption(value: status, child: Text(status.label)), ], onChanged: controller.onStatusChanged, ), ); ``` ## 4. 토글 — `SuperportSwitchField` - 스위치 단독 사용 시 라벨·캡션 레이아웃을 제공한다. - 접근성 관점에서 토글 설명은 문장형으로 작성한다. ```dart SuperportSwitchField( label: '파트너사 전용', value: controller.isPartnerOnly, onChanged: controller.onPartnerOnlyChanged, caption: '활성화 시 파트너사만 접근할 수 있습니다.', ); ``` ## 5. 날짜/기간 — `SuperportDatePickerButton` - 단일 날짜는 `SuperportDatePickerButton`, 기간은 `SuperportDateRangePickerButton`을 사용한다. - 포맷은 기본적으로 `yyyy-MM-dd`, 필요 시 `dateFormat`으로 주입. - 기간 선택은 `firstDate`/`lastDate` 범위를 명시해 엣지 케이스를 제한한다. ```dart SuperportFormField( label: '처리 기간', child: SuperportDateRangePickerButton( value: controller.pendingRange, onChanged: controller.onRangeChanged, firstDate: DateTime(2020), lastDate: DateTime(2030), ), ); ``` ## 6. 검증 메시지 - Validator는 필수 오류 → 형식 오류 → 업무 규칙 순서로 확인하고, 메시지는 `SuperportFormField.errorText`로 전달한다. - 포커스 이동 시 즉시 에러를 표시하며, 성공 시 `caption`으로 가이드를 남겨 재입력을 돕는다. ## 7. 레이아웃 - 가로 240px/500px 프리셋은 `SizedBox`로 감싸 사용하며, 반응형 환경에서는 `ResponsiveLayoutSlot`(섹션 13 참조)을 이용한다. - 두 줄 이상 배치 시 `Wrap` + `spacing:16`/`runSpacing:16`을 기본으로 한다. ## 8. 샘플 코드 경로 - `lib/widgets/components/form_field.dart` - `lib/features/inventory/inbound/presentation/pages/inbound_page.dart` — 입고 등록 모달 위 가이드를 준수하면 폼 간 스타일과 상호작용 규칙을 동일하게 유지할 수 있다.