ERP-node/docs/responsive-component-strate...

5.8 KiB

WACE 반응형 컴포넌트 전략

개요

WACE 프로젝트의 모든 반응형 UI는 3개의 레이아웃 프리미티브 + 1개의 훅으로 통일한다. 컴포넌트마다 새로 타입을 정의하거나 리사이저를 구현하지 않는다.

아키텍처

┌─────────────────────────────────────────────────┐
│            useResponsive() 훅                    │
│   isMobile | isTablet | isDesktop | width       │
└──────────┬──────────┬──────────┬────────────────┘
           │          │          │
   ┌───────▼──┐ ┌────▼─────┐ ┌─▼──────────────┐
   │ 데이터    │ │ 좌우분할  │ │ 캔버스(디자이너)│
   │ 목록      │ │ 패널     │ │ 화면           │
   └──────────┘ └──────────┘ └────────────────┘
   ResponsiveDataView  ResponsiveSplitPanel  ResponsiveGridRenderer

1. useResponsive (훅)

위치: frontend/lib/hooks/useResponsive.ts

모든 반응형 판단의 기반. 직접 breakpoint 분기가 필요할 때만 사용. 가능하면 아래 레이아웃 컴포넌트를 쓰고, 훅 직접 사용은 최소화.

반환값 브레이크포인트 해상도
isMobile xs, sm < 768px
isTablet md 768 ~ 1023px
isDesktop lg, xl, 2xl >= 1024px

2. ResponsiveDataView (데이터 목록)

위치: frontend/components/common/ResponsiveDataView.tsx 패턴: 데스크톱 = 테이블, 모바일 = 카드 리스트 적용 대상: 모든 목록/리스트 화면

<ResponsiveDataView<User>
  data={users}
  columns={columns}
  keyExtractor={(u) => u.id}
  cardTitle={(u) => u.name}
  cardFields={[
    { label: "이메일", render: (u) => u.email },
    { label: "부서", render: (u) => u.dept },
  ]}
  renderActions={(u) => <Button>편집</Button>}
/>

적용 완료 (12개 화면):

  • UserTable, CompanyTable, UserAuthTable
  • DataFlowList, ScreenList
  • system-notices, approvalTemplate, standards
  • batch-management, mail/receive, flowMgmtList
  • exconList, exCallConfList

3. ResponsiveSplitPanel (좌우 분할)

위치: frontend/components/common/ResponsiveSplitPanel.tsx 패턴: 데스크톱 = 좌우 분할(리사이저 포함), 모바일 = 세로 스택(접기/펼치기) 적용 대상: 카테고리관리, 메뉴관리, 부서관리, BOM 등 좌우 분할 레이아웃

<ResponsiveSplitPanel
  left={<TreeView />}
  right={<DetailPanel />}
  leftTitle="카테고리"
  leftWidth={25}
  minLeftWidth={10}
  maxLeftWidth={40}
  height="calc(100vh - 120px)"
/>

Props:

Prop 타입 기본값 설명
left ReactNode 필수 좌측 패널 콘텐츠
right ReactNode 필수 우측 패널 콘텐츠
leftTitle string "목록" 모바일 접기 헤더
leftWidth number 25 초기 좌측 너비(%)
minLeftWidth number 10 최소 좌측 너비(%)
maxLeftWidth number 50 최대 좌측 너비(%)
showResizer boolean true 리사이저 표시
collapsedOnMobile boolean true 모바일 기본 접힘
height string "100%" 컨테이너 높이

동작:

  • 데스크톱(>= 1024px): 좌우 분할 + 드래그 리사이저 + 좌측 접기 버튼
  • 모바일(< 1024px): 세로 스택, 좌측 패널 40vh 제한, 접기/펼치기

마이그레이션 후보:

  • V2CategoryManagerComponent (완료)
  • SplitPanelLayoutComponent (v1, v2)
  • BomTreeComponent
  • ScreenSplitPanel
  • menu/page.tsx (메뉴 관리)
  • departments/page.tsx (부서 관리)

4. ResponsiveGridRenderer (디자이너 캔버스)

위치: frontend/components/screen/ResponsiveGridRenderer.tsx 패턴: 데스크톱(비전폭 컴포넌트) = 캔버스 스케일링, 그 외 = Flex 그리드 적용 대상: 화면 디자이너로 만든 동적 화면

이 컴포넌트는 화면 디자이너 시스템 전용. 일반 개발에서 직접 사용하지 않음.

사용 가이드

새 화면 만들 때

화면 유형 사용 컴포넌트
데이터 목록 (테이블) ResponsiveDataView
좌우 분할 (트리+상세) ResponsiveSplitPanel
디자이너 화면 ResponsiveGridRenderer (자동)
단순 레이아웃 Tailwind 반응형 (flex-col lg:flex-row)

금지 사항

  1. 컴포넌트 내부에 isDraggingRef, handleMouseDown/Move/Up 직접 구현 금지 -> ResponsiveSplitPanel 사용
  2. hidden lg:block / lg:hidden 패턴으로 테이블/카드 이중 렌더링 금지 -> ResponsiveDataView 사용
  3. window.innerWidth 직접 체크 금지 -> useResponsive() 훅 사용
  4. 반응형 분기를 위한 새로운 타입/인터페이스 정의 금지 -> 기존 프리미티브의 Props 사용

폐기 예정 컴포넌트

컴포넌트 대체 상태
ResponsiveContainer Tailwind 또는 useResponsive 미사용, 삭제 예정
ResponsiveGrid Tailwind grid-cols-* 미사용, 삭제 예정
ResponsiveText Tailwind text-sm lg:text-lg 미사용, 삭제 예정

파일 구조

frontend/
├── lib/hooks/
│   └── useResponsive.ts           # 브레이크포인트 훅 (기반)
├── components/common/
│   ├── ResponsiveDataView.tsx      # 테이블/카드 전환
│   └── ResponsiveSplitPanel.tsx    # 좌우 분할 반응형
└── components/screen/
    └── ResponsiveGridRenderer.tsx  # 디자이너 캔버스 렌더러