ComponentsP3 본문

FileViewer

통합 파일 뷰어 — 이미지·영상·PDF·텍스트·마크다운을 한 오버레이에서 렌더하고, 렌더러 레지스트리로 오피스·한글 어댑터까지 확장하는 뷰어입니다.

마지막 업데이트 2026-07-03

한눈에#

여러 종류의 파일을 한 전체 화면 뷰어에서 보는 통합 라이트박스입니다 — 이미지· 영상은 네이티브 미디어로, PDF는 브라우저 네이티브 뷰어로, 텍스트·마크다운은 자체 렌더러로 표시합니다. 타입별 렌더러는 레지스트리로 관리되어, 오피스·한글 같은 무거운 포맷은 소비자가 opt-in 어댑터를 등록해 확장합니다. 지원하지 않는 형식은 메타카드(파일명·형식·다운로드)로 조용히 강등됩니다.

트리거를 눌러 이미지·마크다운·텍스트·미지원 폴백을 직접 확인하세요:

사용 시점#

파일 첨부·문서 미리보기처럼 여러 타입의 원본을 한 뷰어에서 확인해야 하는 곳이면 FileViewer — 이미지·영상만이면 더 가벼운 ImageViewer가 적합합니다.

  • 쓴다 — FileUpload 미리보기, 첨부 목록 뷰어처럼 이미지·영상·PDF·문서가 섞여 있고 타입별로 다르게 보여줘야 할 때
  • 안 쓴다 — 이미지·영상만(ImageViewer), 확인·결정 다이얼로그(Modal), 인라인 확대(팝업이 과할 때)

변형·상태#

단일 컴포넌트입니다 — items가 2개 이상이면 좌우 내비게이션·1 / n 카운터·하단 필름스트립이 자동 노출됩니다. index+onIndexChange를 주면 제어 모드, 없으면 defaultIndex로 시작하는 비제어입니다.

  • 타입 판별 — 항목의 type을 주면 신뢰하고, 없으면 name·mimeType으로 판별합니다(image·video·pdf·document·spreadsheet·presentation·hwp·text·markdown·unknown)
  • 내장 렌더러(zero-dep) — image·video·pdf(네이티브 iframe)·text·markdown· csv(→ WDS Table 재사용). 액션바 컨트롤은 렌더러가 선언한 capabilities에서 파생됩니다(이미지=줌·회전, 문서·표=스크롤). 하드코딩 분기 없음. xlsx 등 바이너리 표는 어댑터가 필요합니다. text·markdown·csv는 인코딩을 자동 감지합니다 (BOM → UTF-8 → EUC-KR 폴백 — 한국 레거시 텍스트도 깨지지 않음, charset 힌트로 지정 가능)
  • 어댑터 확장renderers prop으로 pdf·office·hwp 등 렌더러를 등록/오버라이드. @wds/ui-web/viewers/docx(docxRenderer@wds/ui-web/viewers/hwp (createHwpRenderer@wds/ui-web/viewers/pdf(createPdfRenderer)는 무거운 의존을 optional peer로 분리한 서브패스 어댑터입니다. pdf 어댑터는 pdf.js 캔버스로 내장 native-pdf(iframe)를 오버라이드해 줌·세로 스크롤을 셸과 통합하며(iOS 인라인 실패·크롬 없는 일관 렌더에 유용), worker(pdf.worker.min.mjs)를, hwp 어댑터는 rhwp WASM (rhwp_bg.wasm)을 소비자가 same-origin 호스팅해 createPdfRenderer({ workerUrl })· createHwpRenderer({ wasmUrl })로 주입합니다. @wds/ui-web/viewers/xlsx (xlsxRenderer)는 엑셀(xlsx/xls/ods)을 파싱해 렌더하고(다중 시트는 탭), 내장 csv를 오버라이드해 csv까지 함께 처리합니다. .xlsx는 exceljs로 셀 서식(배경·글꼴·정렬· 테두리)·병합까지 렌더(엑셀답게)하고, xls·ods·csv나 exceljs 미설치 시 SheetJS 값 그리드로 폴백합니다. ★SheetJS(xlsx)는 npm 최신(0.18.5)이 CVE 2건으로 동결이라 공식 CDN tarball(cdn.sheetjs.com/xlsx-0.20.3)로 설치해야 합니다(소비 가이드 §7.5). @wds/ui-web/viewers/pptx(pptxRenderer)는 fflate로 OOXML을 열어 슬라이드 텍스트 아웃라인 + 임베디드 이미지·썸네일을 렌더합니다(도형·레이아웃 등 완전 시각 충실도는 서버 변환으로 — 소비 가이드 §7.6). 미등록 타입이나 어댑터 로드 실패(피어 미설치·worker/WASM 미호스팅)는 메타카드로 폴백
  • 액션 — 다운로드는 항상, 삭제는 onDelete를 줄 때만 노출

항목의 name은 헤더 캡션·필름스트립 라벨·dialog 접근성 이름·다운로드 파일명이 되고, description(용량·형식 등)은 하단 캡션으로 렌더됩니다.

API#

Prop타입기본값설명
openboolean
onClose() => void
itemsreadonly FileViewerItem[]표시할 파일 목록 — 2개 이상이면 ←/→ 내비·카운터·필름스트립 노출
indexnumber
defaultIndexnumber0
onIndexChange(index: number) => void
onDelete(index: number) => void제공 시 액션바에 삭제 노출 — 현재 항목 인덱스로 호출
closeLabelstring닫기
renderersPartial<Record<FileViewerItemType, FileRendererEntry>>코어 registry에 추가/오버라이드할 렌더러(어댑터). 미해결 타입은 메타카드 폴백. @wds /ui-web/viewers/* 어댑터를 여기 등록한다.
refRef<HTMLDivElement>

접근성#

role="dialog" + aria-modal로 열리고 이름은 현재 항목의 name입니다. 열리는 동안 포커스가 뷰어 안에 갇히고 배경은 inert 처리되며, 닫히면 트리거로 포커스가 복원됩니다(Modal과 동일 계약). 카운터는 aria-live="polite"로 항목 전환을 낭독하고, PDF는 title이 있는 <iframe>, 문서 본문은 키보드 스크롤 가능한 role="region"으로 렌더됩니다.

동작
/ 이전/다음 파일 (양 끝 클램프)
+ / -확대/축소 (이미지 전용)
0원래 크기 리셋 (이미지 전용)
Escape닫기

/는 항상 파일 축이며, 필름스트립 썸네일은 aria-current로 현재 항목을 노출합니다. 모든 크롬 버튼은 44px 터치 타깃입니다.

토큰#

표면은 WDS 라이트/다크 테마를 따릅니다 — 베일은 color.bg 92%(color-mix), 잉크는 color.text/text-subtle, 액션바는 color.surface+color.border+shadow.lg, 필름스트립 활성 썸네일은 color.primary 테두리입니다. 진입은 spring.spatial, 줌은 spring.effect이며 prefers-reduced-motion에서 정지합니다.

관련#

  • ImageViewer — 이미지·영상 전용 라이트박스(더 가벼움)
  • FileUpload — 미리보기가 뷰어를 합성
  • Modal — 결정형 오버레이 (같은 포커스/닫힘 계약)