Files
superport_v2/doc/input_widget_guide.md
2025-09-29 01:51:47 +09:00

4.1 KiB

입력 위젯 가이드

Superport v2의 폼 UI는 shadcn_ui 구성 요소를 기반으로 하며, 아래 지침을 따를 때 레이아웃과 상호작용이 일관되게 유지된다.

1. 기본 컨테이너 — SuperportFormField

  • 라벨/필수 표시/보조 설명/에러 메시지를 하나의 빌딩 블록으로 묶는다.
  • 라벨은 좌측 정렬, 12pt, 필수 항목은 *(파괴색)으로 표시한다.
  • 자식 위젯은 ShadInput, ShadSelect, SuperportDatePickerButton 등 어떤 입력 요소든 가능하다.
  • 에러 문구는 상단 Validator에서 내려오는 한글 메시지를 그대로 사용한다.
SuperportFormField(
  label: '창고',
  required: true,
  caption: '입고가 진행될 창고를 선택하세요.',
  errorText: state.errorMessage,
  child: ShadSelect<String>(
    initialValue: controller.selectedWarehouse,
    options: warehouses.map((w) => ShadOption(value: w.id, child: Text(w.name))).toList(),
    onChanged: controller.onWarehouseChanged,
  ),
);

2. 텍스트 입력 — SuperportTextInput

  • ShadInput에 공통 프리셋을 적용한 래퍼.
  • 플레이스홀더는 한글 문장형으로 작성하고, 검색 필드라면 돋보기 아이콘을 leading으로 배치한다.
  • 여러 줄 입력은 maxLines 변경만으로 처리한다.
SuperportFormField(
  label: '비고',
  child: SuperportTextInput(
    controller: remarkController,
    placeholder: const Text('추가 설명을 입력하세요.'),
    maxLines: 3,
  ),
);

3. 선택 컴포넌트 — ShadSelect

  • 단일 선택은 ShadSelect<T>를 그대로 사용하고, SuperportFormField로 라벨만 감싼다.
  • 다중 선택이 필요한 경우 ShadSelect.multiple 과 토큰(UiChip) 스타일을 조합한다.
  • 최초 옵션은 전체/선택하세요처럼 명확한 기본값을 제공한다.
SuperportFormField(
  label: '상태',
  required: true,
  child: ShadSelect<OrderStatus?>(
    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

  • 스위치 단독 사용 시 라벨·캡션 레이아웃을 제공한다.
  • 접근성 관점에서 토글 설명은 문장형으로 작성한다.
SuperportSwitchField(
  label: '파트너사 전용',
  value: controller.isPartnerOnly,
  onChanged: controller.onPartnerOnlyChanged,
  caption: '활성화 시 파트너사만 접근할 수 있습니다.',
);

5. 날짜/기간 — SuperportDatePickerButton

  • 단일 날짜는 SuperportDatePickerButton, 기간은 SuperportDateRangePickerButton을 사용한다.
  • 포맷은 기본적으로 yyyy-MM-dd, 필요 시 dateFormat으로 주입.
  • 기간 선택은 firstDate/lastDate 범위를 명시해 엣지 케이스를 제한한다.
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 — 입고 등록 모달

위 가이드를 준수하면 폼 간 스타일과 상호작용 규칙을 동일하게 유지할 수 있다.