# Vue File Preview [![npm version](https://img.shields.io/npm/v/@eternalheart/vue-file-preview.svg)](https://www.npmjs.com/package/@eternalheart/vue-file-preview)[![license](https://img.shields.io/npm/l/@eternalheart/vue-file-preview.svg)](https://github.com/wh131462/file-preview/blob/master/LICENSE)[![downloads](https://img.shields.io/npm/dm/@eternalheart/vue-file-preview.svg)](https://www.npmjs.com/package/@eternalheart/vue-file-preview) English | [简体中文](./README.zh-CN.md) A modern, feature-rich file preview component for Vue 3 with support for images, videos, audio, PDFs, Office documents (Word, Excel, PowerPoint), Markdown, and code files. ## ✨ Features - 🎨 **Modern UI** - Clean and modern interface with smooth animations - 📁 **Multi-format Support** - Supports 20+ file formats - 🪟 **Two Display Modes** - Full-screen modal **or** inline embedded preview - 🖼️ **Powerful Image Viewer** - Zoom, rotate, drag, mouse wheel zoom - 🎬 **Custom Video Player** - Built on Video.js, supports multiple video formats - 🎵 **Custom Audio Player** - Beautiful audio control interface - 📄 **PDF Viewer** - Pagination support - 📊 **Office Documents Support** - Word, Excel, PowerPoint file preview - 📝 **Markdown Rendering** - GitHub Flavored Markdown support - 💻 **Code Highlighting** - Supports 40+ programming languages - 📱 **Responsive Design** - Adapts to all screen sizes - ⌨️ **Keyboard Navigation** - Arrow keys and ESC support ## 📦 Installation ```bash # Using npm npm install @eternalheart/vue-file-preview # Using yarn yarn add @eternalheart/vue-file-preview # Using pnpm pnpm add @eternalheart/vue-file-preview ``` **Important:** You also need to import the CSS file: ```ts import '@eternalheart/vue-file-preview/style.css'; ``` ### PDF.js Configuration (Optional) If you need to preview PDF files, it's recommended to configure PDF.js to use local static files for better performance and stability: #### Method 1: Use CDN (Default) By default, the component automatically uses unpkg CDN to load PDF.js, no additional configuration needed. #### Method 2: Use Local Static Files (Recommended for Production) 1. Copy PDF.js files to your public directory: ```bash cp -r node_modules/pdfjs-dist/build/pdf.worker.min.mjs public/pdfjs/ cp -r node_modules/pdfjs-dist/cmaps public/pdfjs/ ``` 2. Configure PDF.js in your app entry: ```ts import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs'; import { configurePdfWorker } from '@eternalheart/vue-file-preview'; configurePdfWorker(pdfjsLib, { workerSrc: '/pdfjs/pdf.worker.min.mjs', cMapUrl: '/pdfjs/cmaps/', cMapPacked: true, }); ``` #### Auto-copy with Vite (Recommended) Configure auto-copy in `vite.config.ts`: ```ts import { defineConfig } from 'vite'; import { viteStaticCopy } from 'vite-plugin-static-copy'; export default defineConfig({ plugins: [ viteStaticCopy({ targets: [ { src: 'node_modules/pdfjs-dist/build/pdf.worker.min.mjs', dest: 'pdfjs' }, { src: 'node_modules/pdfjs-dist/cmaps', dest: 'pdfjs' } ] }) ] }); ``` ### Vite Bundler Note (AVIF Decoder) If your project bundler is Vite and you happen to have `@jsquash/avif` installed (transitively or directly), the production build may fail with: ``` [commonjs--resolver] Invalid value "iife" for option "worker.format" - UMD and IIFE output formats are not supported for code-splitting builds. file: .../@jsquash/avif/codec/enc/avif_enc_mt.js ``` This happens because `@jsquash/avif` ships a multi-threaded worker that uses code-splitting, while Vite's default `worker.format` is `'iife'`, which does not support split chunks. **Fix** — add this to your `vite.config.ts`: ```ts export default defineConfig({ // ... your existing config worker: { format: 'es', }, }); ``` `'es'` produces module workers (`type: 'module'`), supported by all modern browsers and compatible with code-splitting. > Note: `@jsquash/avif` is only used as a fallback when the browser does not natively support AVIF (Chrome 85+, Firefox 93+, Safari 16+ all support it natively). If your target browsers cover the native list, you can also remove `@jsquash/avif` from your dependencies entirely. ## 🚀 Quick Start ### Basic Usage ```vue ``` ### Multiple Input Types The component supports three types of file inputs: ```vue ``` ### Embedded Mode (`FilePreviewEmbed`) Besides the full-screen modal, the library also ships an **embedded** variant that renders the preview inline inside any container. Useful for detail panels, side-by-side layouts, dashboards, etc. ```vue ``` Differences from `FilePreviewModal`: - No teleport, no full-screen overlay, no `isOpen` / `@close` - Does **not** show the close button in the toolbar - Keyboard navigation (←/→) is scoped to the embed container (focus-based) - Size defaults to `width: 100%; height: 100%`; override via `width` / `height` props ```vue ``` ## 📖 Supported File Formats ### Images - **Formats**: JPG, PNG, GIF, WebP, SVG, BMP, ICO - **Features**: Zoom (0.1x - 10x), rotate, drag, mouse wheel zoom, double-click reset ### Videos - **Formats**: MP4, WebM, OGG, MOV, AVI, MKV, M4V, 3GP, FLV - **Features**: Custom player, progress control, volume adjustment, fullscreen ### Audio - **Formats**: MP3, WAV, OGG, M4A, AAC, FLAC - **Features**: Custom player, progress bar, volume control, skip forward/backward ### Documents - **PDF**: Pagination, zoom - **Word**: DOCX format support - **Excel**: XLSX format support - **PowerPoint**: PPTX/PPT format support, slide preview ### Fonts - **Formats**: TTF, OTF, WOFF, WOFF2 - **Features**: Font metadata (family, designer, version), character set preview, custom text input, multi-size display ### Code & Text - **Markdown**: GitHub Flavored Markdown, code highlighting - **Code Files**: JS, TS, Python, Java, C++, Go, Rust, and 40+ languages - **Config/Logs**: YAML, TOML, INI, ENV, LOG, DIFF, PATCH, etc. ### Structured Data - **JSON**: Auto formatting + syntax highlighting - **CSV/TSV**: Zero-dependency parser, table view with headers and row/column stats - **XML**: `DOMParser` validation + pretty print + syntax highlighting ### Subtitles & Lyrics - **SRT / WebVTT**: Zero-dependency parser, structured cue list (index, time range, text) - **LRC / Enhanced LRC**: Lyric files with `[mm:ss.xx]` line stamps (and inline `` per-word stamps for ELRC), with `[ti:][ar:][al:]` metadata header - **ASS / SSA**: Advanced SubStation Alpha — extracts Dialogue events, strips `\N` `\h` and `{...}` override codes, surfaces Style names - **TTML / DFXP**: W3C / Apple Music XML captions, supports `begin` / `end` / `dur` and `
` ### Archives - **ZIP**: Tree view + inline preview for text/code/image entries, download fallback for other types ### Outlook Email - **MSG**: Headers, body rendering, attachment list ### E-books - **EPUB**: Chapter navigation, pagination ## ⚠️ Limitations & Performance ### Support Levels **✅ Full Support (Production Ready)** - Images (JPG, PNG, GIF, WebP, SVG, BMP, ICO) - Videos (MP4, WebM, OGG) - Audio (MP3, WAV, OGG) - PDF - Markdown - Code files (40+ languages via Shiki, lazy-loaded) - JSON, CSV, XML **⚠️ Partial Support (Preview Only)** - **Office (DOCX, XLSX, PPTX)**: Basic layout and text rendering. Complex formatting (charts, macros, embedded objects) may not render accurately. - **ZIP**: Directory tree browsing + inline preview for text/code/images. Large archives (>100MB) may cause performance issues. - **Fonts (TTF, OTF, WOFF)**: Metadata + character preview. Full font feature testing not supported. **🧪 Experimental** - **MSG (Outlook Email)**: Headers and plain text body. Complex HTML body may not render correctly. - **EPUB**: Basic chapter navigation. CSS styling may differ from native readers. DRM-protected files not supported. - **Subtitle formats (SRT, ASS, TTML, LRC)**: Text display only. No video sync or advanced styling. ### Performance Boundaries | File Size | Status | Notes | |-----------|--------|-------| | < 50MB | ✅ Recommended | Smooth preview experience | | 50-100MB | ⚠️ May lag | UI may become unresponsive during load | | > 100MB | ❌ Not recommended | Browser memory limits may be exceeded | **Special Cases:** - **ZIP archives**: Performance depends on file count, not just size - **Office documents**: Complex files (>200 pages, heavy images) may timeout - **Code highlighting**: Files >5MB may take 3-5s to highlight ### Browser Compatibility **Minimum Requirements:** - Chrome 90+ / Edge 90+ - Firefox 88+ - Safari 14+ **Known Limitations:** - **Safari iOS**: Video autoplay requires user interaction - **Firefox**: AVIF support requires Firefox 93+ (fallback decoder included) - **Office formats**: Rendering quality varies across browsers - **EPUB**: Some CSS features unsupported in older browsers ## 🎮 API Reference ### FilePreviewModal Props | Prop | Type | Required | Description | |------|------|----------|-------------| | `files` | `PreviewFileInput[]` | ✅ | Array of files (supports File objects, file objects, or URL strings) | | `currentIndex` | `number` | ✅ | Current file index | | `isOpen` | `boolean` | ✅ | Whether the modal is open | | `customRenderers` | `CustomRenderer[]` | ❌ | Custom renderers for specific file types | | `locale` | `Locale` | ❌ | UI language (`'zh-CN'` default, `'en-US'` built-in) | | `messages` | `Partial>>` | ❌ | Custom translation overrides | | `headless` | `boolean` | ❌ | Headless mode — hides toolbar and navigation arrows | | `theme` | `Theme` | ❌ | Theme mode: `'auto' \| 'dark' \| 'light'` (default `'dark'`) | | `showDownload` | `boolean` | ❌ | Whether to show the download button (default `true`) | ### FilePreviewModal Events | Event | Payload | Description | |-------|---------|-------------| | `close` | - | Emitted when the modal should close | | `navigate` | `number` | Emitted when navigating to a different file index | ### FilePreviewEmbed Props | Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | `files` | `PreviewFileInput[]` | ✅ | - | Array of files | | `currentIndex` | `number` | ❌ | `0` | Current file index | | `customRenderers` | `CustomRenderer[]` | ❌ | - | Custom renderers | | `width` | `number \| string` | ❌ | `'100%'` | Container width | | `height` | `number \| string` | ❌ | `'100%'` | Container height | | `locale` | `Locale` | ❌ | `'zh-CN'` | UI language (`'zh-CN'` or `'en-US'`) | | `messages` | `Partial>>` | ❌ | - | Custom translation overrides | | `headless` | `boolean` | ❌ | `false` | Headless mode — hides toolbar and navigation arrows | | `theme` | `Theme` | ❌ | `'dark'` | Theme mode: `'auto' \| 'dark' \| 'light'` | | `showDownload` | `boolean` | ❌ | `true` | Whether to show the download button | ### FilePreviewEmbed Events | Event | Payload | Description | |-------|---------|-------------| | `navigate` | `number` | Emitted when navigating to a different file index | ### FilePreviewContent (advanced) Both `FilePreviewModal` and `FilePreviewEmbed` are thin wrappers around the exported lower-level `FilePreviewContent` component. Use it directly when building a fully custom wrapper: ```vue ``` ### File Type Definitions ```typescript // Supports three types of file input type PreviewFileInput = File | PreviewFileLink | string; // 1. Native File object (Browser File API) const file: File = ...; // 2. File object interface PreviewFileLink { id?: string; // Optional unique identifier name: string; // File name type: string; // MIME type url: string; // File URL (supports blob URLs and HTTP URLs) size?: number; // File size in bytes } // 3. HTTP URL string const url: string = 'https://example.com/file.pdf'; ``` ## 🧩 Custom Renderers The library supports custom renderers for handling file types not built-in. Custom renderers can optionally provide toolbar configurations and integrate with the library's architecture. ### Event-Driven Toolbar Updates Custom renderers can implement real-time toolbar updates using Vue 3's reactivity system: **Benefits:** - **Real-time updates**: Toolbar reflects state changes immediately via Vue reactivity - **Better performance**: No polling overhead, leverages Vue's efficient change detection - **Type-safe**: Full TypeScript support with proper interfaces **Implementation:** ```vue ``` **Main component usage:** ```vue ``` The main component automatically tracks reactive changes in `getToolbarGroups()` via Vue's reactivity system. No manual subscription needed. ### Renderer Lazy Loading All built-in renderers use code-splitting via `defineAsyncComponent` to minimize the main bundle size and improve initial load performance. **Architecture:** - **Registration**: Renderers register in `src/renderers/lazy.ts` using `defineAsyncComponent` wrappers - **Loading**: Each renderer is a separate chunk, loaded on-demand when needed - **Fallback**: `RendererLoading` component handles the loading state **Bundle Size Impact:** - Main entry point: gzip ≤ 60 KB (strictly enforced by CI) - Each renderer: separate async chunk - Total library: gzip ≤ 500 KB (all renderers combined) **Implementation Example:** ```ts // src/renderers/lazy.ts import { defineAsyncComponent } from 'vue'; const wrap = (loader: () => Promise) => defineAsyncComponent({ loader, loadingComponent: RendererLoading, delay: 0 }); export const CustomRenderer = wrap(() => import('./Custom/index.vue')); ``` ```vue ``` **For Custom Renderers:** If you want your custom renderer to benefit from code-splitting, use the same pattern: ```vue ``` ### i18n Integration Custom renderers can access the library's i18n system via the `useTranslator()` composable for consistent multilingual support. **Architecture:** - **Dictionary Source**: `file-preview-core/src/i18n/messages/` (zh-CN.ts, en-US.ts) - **No Hardcoding**: All user-visible text must use translation keys - **Automatic Locale Switching**: Follows the `locale` prop passed to `FilePreviewModal` **Usage in Custom Renderers:** ```vue ``` **Note on Usage:** - In `