# VD-05: Semantic icon facade와 native-first interaction - 상태: Accepted - 결정일: 2026-07-26 - 적용 브랜치: `feature-frontend-design-system-platform` - 재검토: native 계약으로 충족할 수 없는 widget 요구가 확인될 때 ## 배경 앱 셸과 공통 UI는 문자 glyph, raw button/select와 페이지별 focus 처리를 사용했다. 아이콘 공급자와 복합 interaction을 제품 코드에 직접 노출하면 번들, 접근성, vendor type과 교체 비용이 모든 feature로 전파된다. 반대로 실제 요구가 없는 두 개의 headless vendor를 기본 설치하면 skeleton 소비자가 제거해야 할 의존성과 중복 interaction 모델이 생긴다. ## 결정 1. 아이콘 공급자는 lockfile 최소 게시 유예를 통과한 `lucide-react@1.25.0`으로 고정한다. 2. `lucide-react`의 static named import는 `design-system/icons/vendors/lucide.tsx` 한 파일에서만 허용한다. 3. public API는 `MenuIcon`, `CloseIcon`, `WarningIcon` 같은 의미 이름만 노출한다. vendor component type, icon name, stroke API와 dynamic icon registry는 노출하지 않는다. 4. 장식 아이콘은 accessibility tree에서 제외한다. 정보를 단독 전달하는 아이콘은 `label`, icon-only action은 필수 `accessibleName`을 사용한다. 5. 현재 복합 control은 native `dialog`, form control, `details`와 local TypeScript state model로 구현한다. Menu는 roving focus/typeahead/Escape, Tabs는 manual/automatic activation, Drawer는 modal/background 비활성화/focus restore 계약을 가진다. 6. React Aria와 Radix는 기본 dependency로 추가하지 않는다. native platform이 collision, nested overlay, virtualized collection 또는 복합 select 요구를 충족하지 못한다는 재현 가능한 요구가 생길 때 prototype과 ADR로 다시 평가한다. 7. Storybook과 pinned visual baseline은 VD-08/RP-10에서 도입한다. RP-07의 runtime gallery와 browser interaction test는 해당 workshop을 대체한다고 주장하지 않는다. ## 경계와 검증 - 제품 코드는 `presentation/design-system/index`만 import한다. - design-system 검사기는 direct icon/headless import, deep import, raw palette, undefined token과 tooltip-only required information fixture를 거절한다. - type negative fixture는 accessible name 없는 `IconButton`을 거절한다. - component test는 decorative icon, form control, Menu, Tabs, Drawer와 Toast를 검증한다. - Chromium/Firefox E2E는 compact Drawer의 native modal 상태, Escape, focus restore, gallery keyboard interaction과 axe를 검증한다. - 로컬 WebKit 실행은 host `libevent-2.1.so.7` 부재로 환경 검증이 남아 있으며 공급자 선택이나 product behavior의 PASS로 숨기지 않는다. ## Rollback 기존 `presentation/components/ui/*` 경로는 canonical TypeScript primitive를 재수출하므로 소비 코드를 즉시 되돌릴 수 있다. Lucide 제거 시 vendor facade와 semantic icon 구현만 교체하고 제품 API는 유지한다. headless vendor를 나중에 도입해도 public props와 interaction test를 유지한다.