Repository navigation
refactor(ui): 대화상자·시트·메뉴·선택기를 shadcn(Base UI) 동작 부품으로 교체 - #254
Merged
Merged
Conversation
- button, dialog, alert-dialog, drawer, dropdown-menu, select, combobox, popover, tabs와 combobox가 쓰는 input-group을 받은 그대로 둠(모두 Base UI 기반, drawer도 vaul 없음) - add가 함께 설치한 cn 패키지는 부품을 고칠 때 @/lib/utils로 바꾸고 지운다 - add가 덮어쓴 input·textarea는 우리 파일로 되돌림 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 대화상자 안 폼을 새로 쓸 때 @tanstack/react-form으로 칸별 검증·제출 상태를 다룬다(zod는 나중에) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 앱 내용을 isolate 묶음으로 감싸 body로 포털되는 Base UI 팝업이 앱의 z-index와 섞이지 않게 함(토스트는 밖에 두어 대화상자 위에 보임)
- iOS 26 Safari용 body { position: relative } 추가(Base UI 빠른 시작 안내)
- 랜딩·로그인 PC·모바일에서 감싸기 전후 배치가 같음을 확인
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma ❸ Icon의 check(252:27411)·sign/logout(252:30979) 24px 원본, 선 1.8·currentColor - Select·Combobox 선택 표시와 메뉴의 나가기·로그아웃 항목에 쓴다 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma Button(5272:3019)·Button Base(5002:3814): variant solid·weak·outline × tone neutral·brand·critical × size lg 56·md 48·sm 36·xs 32, 등록된 6종만 타입으로 허용 - Hover·Pressed·Disabled(opacity 없이 fill/default·text/disabled)·Loading 색을 Figma 값으로, 비활성은 data-disabled로 그림 - loading이면 내용 자리를 남기고 가운데 progress(lg 24·그 외 20), 중복 실행 차단·포커스 유지, 이름은 loadingLabel(aria-labelledby) - buttonVariants는 내보내지 않음(className으로 버튼 모양 흉내 금지) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma Modal(5956:24724): padding 20·간격 20·모서리 12·fill/elevate·shadow/default, 딤은 지금 앱 값 black/40 - 제목 줄에 닫기 X(24, 누르는 영역 44), Footer는 취소→확인 꽉 채움, 폭은 Figma 353 기본 + 지금 화면 폭 변형 - closeDisabled면 Esc·딤·X·취소로 닫히지 않고, 안쪽 입력이 막은 Esc는 대화상자를 닫지 않음 - 열림·닫힘은 Base UI data-starting/ending-style 전환, 중첩 대화상자도 딤을 그림 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma Alert Dialog(5621:3002): 353~400 폭·padding 24·모서리 10·그림자 없음·가운데 정렬, 버튼 md 48 꽉 채움(가로 취소→주요, 세로 주요→취소) - 확인 버튼은 Neutral Solid 또는 Critical Solid만, 첫 포커스는 취소 버튼 - backdropCloseLabel을 주면 딤을 눌러 닫힘(지금 확인창 동작), closeDisabled로 처리 중 닫힘을 막음, z-50·최대 높이 스크롤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma Bottom Sheet(5924:13961): 위 모서리 20, 딤 gray-950 20%, 제목 title/lg·영역 간격 20, 손잡이 36×4 - 아래로 스와이프해 닫기(Base UI 기준), 버튼·입력·label·checkbox/switch/radio 위에서는 끌리지 않음 - Dialog와 같은 closeDisabled·Esc 규칙, 중첩 시트도 딤을 그림 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma Dropdown Menu(5864:13084)·Item(5956:16861): 모서리 12·테두리 없음·shadow/default·최소 폭 160·항목 48/50, 위험 항목 red-800
- 기본 modal={false}로 바깥 클릭이 뒤로 전달되고 스크롤을 막지 않는 지금 동작 유지, 키보드 포커스 윤곽선
- 링크 항목은 누르면 닫힘, 북마크 2단 메뉴용 하위 메뉴 파트
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma 08 Select(5047:440): 트리거 48·모서리 8, 목록 fill/elevate·border·shadow·행 56+구분선, 선택 행 체크 16
- 기본 alignItemWithTrigger={false}·modal={false}(아래로 열리고 바깥 클릭이 전달되는 지금 동작)
- 오류는 Text Field 모양(aria-invalid 빨간 테두리, Field 라벨·FieldError), 포커스 윤곽선·hover 테두리
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma 07 Select Field(5030:666): 검색칸은 SearchBar 모양, 목록 fill/subtle·border·그림자 없음·행 56+구분선, 선택 행 체크 16 - 통화 선택처럼 트리거 → 팝업 안 검색 → 목록 패턴용 파트만 남김 - input-group은 SearchBar와 겹치고 쓰는 곳이 없어 지움 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma에 일반 팝오버가 없어 Modal 표면(fill/elevate·모서리 12·shadow/default), 여백·폭은 지금 헤더 미리보기 값(panel) - 기간 칸 아래 달력용 bare 변형(기준 요소 폭), 기본 sideOffset 8 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma 11 Tabs(5138:2632): Line은 탭마다 고정 2px 막대(border-subtle, 선택 primary), Chip Solid·Outline 변형, 좌우 padding 24 - shadcn 전용 변형(data-horizontal 등)을 data-[orientation]으로 바꿈 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 받은 부품을 모두 @/lib/utils의 cn(타이포 토큰 등록)으로 바꿔 쓰는 곳이 없음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 원칙 1-1: 범용 Button 보류 문구를 ui Button 사용법으로, 팝업 z-index는 모두 z-50 + 앱 isolate 묶음, 예시를 ui Dialog로 - 원칙 2-9 새로 씀: 대화상자 폼은 TanStack Form, 검증은 칸마다, 버튼 loading·closeDisabled는 mutation isPending 하나로 - 안티패턴 6: 손으로 만든 메뉴·셀렉트·탭과 useState 폼을 신호로, 쓸 부품 목록 갱신 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ResponsiveDialog: PC는 Dialog, 모바일 기기(isMobileDevice)는 아래 시트(Drawer)로 같은 내용을 그린다 - DialogBody: 긴 폼에서 제목 줄·Footer는 고정하고 본문만 스크롤한다(시트 DrawerBody와 같은 방식) - 원칙 1-1 부품 표에 ResponsiveDialog 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 확인창 모양 3종(default·ledger·alert)을 Figma Alert Dialog 하나로 통일하고 appearance prop 삭제 - 처리 중에는 확인 버튼에 progress를 보이고 Esc·딤·취소를 모두 막는다(문구 '처리 중…' 대신) - 딤을 누르면 닫히는 지금 동작은 유지, 닫기 X는 Figma에 없어 뺐다 - 삭제·비우기 확인창(북마크 폴더·장소, 일차, 일정 장소, 메모)에 destructive를 줘 Critical 버튼으로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 비용 추가·수정, 비용 목록, 정산 요약: showModal 대화상자 → ResponsiveDialog(PC Dialog, 모바일 기기 시트) - 비용 추가·수정 폼을 TanStack Form으로 옮기고 칸마다 오류(빨간 테두리 + 아래 문구)를 보인다. 카테고리 Select도 같은 오류 모양 - validateExpense를 칸별 검증 함수로 나눔(기존 결과·문구는 그대로) - 카테고리·일차·연결 장소는 ui Select, 통화는 ui Combobox(팝업 안 검색, 검색어 입력 뒤 Enter로 첫 결과 선택) - 통화 목록이 없거나 목록 밖 통화여도 통화 칸에 폼 값을 보인다 - 비용 삭제 확인은 AlertDialog, 실패하면 포커스를 그 삭제 버튼으로 돌린다 - 정산 요약 대화상자는 시트 높이를 BelowNav로 고정하고 쓰지 않던 settlement 분기 삭제 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 가계부 버튼을 ui Button으로(expenseButtonClass 삭제), 비용 더보기 메뉴는 DropdownMenu - 정산 범위·분석 기준 탭은 Tabs(Chip Outline). 일차 필터 알약은 그대로 - 예산 대화상자: Dialog + TanStack Form. 입력 오류는 칸 아래, 저장 실패는 칸 밖 문장(지금 구분 유지), 저장 중 progress·닫기 막기 - 조회 다시 시도 버튼은 테스트가 disabled를 확인해 loading 대신 지금처럼 문구 + disabled Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 시간 설정: Dialog + TanStack Form, 적용 중 progress·닫기 막기 - 메모 덮어쓰기 확인은 ConfirmDialog, 메모 인라인 취소·저장은 Button sm - 일차 메뉴는 DropdownMenu(포털 클릭이 일차 섹션으로 올라가지 않게 감쌈) - 북마크에서 추가: ResponsiveDialog(PC Dialog, 모바일 기기 시트) - 쓰지 않게 된 timeSaveButtonCompact 토큰 삭제 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 일차 관리·장소 메뉴·메모·시간 시트를 Base UI Drawer로(끌어서 닫기·포커스·스크롤 잠금은 Base UI 기본) - 메모 시트는 TanStack Form, 2000자 넘으면 칸 오류. 저장·삭제는 누른 버튼에만 progress - 시간 시트 저장 버튼은 Button loading(폼은 버튼·휠 구성이라 그대로) - 장소 메뉴 '일정 추가'로 검색 화면을 열 때는 시트의 포커스 복귀를 꺼 검색창 포커스·키보드를 지킨다 - 메뉴 행은 MobileSheetMenuItem으로 옮기고, 쓰는 곳이 없어진 MobileBottomSheet와 테스트 삭제 - drawer.tsx 주석의 '지금 시트'를 '옛 시트'로 정리 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 북마크에 담기·일정에 추가: createPortal 오버레이 → Dialog, 처리 중 progress·닫기 막기. 일정 목록은 DialogBody로 포커스 윤곽이 잘리지 않게 - 북마크 생성·편집: Dialog + TanStack Form(제목 50자 검증·글자 수), 색 선택은 그대로 - 북마크 폴더·장소 메뉴는 DropdownMenu. 장소의 '카테고리 변경'은 하위 메뉴 대신 지금처럼 메뉴 안 단계 전환 - 장소 상세 홈·리뷰 탭은 ui Tabs(line) - 쓰지 않게 된 DropdownMenuSub 파트와 place Tab 타입 삭제 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 지도 평점 필터: FilterDropdown → ui Select(트리거는 칩 모양, 고르면 선택 칩). 스크롤·창 크기 변경 때 닫힘은 유지 - 날짜 선택: 칸 아래 달력은 Popover, 가운데 팝업은 Base UI Dialog(대화상자 위에서 열면 Esc는 달력만 닫는다) - 쓰지 않게 된 filter-dropdown·map-chip-button과 드롭다운 z 상수 삭제 - 다음 커밋(여행 정보 수정 대화상자 교체)과 함께 대화상자 안 날짜 팝업이 위에 뜬다 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 초대하기·여행 정보 수정: SettingsDialog → Dialog. 적용하기는 Button(대화상자 규칙 Neutral Solid) - 여행 정보 수정 폼 값은 TanStack Form으로 관리(칸 표시 props·저장 호출은 테스트가 확인해 유지) - 기간 축소 확인은 폼의 자식 AlertDialog로 대화상자 위에 뜬다 - 목적지 입력의 Esc는 추천 목록이 열려 있을 때만 목록을 닫고, 닫혀 있으면 대화상자가 닫힌다 - 홈 프로필·방 카드 메뉴는 DropdownMenu(아이콘은 디자인 시스템 아이콘), 쓰지 않게 된 Figma svg 4개 삭제 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 모바일 헤더 메뉴·구성원 옵션 메뉴는 DropdownMenu, 헤더 구성원 미리보기는 Popover(안의 구성원 메뉴를 눌러도 닫히지 않음) - 구성원 안내·회원 탈퇴 2종은 AlertDialog(탈퇴는 Critical), 쿠키 설정은 Dialog(포커스 복귀 순서는 지금과 같음) - 쿠키 저장·동의 배너·내 정보 버튼을 SettingsActionButton → ui Button - 쿠키 동의 배너를 z-40으로 낮춰 Base UI 대화상자(z-50)가 배너를 덮게 한다 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 카테고리·준비물 이름 대화상자: Dialog + TanStack Form(이름 검증은 칸 오류), 메모도 TanStack Form - 카테고리 메뉴는 DropdownMenu, 삭제 확인은 ConfirmDialog, 버튼은 ui Button - 상세는 PC 오른쪽 패널 그대로, 모바일 기기는 Drawer. 시트 이름은 준비물 이름 - 동기화 오류처럼 저장할 수 없는 상태면 저장·추가 버튼을 비활성으로 보인다(다른 항목 저장 중에는 제출만 막음) - 쓰지 않게 된 CSS 규칙과 테스트의 SettingsDialog mock 삭제 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- SettingsDialog·SettingsActionButton·useSheetDrag·BottomSheetDragHandle 삭제(모든 화면이 ui 부품으로 옮김) - 지운 SettingsDialog의 테스트 케이스 삭제 - ui 주석에서 옛 부품을 가리키는 표현 정리 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- lg(640) → sm(384), dialog size 주석의 사용처도 옮김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 개인정보 처리방침을 한 줄로 두고 그 아래 Footer(취소 Neutral Weak → 저장 Neutral Solid) - 취소는 대화상자를 닫음(onCancel), 저장 결과 문장은 버튼 아래 - 테스트 렌더에 onCancel 추가(기대값 그대로) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- sm(384) → md(448), dialog size 주석의 사용처도 옮김(회원 탈퇴는 AlertDialog로 바뀌어 뺌) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- sm(384)이 좁아 어색해서 md(448), dialog size 주석의 사용처도 옮김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Figma body/lg(18)가 제목에 비해 커 보여 body-m-regular(16/24)로, 제목 22는 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 목록 폭이 트리거 폭(144·160)과 같아, 체크 자리 48과 스크롤 막대 15가 생기면 '전체 카테고리'가 두 줄이 됨 - 두 폭 구분 없이 184 하나로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 입력바 100 → 124(14px 글자 3줄), 모바일 기기는 100 그대로, 작은 패널 110 그대로 - 높이를 인라인 style에서 클래스(mobile: 변형)로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 스크롤 막대를 늘 숨겨 마우스로는 뒤쪽 일차(Day 20 등)에 닿을 수 없었음 - PC는 얇은 막대(북마크에서 추가 칩 줄과 같은 모양), 모바일 기기는 지금처럼 숨김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 통화 칸 96 → 112: ui Combobox 트리거의 여백·▼ 자리(66)를 빼면 코드 자리가 30이라 KRW·BHD가 말줄임됐음 - 16px에서 가장 넓은 코드(MWK 37)도 들어가는 46 확보 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # src/components/rooms/RoomTripEditForm.tsx
- ConfirmDialog에 confirmDisabled 추가(확인 버튼만 비활성, 취소·닫기는 그대로) - 동기화 오류 등 ready가 아닐 때 '삭제'가 눌리는데 아무 반응이 없던 문제(옛 화면은 비활성) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 대화상자 안 버튼만 loading(progress·aria-busy), 패널의 재시도 버튼은 대화상자 밖이라 문구 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 제목·목적지·기간을 form.Field + validators로, 오류는 칸 아래 FieldError(제목은 aria-invalid로 Text Field 오류 모양) - 검증 함수는 trip-form.ts의 tripTitleError·tripDestinationsError·tripDateRangeError(나중에 zod 스키마 자리), 적용하기 잠금도 같은 함수 - RoomTripEditFields는 읽기 전용 칸만 남겨 RoomTripReadOnlyFields로, 목적지는 새 여행 만들기와 같은 DestinationChipsField 재사용 - 테스트는 실제 제목 칸·목적지·기간 onChange로 바꾸고 칸별 오류 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 포털된 대화상자·메뉴를 document에서 찾고, dialog[open] 대신 role="dialog"·menuitem - Tab 순환·메뉴 좌표 단정은 Base UI 몫이라 빼고, 바깥 aria-hidden·포커스 복귀·메뉴 단계 전환으로 검사 - 저장 중 닫힘 막힘, 제목 칸 오류(aria-invalid·칸 아래 문장), 목적지 비움 오류, 기간 축소 확인 저장 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- react-test-renderer 대신 react-dom + document 조회, props 직접 호출 대신 실제 클릭·입력 이벤트 - 확인창: X 없음, 바깥 aria-hidden, 진행 중 접근성 이름 '처리 중'·aria-busy, 첫 포커스 '취소' - 시트 끌기 수치·Tab 순환 테스트는 지우고, 저장 중 닫힘 막힘·모바일 메모 초안 유지·삭제 확인 confirmDisabled 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- dialog[open]·aria-modal·inert 대신 role="dialog"·바깥 aria-hidden, 메뉴·Select 목록은 document에서 menuitem·option으로 - 옛 SettingsDialog 클래스 계약(거터·640 폭) 테스트는 지움 - 쿠키 설정 취소(저장 안 하고 닫힘)·저장 결과 문장이 버튼 아래 live 영역에 보이는지, 모바일 메뉴 항목으로 수정 대화상자 열기 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- react-test-renderer(Base UI 메뉴 트리거가 렌더 단계에서 실패) 대신 react-dom + document 조회, props 직접 호출 대신 실제 메뉴·Select·탭 조작 - 확인창 mock 대신 실제 alertdialog, 예산 칸 오류는 aria-invalid·aria-describedby FieldError로 검사 - 정산 요약 대화상자 안 재시도는 progress(aria-busy·이름 '조회 다시 시도 중'), 패널 재시도는 native disabled 그대로인지 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- react-test-renderer props 호출 대신 react-dom + 실제 클릭·입력·키 이벤트, 가짜 native dialog 제거 - 오류는 칸별(aria-invalid·칸 아래 FieldError)로, 폼 아래 문장은 저장 실패·권한 같은 폼 전체 오류만 - 카테고리 칸 오류, 목록·통화 검색 Esc는 팝업만 닫힘, PC 딤은 안 닫고 모바일 시트 딤은 닫음, 빈 값 '장소 연결 없음' 표시 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ExpenseDialog.drag.test 삭제: 옛 useSheetDrag 수치(translateY·80px) 검사라 끌기는 Base UI Drawer 몫 - ExpenseBackdrop.test를 새 동작으로 다시 씀: 모바일 시트는 딤으로 닫힘, PC는 딤으로 안 닫힘, 저장·삭제 중엔 딤·Esc·X·취소 모두 막힘 - ExpenseProvider·ExpenseScopePanel은 react-dom + document 조회, 삭제 중 확인 버튼 progress(aria-busy·이름 '삭제 중') Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 저장 요청(useUpdateRoom)을 대화상자가 만들어 폼에 내려 주고, 대화상자는 그 isPending으로 closeDisabled - 저장 중 Esc·X로 닫히지 않는 테스트 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Popover modal="trap-focus" + 보이지 않는 Popover.Close(Base UI는 닫기 부품이 있어야 가둠, Tab 순서 밖, 누르면 Esc처럼 취소) - 달력이 body로 포털된 뒤 마지막 버튼에서 Tab을 누르면 로고 링크로 튀고 달력이 열린 채 남던 회귀 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



노션
변경 내용
변경 이유
refactor/shadcn-base-ui로 유지. 이 PR을 병합하면 refactor(ui): 공통 UI와 대화상자를 shadcn(Base UI)으로 통합 #253 head가 바뀌므로 refactor(ui): 공통 UI와 대화상자를 shadcn(Base UI)으로 통합 #253 병합 전 새 head의 검증 결과를 다시 확인테스트
npm run lintnpm test— 최신 수정본 1,663개 통과npm run build— 로컬 테스트 설정으로 검증🤖 Generated with Claude Code