@files-preview-app/preview-file 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +674 -674
- package/THIRD_PARTY_LICENSES.md +18 -18
- package/dist/angular.cjs +175 -15
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +175 -15
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +175 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +175 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +175 -15
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +175 -15
- package/dist/react.js.map +1 -1
- package/dist/styles.css +202 -190
- package/dist/vue.cjs +175 -15
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +175 -15
- package/dist/vue.js.map +1 -1
- package/package.json +161 -161
package/README.md
CHANGED
|
@@ -1,674 +1,674 @@
|
|
|
1
|
-
# @files-preview-app/preview-file
|
|
2
|
-
|
|
3
|
-
<p align="center">
|
|
4
|
-
<a href="https://patelsumit5192.github.io/preview-file/">
|
|
5
|
-
<img src="https://img.shields.io/badge/Live%20Demo-Explore%20Online-brightgreen?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Live Demo" />
|
|
6
|
-
</a>
|
|
7
|
-
<a href="https://www.npmjs.com/package/@files-preview-app/preview-file">
|
|
8
|
-
<img src="https://img.shields.io/npm/v/@files-preview-app/preview-file.svg?style=for-the-badge&color=blue" alt="npm version" />
|
|
9
|
-
</a>
|
|
10
|
-
<a href="https://opensource.org/licenses/MIT">
|
|
11
|
-
<img src="https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge" alt="License: MIT" />
|
|
12
|
-
</a>
|
|
13
|
-
<a href="https://github.com/patelsumit5192/preview-file">
|
|
14
|
-
<img src="https://img.shields.io/badge/GitHub-Repo-181717?style=for-the-badge&logo=github&logoColor=white" alt="GitHub" />
|
|
15
|
-
</a>
|
|
16
|
-
</p>
|
|
17
|
-
|
|
18
|
-
> **The all-in-one, 100% client-side file preview library for React, Next.js, Angular, Vue 3, Nuxt 3, and Vanilla JavaScript / TypeScript.**
|
|
19
|
-
> Preview **PDF, Word (.docx), Excel (.xlsx), PowerPoint (.pptx), CSV/TSV, ZIP Archives, Rich Markdown, 3D Models (.stl, .obj), Images, Video, Audio, and Code/Text (190+ languages)** with a built-in customizable toolbar (zoom, rotate, thumbnails, page jump, download, print). 100% free, permissive open-source, and client-side (zero cloud or server needed).
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## 🌐 Live Interactive Demo
|
|
24
|
-
|
|
25
|
-
Try the interactive demo with instant sample files directly in your browser:
|
|
26
|
-
👉 **[Launch Live Demo (GitHub Pages)](https://patelsumit5192.github.io/preview-file/)**
|
|
27
|
-
|
|
28
|
-
- Instant samples for **PDF, DOCX, XLSX, PPTX, CSV, ZIP, Markdown, 3D STL, SVG, and Code**
|
|
29
|
-
- Drag-and-drop your own files from your computer
|
|
30
|
-
- Live framework code generator (React, Angular, Vue, Vanilla)
|
|
31
|
-
- Light & Dark mode toggle
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## 📦 Installation
|
|
36
|
-
|
|
37
|
-
Install the **single all-in-one package** in your project:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
npm install @files-preview-app/preview-file
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Or using Yarn, pnpm, or Bun:
|
|
44
|
-
```bash
|
|
45
|
-
pnpm add @files-preview-app/preview-file
|
|
46
|
-
# or
|
|
47
|
-
yarn add @files-preview-app/preview-file
|
|
48
|
-
# or
|
|
49
|
-
bun add @files-preview-app/preview-file
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Import the toolbar and viewer stylesheet in your global CSS or root component:
|
|
53
|
-
```css
|
|
54
|
-
import '@files-preview-app/preview-file/styles.css';
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## 🎯 Supported Frameworks & Version Matrix
|
|
60
|
-
|
|
61
|
-
| Framework | Supported Versions | Package Entry Point | Integration Notes |
|
|
62
|
-
|---|---|---|---|
|
|
63
|
-
| **React** | `>=16.8.0` (React 17, 18, 19) | `@files-preview-app/preview-file/react` | Full Hooks, `forwardRef`, `FilePreviewHandle` |
|
|
64
|
-
| **Next.js** | 13.x, 14.x, 15.x | `@files-preview-app/preview-file/react` | App Router (`'use client'`) & Pages Router |
|
|
65
|
-
| **Angular** | `>=14.0.0` (Angular 15, 16, 17, 18, 19) | `@files-preview-app/preview-file/angular` | Standalone Component & NgModule, `@ViewChild` |
|
|
66
|
-
| **Vue 3** | `>=3.0.0` (Vue 3.2, 3.3, 3.4, 3.5+) | `@files-preview-app/preview-file/vue` | Composition API (`<script setup>`) & Options API |
|
|
67
|
-
| **Nuxt 3** | `>=3.0.0` | `@files-preview-app/preview-file/vue` | Wrapped inside `<ClientOnly>` component |
|
|
68
|
-
| **Vanilla JS / TS** | ES2020+ | `@files-preview-app/preview-file` | Pure DOM API, Vite, Webpack, Rollup, Parcel, esbuild |
|
|
69
|
-
| **Svelte / Solid** | All versions | `@files-preview-app/preview-file` | Direct DOM container attachment |
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## 🚀 Framework Integration Guides
|
|
74
|
-
|
|
75
|
-
### 1. React (`@files-preview-app/preview-file/react`)
|
|
76
|
-
|
|
77
|
-
#### Basic Usage
|
|
78
|
-
```tsx
|
|
79
|
-
import React, { useState } from 'react';
|
|
80
|
-
import { FilePreview } from '@files-preview-app/preview-file/react';
|
|
81
|
-
import '@files-preview-app/preview-file/styles.css';
|
|
82
|
-
|
|
83
|
-
export default function App() {
|
|
84
|
-
const [file, setFile] = useState<File | string>(
|
|
85
|
-
'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
<div style={{ padding: '20px' }}>
|
|
90
|
-
<input
|
|
91
|
-
type="file"
|
|
92
|
-
onChange={(e) => e.target.files?.[0] && setFile(e.target.files[0])}
|
|
93
|
-
/>
|
|
94
|
-
|
|
95
|
-
<div style={{ width: '100%', height: '750px', marginTop: '16px' }}>
|
|
96
|
-
<FilePreview
|
|
97
|
-
src={file}
|
|
98
|
-
options={{
|
|
99
|
-
theme: 'light', // 'light' | 'dark' | 'auto'
|
|
100
|
-
showToolbar: true,
|
|
101
|
-
toolbarPosition: 'top', // 'top' | 'bottom'
|
|
102
|
-
showThumbnails: false,
|
|
103
|
-
}}
|
|
104
|
-
onLoading={() => console.log('File loading started')}
|
|
105
|
-
onLoaded={(info) => console.log('Loaded successfully:', info)}
|
|
106
|
-
onError={(err) => console.error('Preview error:', err)}
|
|
107
|
-
onPageChange={(data) => console.log('Page switched:', data)}
|
|
108
|
-
onZoomChange={(data) => console.log('Zoom scale:', data)}
|
|
109
|
-
/>
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
#### Advanced React (Programmatic Controls via `ref`)
|
|
117
|
-
```tsx
|
|
118
|
-
import React, { useRef, useState } from 'react';
|
|
119
|
-
import { FilePreview, type FilePreviewHandle } from '@files-preview-app/preview-file/react';
|
|
120
|
-
import '@files-preview-app/preview-file/styles.css';
|
|
121
|
-
|
|
122
|
-
export default function AdvancedViewer() {
|
|
123
|
-
const previewRef = useRef<FilePreviewHandle>(null);
|
|
124
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
125
|
-
const [file, setFile] = useState<string>('https://example.com/contract.docx');
|
|
126
|
-
|
|
127
|
-
// Trigger instance methods programmatically
|
|
128
|
-
const handleZoomIn = () => previewRef.current?.getInstance()?.zoomIn?.();
|
|
129
|
-
const handleZoomOut = () => previewRef.current?.getInstance()?.zoomOut?.();
|
|
130
|
-
const handleRotate = () => previewRef.current?.getInstance()?.rotateCW?.();
|
|
131
|
-
const handleDownload = () => previewRef.current?.getInstance()?.download?.();
|
|
132
|
-
const handlePrint = () => previewRef.current?.getInstance()?.print?.();
|
|
133
|
-
const handleNextPage = () => {
|
|
134
|
-
const next = currentPage + 1;
|
|
135
|
-
previewRef.current?.getInstance()?.goToPage?.(next);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<div>
|
|
140
|
-
{/* Custom external controls */}
|
|
141
|
-
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
|
|
142
|
-
<button onClick={handleZoomIn}>Zoom In (+)</button>
|
|
143
|
-
<button onClick={handleZoomOut}>Zoom Out (-)</button>
|
|
144
|
-
<button onClick={handleRotate}>Rotate (90°)</button>
|
|
145
|
-
<button onClick={handleNextPage}>Next Page</button>
|
|
146
|
-
<button onClick={handleDownload}>Download File</button>
|
|
147
|
-
<button onClick={handlePrint}>Print</button>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div style={{ width: '100%', height: '800px' }}>
|
|
151
|
-
<FilePreview
|
|
152
|
-
ref={previewRef}
|
|
153
|
-
src={file}
|
|
154
|
-
options={{ theme: 'light', showToolbar: true }}
|
|
155
|
-
onPageChange={(data: any) => setCurrentPage(data.page)}
|
|
156
|
-
/>
|
|
157
|
-
</div>
|
|
158
|
-
</div>
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
### 2. Next.js (App Router & Pages Router)
|
|
166
|
-
|
|
167
|
-
Because file previews use client-side DOM and canvas APIs, disable SSR using Next.js `dynamic`:
|
|
168
|
-
|
|
169
|
-
```tsx
|
|
170
|
-
'use client';
|
|
171
|
-
|
|
172
|
-
import dynamic from 'next/dynamic';
|
|
173
|
-
import '@files-preview-app/preview-file/styles.css';
|
|
174
|
-
|
|
175
|
-
// Disable SSR for the preview component
|
|
176
|
-
const FilePreview = dynamic(
|
|
177
|
-
() => import('@files-preview-app/preview-file/react').then((mod) => mod.FilePreview),
|
|
178
|
-
{ ssr: false }
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
export default function NextPreviewPage() {
|
|
182
|
-
return (
|
|
183
|
-
<main style={{ width: '100vw', height: '100vh' }}>
|
|
184
|
-
<FilePreview
|
|
185
|
-
src="https://example.com/spreadsheet.xlsx"
|
|
186
|
-
options={{ theme: 'auto', showToolbar: true }}
|
|
187
|
-
/>
|
|
188
|
-
</main>
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
### 3. Angular (`@files-preview-app/preview-file/angular`)
|
|
196
|
-
|
|
197
|
-
#### Standalone Component (Angular 14, 15, 16, 17, 18, 19)
|
|
198
|
-
```typescript
|
|
199
|
-
import { Component, ViewChild } from '@angular/core';
|
|
200
|
-
import { CommonModule } from '@angular/common';
|
|
201
|
-
import { FilePreviewComponent } from '@files-preview-app/preview-file/angular';
|
|
202
|
-
|
|
203
|
-
@Component({
|
|
204
|
-
selector: 'app-document-viewer',
|
|
205
|
-
standalone: true,
|
|
206
|
-
imports: [CommonModule, FilePreviewComponent],
|
|
207
|
-
template: `
|
|
208
|
-
<div class="viewer-wrapper" style="width: 100%; height: 800px;">
|
|
209
|
-
<!-- File Selector -->
|
|
210
|
-
<input type="file" (change)="onFileChange($event)" />
|
|
211
|
-
|
|
212
|
-
<!-- Custom Actions -->
|
|
213
|
-
<div class="actions" style="margin: 10px 0;">
|
|
214
|
-
<button (click)="zoomIn()">Zoom In</button>
|
|
215
|
-
<button (click)="zoomOut()">Zoom Out</button>
|
|
216
|
-
<button (click)="download()">Download</button>
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
<!-- Preview Component -->
|
|
220
|
-
<fp-file-preview
|
|
221
|
-
#preview
|
|
222
|
-
[src]="selectedFile"
|
|
223
|
-
[options]="{ theme: 'light', showToolbar: true, toolbarPosition: 'top' }"
|
|
224
|
-
(loading)="onLoading()"
|
|
225
|
-
(loaded)="onLoaded($event)"
|
|
226
|
-
(error)="onError($event)"
|
|
227
|
-
(pageChange)="onPageChange($event)"
|
|
228
|
-
(zoomChange)="onZoomChange($event)"
|
|
229
|
-
/>
|
|
230
|
-
</div>
|
|
231
|
-
`,
|
|
232
|
-
styleUrls: ['@files-preview-app/preview-file/styles.css']
|
|
233
|
-
})
|
|
234
|
-
export class DocumentViewerComponent {
|
|
235
|
-
@ViewChild('preview') previewComponent!: FilePreviewComponent;
|
|
236
|
-
|
|
237
|
-
selectedFile: string | File = 'https://example.com/presentation.pptx';
|
|
238
|
-
|
|
239
|
-
onFileChange(event: Event) {
|
|
240
|
-
const input = event.target as HTMLInputElement;
|
|
241
|
-
if (input.files?.[0]) {
|
|
242
|
-
this.selectedFile = input.files[0];
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Programmatic controls
|
|
247
|
-
zoomIn() {
|
|
248
|
-
this.previewComponent.getInstance()?.zoomIn?.();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
zoomOut() {
|
|
252
|
-
this.previewComponent.getInstance()?.zoomOut?.();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
download() {
|
|
256
|
-
this.previewComponent.getInstance()?.download?.();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Event handlers
|
|
260
|
-
onLoading() {
|
|
261
|
-
console.log('Loading file...');
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
onLoaded(event: unknown) {
|
|
265
|
-
console.log('File successfully loaded:', event);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
onError(err: Error) {
|
|
269
|
-
console.error('Failed to preview file:', err);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
onPageChange(data: unknown) {
|
|
273
|
-
console.log('Page switched:', data);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
onZoomChange(data: unknown) {
|
|
277
|
-
console.log('Zoom changed:', data);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
#### Traditional NgModule (Angular 14+)
|
|
283
|
-
```typescript
|
|
284
|
-
import { NgModule } from '@angular/core';
|
|
285
|
-
import { BrowserModule } from '@angular/platform-browser';
|
|
286
|
-
import { FilePreviewComponent } from '@files-preview-app/preview-file/angular';
|
|
287
|
-
import { AppComponent } from './app.component';
|
|
288
|
-
|
|
289
|
-
@NgModule({
|
|
290
|
-
declarations: [AppComponent],
|
|
291
|
-
imports: [BrowserModule, FilePreviewComponent],
|
|
292
|
-
bootstrap: [AppComponent]
|
|
293
|
-
})
|
|
294
|
-
export class AppModule {}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
### 4. Vue 3 (`@files-preview-app/preview-file/vue`)
|
|
300
|
-
|
|
301
|
-
#### Composition API (`<script setup>`)
|
|
302
|
-
```vue
|
|
303
|
-
<template>
|
|
304
|
-
<div class="preview-container" style="width: 100%; height: 800px;">
|
|
305
|
-
<!-- Controls Bar -->
|
|
306
|
-
<div class="toolbar-actions" style="margin-bottom: 12px; display: flex; gap: 8px;">
|
|
307
|
-
<input type="file" @change="handleFileSelect" />
|
|
308
|
-
<button @click="zoomIn">Zoom In (+)</button>
|
|
309
|
-
<button @click="zoomOut">Zoom Out (-)</button>
|
|
310
|
-
<button @click="rotate">Rotate (90°)</button>
|
|
311
|
-
<button @click="download">Download</button>
|
|
312
|
-
</div>
|
|
313
|
-
|
|
314
|
-
<!-- Universal Preview Component -->
|
|
315
|
-
<FilePreview
|
|
316
|
-
ref="previewRef"
|
|
317
|
-
:src="fileSource"
|
|
318
|
-
:options="{
|
|
319
|
-
theme: 'light',
|
|
320
|
-
showToolbar: true,
|
|
321
|
-
toolbarPosition: 'top'
|
|
322
|
-
}"
|
|
323
|
-
@loading="onLoading"
|
|
324
|
-
@loaded="onLoaded"
|
|
325
|
-
@error="onError"
|
|
326
|
-
@page-change="onPageChange"
|
|
327
|
-
@zoom-change="onZoomChange"
|
|
328
|
-
/>
|
|
329
|
-
</div>
|
|
330
|
-
</template>
|
|
331
|
-
|
|
332
|
-
<script setup lang="ts">
|
|
333
|
-
import { ref } from 'vue';
|
|
334
|
-
import { FilePreview } from '@files-preview-app/preview-file/vue';
|
|
335
|
-
import '@files-preview-app/preview-file/styles.css';
|
|
336
|
-
|
|
337
|
-
const previewRef = ref<InstanceType<typeof FilePreview> | null>(null);
|
|
338
|
-
const fileSource = ref<string | File>('https://example.com/archive.zip');
|
|
339
|
-
|
|
340
|
-
function handleFileSelect(e: Event) {
|
|
341
|
-
const target = e.target as HTMLInputElement;
|
|
342
|
-
if (target.files?.[0]) {
|
|
343
|
-
fileSource.value = target.files[0];
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Programmatic methods
|
|
348
|
-
function zoomIn() {
|
|
349
|
-
previewRef.value?.getInstance()?.zoomIn?.();
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function zoomOut() {
|
|
353
|
-
previewRef.value?.getInstance()?.zoomOut?.();
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function rotate() {
|
|
357
|
-
previewRef.value?.getInstance()?.rotateCW?.();
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function download() {
|
|
361
|
-
previewRef.value?.getInstance()?.download?.();
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Event callbacks
|
|
365
|
-
function onLoading() {
|
|
366
|
-
console.log('Rendering file...');
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function onLoaded(metadata: unknown) {
|
|
370
|
-
console.log('Preview ready:', metadata);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function onError(err: unknown) {
|
|
374
|
-
console.error('Preview error:', err);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function onPageChange(pageData: unknown) {
|
|
378
|
-
console.log('Page switched:', pageData);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function onZoomChange(zoomData: unknown) {
|
|
382
|
-
console.log('Zoom changed:', zoomData);
|
|
383
|
-
}
|
|
384
|
-
</script>
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
#### Nuxt 3 Integration
|
|
388
|
-
Wrap inside `<ClientOnly>` to avoid server-side rendering:
|
|
389
|
-
```vue
|
|
390
|
-
<template>
|
|
391
|
-
<ClientOnly>
|
|
392
|
-
<div style="height: 800px;">
|
|
393
|
-
<FilePreview src="/documents/sample.pdf" />
|
|
394
|
-
</div>
|
|
395
|
-
<template #fallback>
|
|
396
|
-
<div>Loading preview component...</div>
|
|
397
|
-
</template>
|
|
398
|
-
</ClientOnly>
|
|
399
|
-
</template>
|
|
400
|
-
|
|
401
|
-
<script setup lang="ts">
|
|
402
|
-
import { FilePreview } from '@files-preview-app/preview-file/vue';
|
|
403
|
-
import '@files-preview-app/preview-file/styles.css';
|
|
404
|
-
</script>
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
---
|
|
408
|
-
|
|
409
|
-
### 5. Vanilla JavaScript / TypeScript (`@files-preview-app/preview-file`)
|
|
410
|
-
|
|
411
|
-
Use directly with any build tool (Vite, Webpack, Rollup) or via `<script type="module">`:
|
|
412
|
-
|
|
413
|
-
```html
|
|
414
|
-
<!DOCTYPE html>
|
|
415
|
-
<html lang="en">
|
|
416
|
-
<head>
|
|
417
|
-
<meta charset="UTF-8" />
|
|
418
|
-
<title>Universal File Preview</title>
|
|
419
|
-
<!-- Link Stylesheet -->
|
|
420
|
-
<link rel="stylesheet" href="node_modules/@files-preview-app/preview-file/dist/styles.css" />
|
|
421
|
-
<style>
|
|
422
|
-
#viewer-container {
|
|
423
|
-
width: 100%;
|
|
424
|
-
height: 850px;
|
|
425
|
-
border: 1px solid #e2e8f0;
|
|
426
|
-
border-radius: 8px;
|
|
427
|
-
}
|
|
428
|
-
</style>
|
|
429
|
-
</head>
|
|
430
|
-
<body>
|
|
431
|
-
<div style="margin-bottom: 12px; display: flex; gap: 8px;">
|
|
432
|
-
<input type="file" id="file-picker" />
|
|
433
|
-
<button id="btn-zoom-in">Zoom In</button>
|
|
434
|
-
<button id="btn-zoom-out">Zoom Out</button>
|
|
435
|
-
<button id="btn-download">Download</button>
|
|
436
|
-
</div>
|
|
437
|
-
|
|
438
|
-
<div id="viewer-container"></div>
|
|
439
|
-
|
|
440
|
-
<script type="module">
|
|
441
|
-
import { FilePreviewViewer } from './node_modules/@files-preview-app/preview-file/dist/index.js';
|
|
442
|
-
|
|
443
|
-
const container = document.getElementById('viewer-container');
|
|
444
|
-
const filePicker = document.getElementById('file-picker');
|
|
445
|
-
|
|
446
|
-
// 1. Instantiate viewer
|
|
447
|
-
const viewer = new FilePreviewViewer();
|
|
448
|
-
|
|
449
|
-
// 2. Listen to lifecycle events
|
|
450
|
-
viewer.on('loading', () => console.log('File loading started'));
|
|
451
|
-
viewer.on('loaded', (info) => console.log('File loaded:', info));
|
|
452
|
-
viewer.on('error', (err) => console.error('Preview error:', err));
|
|
453
|
-
viewer.on('page-change', (data) => console.log('Page switched:', data));
|
|
454
|
-
|
|
455
|
-
// 3. Render initial file
|
|
456
|
-
let instance = await viewer.preview(
|
|
457
|
-
container,
|
|
458
|
-
'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf',
|
|
459
|
-
{
|
|
460
|
-
theme: 'light',
|
|
461
|
-
showToolbar: true,
|
|
462
|
-
toolbarPosition: 'top'
|
|
463
|
-
}
|
|
464
|
-
);
|
|
465
|
-
|
|
466
|
-
// 4. Handle file selection from local disk
|
|
467
|
-
filePicker.addEventListener('change', async (e) => {
|
|
468
|
-
const file = e.target.files[0];
|
|
469
|
-
if (file) {
|
|
470
|
-
instance = await viewer.preview(container, file, { theme: 'light' });
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
// 5. Connect custom buttons to instance methods
|
|
475
|
-
document.getElementById('btn-zoom-in').addEventListener('click', () => instance?.zoomIn?.());
|
|
476
|
-
document.getElementById('btn-zoom-out').addEventListener('click', () => instance?.zoomOut?.());
|
|
477
|
-
document.getElementById('btn-download').addEventListener('click', () => instance?.download?.());
|
|
478
|
-
</script>
|
|
479
|
-
</body>
|
|
480
|
-
</html>
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
---
|
|
484
|
-
|
|
485
|
-
## 🎛️ Complete Methods Reference
|
|
486
|
-
|
|
487
|
-
### 1. `FilePreviewViewer` (Viewer Class Methods)
|
|
488
|
-
|
|
489
|
-
| Method | Parameters | Returns | Description |
|
|
490
|
-
|---|---|---|---|
|
|
491
|
-
| `preview()` | `container: HTMLElement`, `source: FileSource`, `options?: PreviewViewerOptions` | `Promise<PreviewInstance>` | Renders any supported file into the target DOM element. Cleans up previous renders automatically. |
|
|
492
|
-
| `getInstance()` | None | `PreviewInstance \| null` | Returns the active preview instance, exposing zoom, navigation, export, and rotation methods. |
|
|
493
|
-
| `on()` | `event: string`, `handler: (data: any) => void` | `Unsubscribe: () => void` | Subscribes to lifecycle events. Returns an unsubscribe cleanup function. |
|
|
494
|
-
| `registerPlugin()` | `plugin: PreviewPlugin` | `this` | Registers a custom renderer plugin. |
|
|
495
|
-
| `registerPlugins()` | `plugins: PreviewPlugin[]` | `this` | Registers multiple renderer plugins at once. |
|
|
496
|
-
| `destroy()` | None | `void` | Destroys the active instance, removes toolbar DOM, cancels network abort controllers, and clears listeners. |
|
|
497
|
-
|
|
498
|
-
---
|
|
499
|
-
|
|
500
|
-
### 2. `PreviewInstance` (Active Document Instance Methods)
|
|
501
|
-
|
|
502
|
-
Retrieved via `viewer.getInstance()` or `previewRef.current.getInstance()`.
|
|
503
|
-
|
|
504
|
-
| Category | Method | Return Type | Description | Example Usage |
|
|
505
|
-
|---|---|---|---|---|
|
|
506
|
-
| **Zoom** | `zoomIn()` | `void` | Increments zoom level by 20% | `instance.zoomIn()` |
|
|
507
|
-
| **Zoom** | `zoomOut()` | `void` | Decrements zoom level by 20% | `instance.zoomOut()` |
|
|
508
|
-
| **Zoom** | `setZoom(level)` | `void` | Sets absolute zoom scale (e.g. `1.5` = 150%) | `instance.setZoom(1.5)` |
|
|
509
|
-
| **Zoom** | `getZoom()` | `number` | Gets current zoom scale number | `const z = instance.getZoom()` |
|
|
510
|
-
| **Zoom** | `fitToPage()` | `void` | Resets zoom to fit container viewport | `instance.fitToPage()` |
|
|
511
|
-
| **Pagination** | `goToPage(page)` | `void` | Jumps to specific page, sheet, or slide (1-indexed) | `instance.goToPage(3)` |
|
|
512
|
-
| **Pagination** | `getPageCount()` | `number` | Returns total page, sheet, or slide count | `const total = instance.getPageCount()` |
|
|
513
|
-
| **Pagination** | `getCurrentPage()` | `number` | Returns current 1-indexed page or sheet | `const cur = instance.getCurrentPage()` |
|
|
514
|
-
| **Rotation** | `rotateCW()` | `void` | Rotates document, image, or video 90° clockwise | `instance.rotateCW()` |
|
|
515
|
-
| **Rotation** | `rotateCCW()` | `void` | Rotates 90° counter-clockwise | `instance.rotateCCW()` |
|
|
516
|
-
| **Rotation** | `getRotation()` | `number` | Returns rotation angle in degrees (0, 90, 180, 270) | `const deg = instance.getRotation()` |
|
|
517
|
-
| **Media** | `play()` | `void` | Starts video or audio playback | `instance.play()` |
|
|
518
|
-
| **Media** | `pause()` | `void` | Pauses video or audio playback | `instance.pause()` |
|
|
519
|
-
| **Media** | `isPlaying()` | `boolean` | Checks if media is currently playing | `if (instance.isPlaying()) ...` |
|
|
520
|
-
| **Thumbnails** | `getThumbnails()` | `Thumbnail[]` | Returns list of thumbnails for sidebar | `const thumbs = instance.getThumbnails()` |
|
|
521
|
-
| **Thumbnails** | `toggleThumbnails()`| `void` | Toggles the page thumbnails sidebar panel | `instance.toggleThumbnails()` |
|
|
522
|
-
| **Export** | `download()` | `void` | Downloads original file with proper name & MIME | `instance.download()` |
|
|
523
|
-
| **Export** | `print()` | `void` | Opens browser print dialog formatted for clean output | `instance.print()` |
|
|
524
|
-
| **Lifecycle** | `destroy()` | `void` | Releases memory, cancels rendering, revokes blob URLs | `instance.destroy()` |
|
|
525
|
-
|
|
526
|
-
---
|
|
527
|
-
|
|
528
|
-
## 📡 Complete Events Reference
|
|
529
|
-
|
|
530
|
-
All events can be listened to via framework bindings (`onLoaded`, `(loaded)`, `@loaded`) or `viewer.on('event', handler)`:
|
|
531
|
-
|
|
532
|
-
| Event Name | Framework Prop / Event | Payload Type | Description |
|
|
533
|
-
|---|---|---|---|
|
|
534
|
-
| `'loading'` | `onLoading` / `(loading)` / `@loading` | `{ source: FileSource }` | Emitted immediately when file parsing and decoding starts. |
|
|
535
|
-
| `'loaded'` | `onLoaded` / `(loaded)` / `@loaded` | `{ metadata: FileMetadata, plugin: string }` | Emitted when file rendering completes successfully. Contains detected metadata. |
|
|
536
|
-
| `'error'` | `onError` / `(error)` / `@error` | `Error` | Emitted if file download, decoding, or rendering fails. |
|
|
537
|
-
| `'page-change'` | `onPageChange` / `(pageChange)` / `@page-change` | `{ page: number, totalPages?: number }` | Emitted when user navigates to another page, Excel sheet, or PPT slide. |
|
|
538
|
-
| `'zoom-change'` | `onZoomChange` / `(zoomChange)` / `@zoom-change` | `{ zoom: number }` | Emitted whenever zoom level changes. |
|
|
539
|
-
| `'rotate'` | `onRotate` / `(rotate)` / `@rotate` | `{ rotation: number }` | Emitted when orientation rotates (0°, 90°, 180°, 270°). |
|
|
540
|
-
| `'destroy'` | `onDestroy` / `(destroy)` / `@destroy` | `null` | Emitted when viewer is cleaned up. |
|
|
541
|
-
|
|
542
|
-
### Practical Event Examples
|
|
543
|
-
|
|
544
|
-
#### 1. Show File Metadata Badge on Loaded
|
|
545
|
-
```typescript
|
|
546
|
-
viewer.on('loaded', ({ metadata, plugin }) => {
|
|
547
|
-
console.log('File Name:', metadata.name);
|
|
548
|
-
console.log('File Size:', (metadata.size / 1024).toFixed(1) + ' KB');
|
|
549
|
-
console.log('Detected MIME:', metadata.mimeType);
|
|
550
|
-
console.log('Renderer Plugin:', plugin);
|
|
551
|
-
});
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
#### 2. Display Custom Error Toast Notification
|
|
555
|
-
```typescript
|
|
556
|
-
viewer.on('error', (err) => {
|
|
557
|
-
showToastNotification(`Cannot open file: ${err.message}`, { type: 'error' });
|
|
558
|
-
});
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
#### 3. Synchronize External Page Counter
|
|
562
|
-
```typescript
|
|
563
|
-
viewer.on('page-change', ({ page, totalPages }) => {
|
|
564
|
-
pageIndicatorEl.innerText = `Page ${page} of ${totalPages || '?'}`;
|
|
565
|
-
});
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
---
|
|
569
|
-
|
|
570
|
-
## ⚙️ Complete Properties & Options Reference
|
|
571
|
-
|
|
572
|
-
### 1. `src` Property (Accepts 5 Source Formats)
|
|
573
|
-
|
|
574
|
-
The `src` prop accepts any of the following types:
|
|
575
|
-
|
|
576
|
-
| Format | Type | Example |
|
|
577
|
-
|---|---|---|
|
|
578
|
-
| **Local File** | `File` | From `<input type="file">` event: `e.target.files[0]` |
|
|
579
|
-
| **URL String** | `string` | Remote or local URL: `'https://example.com/file.pdf'` |
|
|
580
|
-
| **Blob** | `Blob` | `new Blob([binaryData], { type: 'application/pdf' })` |
|
|
581
|
-
| **ArrayBuffer** | `ArrayBuffer` | Direct binary buffer: `await response.arrayBuffer()` |
|
|
582
|
-
| **TypedArray** | `Uint8Array` | Byte array: `new Uint8Array(buffer)` |
|
|
583
|
-
| **Base64 URI** | `string` | Data URI: `'data:image/png;base64,iVBORw0...'` |
|
|
584
|
-
|
|
585
|
-
---
|
|
586
|
-
|
|
587
|
-
### 2. `options` Object Reference
|
|
588
|
-
|
|
589
|
-
Passed to `options` prop in React/Angular/Vue or third argument to `viewer.preview(container, src, options)`:
|
|
590
|
-
|
|
591
|
-
| Option Property | Type | Default | Description |
|
|
592
|
-
|---|---|---|---|
|
|
593
|
-
| `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` | UI theme. `'auto'` adapts to system dark mode preferences. |
|
|
594
|
-
| `showToolbar` | `boolean` | `true` | Set `false` to hide built-in toolbar (e.g. when using your own custom buttons). |
|
|
595
|
-
| `toolbarPosition` | `'top' \| 'bottom'` | `'top'` | Positions toolbar at the top or bottom of the viewer container. |
|
|
596
|
-
| `showThumbnails` | `boolean` | `false` | Opens page thumbnails sidebar panel automatically on load. |
|
|
597
|
-
| `className` | `string` | `''` | Custom CSS class attached to the root viewer container element. |
|
|
598
|
-
| `zoom` | `number` | `1.0` | Initial zoom multiplier (`1.0` = 100%, `1.5` = 150%). |
|
|
599
|
-
| `page` | `number` | `1` | Initial page, slide, or sheet number to display on load (1-based). |
|
|
600
|
-
| `locale` | `string` | `'en'` | UI label language localization. |
|
|
601
|
-
| `pluginOptions` | `Record<string, unknown>` | `{}` | Custom options passed directly to underlying format renderer plugins. |
|
|
602
|
-
|
|
603
|
-
---
|
|
604
|
-
|
|
605
|
-
## 🎨 CSS Variables (Theming & Custom Styling)
|
|
606
|
-
|
|
607
|
-
Customize colors, borders, and typography using standard CSS custom properties:
|
|
608
|
-
|
|
609
|
-
```css
|
|
610
|
-
/* Custom Brand Theme */
|
|
611
|
-
.fp-viewer {
|
|
612
|
-
--fp-bg: #ffffff; /* Viewer background */
|
|
613
|
-
--fp-toolbar-bg: #f8fafc; /* Toolbar background */
|
|
614
|
-
--fp-border: #e2e8f0; /* Borders and dividers */
|
|
615
|
-
--fp-text: #0f172a; /* Text color */
|
|
616
|
-
--fp-primary: #3b82f6; /* Active buttons and highlights */
|
|
617
|
-
--fp-btn-hover: #f1f5f9; /* Toolbar button hover color */
|
|
618
|
-
--fp-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
/* Dark Theme Overrides */
|
|
622
|
-
.fp-theme-dark {
|
|
623
|
-
--fp-bg: #0f172a;
|
|
624
|
-
--fp-toolbar-bg: #1e293b;
|
|
625
|
-
--fp-border: #334155;
|
|
626
|
-
--fp-text: #f8fafc;
|
|
627
|
-
--fp-primary: #60a5fa;
|
|
628
|
-
--fp-btn-hover: #334155;
|
|
629
|
-
}
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
---
|
|
633
|
-
|
|
634
|
-
## 📂 Supported Formats Matrix (All 10 Categories)
|
|
635
|
-
|
|
636
|
-
Every file format is rendered 100% in the browser using permissive open-source engines:
|
|
637
|
-
|
|
638
|
-
| Category | File Extensions | Engine | License | Supported Features |
|
|
639
|
-
|---|---|---|---|---|
|
|
640
|
-
| **PDF** | `.pdf` | PDF.js (`pdfjs-dist`) | Apache-2.0 | Multi-page canvas rendering, Zoom In/Out, Fit to page, Rotate CW/CCW, Page jump, Thumbnails sidebar, Print, Download |
|
|
641
|
-
| **Word Document** | `.docx` | `docx-preview` | Apache-2.0 | Preserves styles, tables, bullets, images, fonts, Zoom In/Out, Fit to page, Print, Download |
|
|
642
|
-
| **Excel Spreadsheet** | `.xlsx`, `.xls` | `exceljs` | MIT | Multi-sheet tab bar, styled grid cells, borders, formatting, Zoom, Print, Download |
|
|
643
|
-
| **PowerPoint** | `.pptx`, `.ppsx` | `pptx-browser` | MIT | Slide-by-slide canvas rendering, slide thumbnails sidebar, navigation jump, Zoom, Fit to slide, Print, Download |
|
|
644
|
-
| **CSV / TSV Data** | `.csv`, `.tsv` | `papaparse` | MIT | Auto-detects comma/tab delimiter, tabular grid with header styling, Zoom, Print, Download |
|
|
645
|
-
| **ZIP Archives** | `.zip` | `fflate` | MIT | Hierarchical file tree/table explorer, compression stats, instant search filter, single-file extract/download, download ZIP |
|
|
646
|
-
| **Rich Markdown** | `.md`, `.markdown` | `marked` + `dompurify` | MIT / Apache-2.0 | GitHub Flavored Markdown (tables, checklists, blockquotes), syntax-highlighted code blocks, XSS sanitized, font zoom, Print, Download |
|
|
647
|
-
| **3D Models** | `.stl`, `.obj` | `three` (Three.js) | MIT | 360° mouse orbit controls, perspective camera, ambient & directional lighting, wireframe vs solid toggle, reset view, Download |
|
|
648
|
-
| **Images & Vector** | `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.bmp`, `.svg`, `.ico`, `.tiff` | Native + `@panzoom/panzoom` + `dompurify` | MIT / Apache-2.0 | Smooth pan & zoom, rotate 90°, SVG DOM sanitization, Print, Download |
|
|
649
|
-
| **Video & Audio** | `.mp4`, `.webm`, `.ogg`, `.mov`, `.mp3`, `.wav`, `.flac`, `.aac` | Native HTML5 Media | MIT | Play/Pause, seek bar, volume control, video rotate, fullscreen, Download |
|
|
650
|
-
| **Code & Text** | `.js`, `.ts`, `.jsx`, `.tsx`, `.html`, `.css`, `.json`, `.xml`, `.yaml`, `.py`, `.java`, `.cpp`, `.sql`, `.sh`, etc. (190+ languages) | `highlight.js` | BSD-3-Clause | Syntax highlighting, line numbers gutter, font zoom in/out, Print, Download |
|
|
651
|
-
|
|
652
|
-
---
|
|
653
|
-
|
|
654
|
-
## 🛡️ Security & Privacy Guarantee
|
|
655
|
-
|
|
656
|
-
- 🔒 **100% Client-Side**: Files never leave the user's browser. No documents are uploaded to third-party clouds or external rendering servers.
|
|
657
|
-
- 🛡️ **XSS Protection**: All HTML, Markdown, and SVG inputs are strictly sanitized with `DOMPurify`.
|
|
658
|
-
- 🆓 **100% Permissive Open-Source**: All libraries used are audited under **MIT**, **Apache-2.0**, or **BSD-3-Clause**. No GPL, AGPL, copyleft claims, or paid commercial subscriptions. See [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md).
|
|
659
|
-
|
|
660
|
-
---
|
|
661
|
-
|
|
662
|
-
## 👨💻 Author & Community
|
|
663
|
-
|
|
664
|
-
**Sumit Patel**
|
|
665
|
-
- 🌐 GitHub: [@patelsumit5192](https://github.com/patelsumit5192)
|
|
666
|
-
- 📦 NPM: [patel.sumit51](https://www.npmjs.com/~patel.sumit51)
|
|
667
|
-
- 💻 Repository: [https://github.com/patelsumit5192/preview-file](https://github.com/patelsumit5192/preview-file)
|
|
668
|
-
- 🚀 Live Demo: [https://patelsumit5192.github.io/preview-file/](https://patelsumit5192.github.io/preview-file/)
|
|
669
|
-
|
|
670
|
-
---
|
|
671
|
-
|
|
672
|
-
## 📄 License
|
|
673
|
-
|
|
674
|
-
MIT © 2026 Sumit Patel
|
|
1
|
+
# @files-preview-app/preview-file
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://patelsumit5192.github.io/preview-file/">
|
|
5
|
+
<img src="https://img.shields.io/badge/Live%20Demo-Explore%20Online-brightgreen?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Live Demo" />
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/@files-preview-app/preview-file">
|
|
8
|
+
<img src="https://img.shields.io/npm/v/@files-preview-app/preview-file.svg?style=for-the-badge&color=blue" alt="npm version" />
|
|
9
|
+
</a>
|
|
10
|
+
<a href="https://opensource.org/licenses/MIT">
|
|
11
|
+
<img src="https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge" alt="License: MIT" />
|
|
12
|
+
</a>
|
|
13
|
+
<a href="https://github.com/patelsumit5192/preview-file">
|
|
14
|
+
<img src="https://img.shields.io/badge/GitHub-Repo-181717?style=for-the-badge&logo=github&logoColor=white" alt="GitHub" />
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
> **The all-in-one, 100% client-side file preview library for React, Next.js, Angular, Vue 3, Nuxt 3, and Vanilla JavaScript / TypeScript.**
|
|
19
|
+
> Preview **PDF, Word (.docx), Excel (.xlsx), PowerPoint (.pptx), CSV/TSV, ZIP Archives, Rich Markdown, 3D Models (.stl, .obj), Images, Video, Audio, and Code/Text (190+ languages)** with a built-in customizable toolbar (zoom, rotate, thumbnails, page jump, download, print). 100% free, permissive open-source, and client-side (zero cloud or server needed).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🌐 Live Interactive Demo
|
|
24
|
+
|
|
25
|
+
Try the interactive demo with instant sample files directly in your browser:
|
|
26
|
+
👉 **[Launch Live Demo (GitHub Pages)](https://patelsumit5192.github.io/preview-file/)**
|
|
27
|
+
|
|
28
|
+
- Instant samples for **PDF, DOCX, XLSX, PPTX, CSV, ZIP, Markdown, 3D STL, SVG, and Code**
|
|
29
|
+
- Drag-and-drop your own files from your computer
|
|
30
|
+
- Live framework code generator (React, Angular, Vue, Vanilla)
|
|
31
|
+
- Light & Dark mode toggle
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 📦 Installation
|
|
36
|
+
|
|
37
|
+
Install the **single all-in-one package** in your project:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @files-preview-app/preview-file
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or using Yarn, pnpm, or Bun:
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add @files-preview-app/preview-file
|
|
46
|
+
# or
|
|
47
|
+
yarn add @files-preview-app/preview-file
|
|
48
|
+
# or
|
|
49
|
+
bun add @files-preview-app/preview-file
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Import the toolbar and viewer stylesheet in your global CSS or root component:
|
|
53
|
+
```css
|
|
54
|
+
import '@files-preview-app/preview-file/styles.css';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 🎯 Supported Frameworks & Version Matrix
|
|
60
|
+
|
|
61
|
+
| Framework | Supported Versions | Package Entry Point | Integration Notes |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| **React** | `>=16.8.0` (React 17, 18, 19) | `@files-preview-app/preview-file/react` | Full Hooks, `forwardRef`, `FilePreviewHandle` |
|
|
64
|
+
| **Next.js** | 13.x, 14.x, 15.x | `@files-preview-app/preview-file/react` | App Router (`'use client'`) & Pages Router |
|
|
65
|
+
| **Angular** | `>=14.0.0` (Angular 15, 16, 17, 18, 19) | `@files-preview-app/preview-file/angular` | Standalone Component & NgModule, `@ViewChild` |
|
|
66
|
+
| **Vue 3** | `>=3.0.0` (Vue 3.2, 3.3, 3.4, 3.5+) | `@files-preview-app/preview-file/vue` | Composition API (`<script setup>`) & Options API |
|
|
67
|
+
| **Nuxt 3** | `>=3.0.0` | `@files-preview-app/preview-file/vue` | Wrapped inside `<ClientOnly>` component |
|
|
68
|
+
| **Vanilla JS / TS** | ES2020+ | `@files-preview-app/preview-file` | Pure DOM API, Vite, Webpack, Rollup, Parcel, esbuild |
|
|
69
|
+
| **Svelte / Solid** | All versions | `@files-preview-app/preview-file` | Direct DOM container attachment |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🚀 Framework Integration Guides
|
|
74
|
+
|
|
75
|
+
### 1. React (`@files-preview-app/preview-file/react`)
|
|
76
|
+
|
|
77
|
+
#### Basic Usage
|
|
78
|
+
```tsx
|
|
79
|
+
import React, { useState } from 'react';
|
|
80
|
+
import { FilePreview } from '@files-preview-app/preview-file/react';
|
|
81
|
+
import '@files-preview-app/preview-file/styles.css';
|
|
82
|
+
|
|
83
|
+
export default function App() {
|
|
84
|
+
const [file, setFile] = useState<File | string>(
|
|
85
|
+
'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div style={{ padding: '20px' }}>
|
|
90
|
+
<input
|
|
91
|
+
type="file"
|
|
92
|
+
onChange={(e) => e.target.files?.[0] && setFile(e.target.files[0])}
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<div style={{ width: '100%', height: '750px', marginTop: '16px' }}>
|
|
96
|
+
<FilePreview
|
|
97
|
+
src={file}
|
|
98
|
+
options={{
|
|
99
|
+
theme: 'light', // 'light' | 'dark' | 'auto'
|
|
100
|
+
showToolbar: true,
|
|
101
|
+
toolbarPosition: 'top', // 'top' | 'bottom'
|
|
102
|
+
showThumbnails: false,
|
|
103
|
+
}}
|
|
104
|
+
onLoading={() => console.log('File loading started')}
|
|
105
|
+
onLoaded={(info) => console.log('Loaded successfully:', info)}
|
|
106
|
+
onError={(err) => console.error('Preview error:', err)}
|
|
107
|
+
onPageChange={(data) => console.log('Page switched:', data)}
|
|
108
|
+
onZoomChange={(data) => console.log('Zoom scale:', data)}
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Advanced React (Programmatic Controls via `ref`)
|
|
117
|
+
```tsx
|
|
118
|
+
import React, { useRef, useState } from 'react';
|
|
119
|
+
import { FilePreview, type FilePreviewHandle } from '@files-preview-app/preview-file/react';
|
|
120
|
+
import '@files-preview-app/preview-file/styles.css';
|
|
121
|
+
|
|
122
|
+
export default function AdvancedViewer() {
|
|
123
|
+
const previewRef = useRef<FilePreviewHandle>(null);
|
|
124
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
125
|
+
const [file, setFile] = useState<string>('https://example.com/contract.docx');
|
|
126
|
+
|
|
127
|
+
// Trigger instance methods programmatically
|
|
128
|
+
const handleZoomIn = () => previewRef.current?.getInstance()?.zoomIn?.();
|
|
129
|
+
const handleZoomOut = () => previewRef.current?.getInstance()?.zoomOut?.();
|
|
130
|
+
const handleRotate = () => previewRef.current?.getInstance()?.rotateCW?.();
|
|
131
|
+
const handleDownload = () => previewRef.current?.getInstance()?.download?.();
|
|
132
|
+
const handlePrint = () => previewRef.current?.getInstance()?.print?.();
|
|
133
|
+
const handleNextPage = () => {
|
|
134
|
+
const next = currentPage + 1;
|
|
135
|
+
previewRef.current?.getInstance()?.goToPage?.(next);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div>
|
|
140
|
+
{/* Custom external controls */}
|
|
141
|
+
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
|
|
142
|
+
<button onClick={handleZoomIn}>Zoom In (+)</button>
|
|
143
|
+
<button onClick={handleZoomOut}>Zoom Out (-)</button>
|
|
144
|
+
<button onClick={handleRotate}>Rotate (90°)</button>
|
|
145
|
+
<button onClick={handleNextPage}>Next Page</button>
|
|
146
|
+
<button onClick={handleDownload}>Download File</button>
|
|
147
|
+
<button onClick={handlePrint}>Print</button>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div style={{ width: '100%', height: '800px' }}>
|
|
151
|
+
<FilePreview
|
|
152
|
+
ref={previewRef}
|
|
153
|
+
src={file}
|
|
154
|
+
options={{ theme: 'light', showToolbar: true }}
|
|
155
|
+
onPageChange={(data: any) => setCurrentPage(data.page)}
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### 2. Next.js (App Router & Pages Router)
|
|
166
|
+
|
|
167
|
+
Because file previews use client-side DOM and canvas APIs, disable SSR using Next.js `dynamic`:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
'use client';
|
|
171
|
+
|
|
172
|
+
import dynamic from 'next/dynamic';
|
|
173
|
+
import '@files-preview-app/preview-file/styles.css';
|
|
174
|
+
|
|
175
|
+
// Disable SSR for the preview component
|
|
176
|
+
const FilePreview = dynamic(
|
|
177
|
+
() => import('@files-preview-app/preview-file/react').then((mod) => mod.FilePreview),
|
|
178
|
+
{ ssr: false }
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
export default function NextPreviewPage() {
|
|
182
|
+
return (
|
|
183
|
+
<main style={{ width: '100vw', height: '100vh' }}>
|
|
184
|
+
<FilePreview
|
|
185
|
+
src="https://example.com/spreadsheet.xlsx"
|
|
186
|
+
options={{ theme: 'auto', showToolbar: true }}
|
|
187
|
+
/>
|
|
188
|
+
</main>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### 3. Angular (`@files-preview-app/preview-file/angular`)
|
|
196
|
+
|
|
197
|
+
#### Standalone Component (Angular 14, 15, 16, 17, 18, 19)
|
|
198
|
+
```typescript
|
|
199
|
+
import { Component, ViewChild } from '@angular/core';
|
|
200
|
+
import { CommonModule } from '@angular/common';
|
|
201
|
+
import { FilePreviewComponent } from '@files-preview-app/preview-file/angular';
|
|
202
|
+
|
|
203
|
+
@Component({
|
|
204
|
+
selector: 'app-document-viewer',
|
|
205
|
+
standalone: true,
|
|
206
|
+
imports: [CommonModule, FilePreviewComponent],
|
|
207
|
+
template: `
|
|
208
|
+
<div class="viewer-wrapper" style="width: 100%; height: 800px;">
|
|
209
|
+
<!-- File Selector -->
|
|
210
|
+
<input type="file" (change)="onFileChange($event)" />
|
|
211
|
+
|
|
212
|
+
<!-- Custom Actions -->
|
|
213
|
+
<div class="actions" style="margin: 10px 0;">
|
|
214
|
+
<button (click)="zoomIn()">Zoom In</button>
|
|
215
|
+
<button (click)="zoomOut()">Zoom Out</button>
|
|
216
|
+
<button (click)="download()">Download</button>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<!-- Preview Component -->
|
|
220
|
+
<fp-file-preview
|
|
221
|
+
#preview
|
|
222
|
+
[src]="selectedFile"
|
|
223
|
+
[options]="{ theme: 'light', showToolbar: true, toolbarPosition: 'top' }"
|
|
224
|
+
(loading)="onLoading()"
|
|
225
|
+
(loaded)="onLoaded($event)"
|
|
226
|
+
(error)="onError($event)"
|
|
227
|
+
(pageChange)="onPageChange($event)"
|
|
228
|
+
(zoomChange)="onZoomChange($event)"
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
`,
|
|
232
|
+
styleUrls: ['@files-preview-app/preview-file/styles.css']
|
|
233
|
+
})
|
|
234
|
+
export class DocumentViewerComponent {
|
|
235
|
+
@ViewChild('preview') previewComponent!: FilePreviewComponent;
|
|
236
|
+
|
|
237
|
+
selectedFile: string | File = 'https://example.com/presentation.pptx';
|
|
238
|
+
|
|
239
|
+
onFileChange(event: Event) {
|
|
240
|
+
const input = event.target as HTMLInputElement;
|
|
241
|
+
if (input.files?.[0]) {
|
|
242
|
+
this.selectedFile = input.files[0];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Programmatic controls
|
|
247
|
+
zoomIn() {
|
|
248
|
+
this.previewComponent.getInstance()?.zoomIn?.();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
zoomOut() {
|
|
252
|
+
this.previewComponent.getInstance()?.zoomOut?.();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
download() {
|
|
256
|
+
this.previewComponent.getInstance()?.download?.();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Event handlers
|
|
260
|
+
onLoading() {
|
|
261
|
+
console.log('Loading file...');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
onLoaded(event: unknown) {
|
|
265
|
+
console.log('File successfully loaded:', event);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
onError(err: Error) {
|
|
269
|
+
console.error('Failed to preview file:', err);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
onPageChange(data: unknown) {
|
|
273
|
+
console.log('Page switched:', data);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
onZoomChange(data: unknown) {
|
|
277
|
+
console.log('Zoom changed:', data);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### Traditional NgModule (Angular 14+)
|
|
283
|
+
```typescript
|
|
284
|
+
import { NgModule } from '@angular/core';
|
|
285
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
286
|
+
import { FilePreviewComponent } from '@files-preview-app/preview-file/angular';
|
|
287
|
+
import { AppComponent } from './app.component';
|
|
288
|
+
|
|
289
|
+
@NgModule({
|
|
290
|
+
declarations: [AppComponent],
|
|
291
|
+
imports: [BrowserModule, FilePreviewComponent],
|
|
292
|
+
bootstrap: [AppComponent]
|
|
293
|
+
})
|
|
294
|
+
export class AppModule {}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### 4. Vue 3 (`@files-preview-app/preview-file/vue`)
|
|
300
|
+
|
|
301
|
+
#### Composition API (`<script setup>`)
|
|
302
|
+
```vue
|
|
303
|
+
<template>
|
|
304
|
+
<div class="preview-container" style="width: 100%; height: 800px;">
|
|
305
|
+
<!-- Controls Bar -->
|
|
306
|
+
<div class="toolbar-actions" style="margin-bottom: 12px; display: flex; gap: 8px;">
|
|
307
|
+
<input type="file" @change="handleFileSelect" />
|
|
308
|
+
<button @click="zoomIn">Zoom In (+)</button>
|
|
309
|
+
<button @click="zoomOut">Zoom Out (-)</button>
|
|
310
|
+
<button @click="rotate">Rotate (90°)</button>
|
|
311
|
+
<button @click="download">Download</button>
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<!-- Universal Preview Component -->
|
|
315
|
+
<FilePreview
|
|
316
|
+
ref="previewRef"
|
|
317
|
+
:src="fileSource"
|
|
318
|
+
:options="{
|
|
319
|
+
theme: 'light',
|
|
320
|
+
showToolbar: true,
|
|
321
|
+
toolbarPosition: 'top'
|
|
322
|
+
}"
|
|
323
|
+
@loading="onLoading"
|
|
324
|
+
@loaded="onLoaded"
|
|
325
|
+
@error="onError"
|
|
326
|
+
@page-change="onPageChange"
|
|
327
|
+
@zoom-change="onZoomChange"
|
|
328
|
+
/>
|
|
329
|
+
</div>
|
|
330
|
+
</template>
|
|
331
|
+
|
|
332
|
+
<script setup lang="ts">
|
|
333
|
+
import { ref } from 'vue';
|
|
334
|
+
import { FilePreview } from '@files-preview-app/preview-file/vue';
|
|
335
|
+
import '@files-preview-app/preview-file/styles.css';
|
|
336
|
+
|
|
337
|
+
const previewRef = ref<InstanceType<typeof FilePreview> | null>(null);
|
|
338
|
+
const fileSource = ref<string | File>('https://example.com/archive.zip');
|
|
339
|
+
|
|
340
|
+
function handleFileSelect(e: Event) {
|
|
341
|
+
const target = e.target as HTMLInputElement;
|
|
342
|
+
if (target.files?.[0]) {
|
|
343
|
+
fileSource.value = target.files[0];
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Programmatic methods
|
|
348
|
+
function zoomIn() {
|
|
349
|
+
previewRef.value?.getInstance()?.zoomIn?.();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function zoomOut() {
|
|
353
|
+
previewRef.value?.getInstance()?.zoomOut?.();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function rotate() {
|
|
357
|
+
previewRef.value?.getInstance()?.rotateCW?.();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function download() {
|
|
361
|
+
previewRef.value?.getInstance()?.download?.();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Event callbacks
|
|
365
|
+
function onLoading() {
|
|
366
|
+
console.log('Rendering file...');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function onLoaded(metadata: unknown) {
|
|
370
|
+
console.log('Preview ready:', metadata);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function onError(err: unknown) {
|
|
374
|
+
console.error('Preview error:', err);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function onPageChange(pageData: unknown) {
|
|
378
|
+
console.log('Page switched:', pageData);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function onZoomChange(zoomData: unknown) {
|
|
382
|
+
console.log('Zoom changed:', zoomData);
|
|
383
|
+
}
|
|
384
|
+
</script>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### Nuxt 3 Integration
|
|
388
|
+
Wrap inside `<ClientOnly>` to avoid server-side rendering:
|
|
389
|
+
```vue
|
|
390
|
+
<template>
|
|
391
|
+
<ClientOnly>
|
|
392
|
+
<div style="height: 800px;">
|
|
393
|
+
<FilePreview src="/documents/sample.pdf" />
|
|
394
|
+
</div>
|
|
395
|
+
<template #fallback>
|
|
396
|
+
<div>Loading preview component...</div>
|
|
397
|
+
</template>
|
|
398
|
+
</ClientOnly>
|
|
399
|
+
</template>
|
|
400
|
+
|
|
401
|
+
<script setup lang="ts">
|
|
402
|
+
import { FilePreview } from '@files-preview-app/preview-file/vue';
|
|
403
|
+
import '@files-preview-app/preview-file/styles.css';
|
|
404
|
+
</script>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
### 5. Vanilla JavaScript / TypeScript (`@files-preview-app/preview-file`)
|
|
410
|
+
|
|
411
|
+
Use directly with any build tool (Vite, Webpack, Rollup) or via `<script type="module">`:
|
|
412
|
+
|
|
413
|
+
```html
|
|
414
|
+
<!DOCTYPE html>
|
|
415
|
+
<html lang="en">
|
|
416
|
+
<head>
|
|
417
|
+
<meta charset="UTF-8" />
|
|
418
|
+
<title>Universal File Preview</title>
|
|
419
|
+
<!-- Link Stylesheet -->
|
|
420
|
+
<link rel="stylesheet" href="node_modules/@files-preview-app/preview-file/dist/styles.css" />
|
|
421
|
+
<style>
|
|
422
|
+
#viewer-container {
|
|
423
|
+
width: 100%;
|
|
424
|
+
height: 850px;
|
|
425
|
+
border: 1px solid #e2e8f0;
|
|
426
|
+
border-radius: 8px;
|
|
427
|
+
}
|
|
428
|
+
</style>
|
|
429
|
+
</head>
|
|
430
|
+
<body>
|
|
431
|
+
<div style="margin-bottom: 12px; display: flex; gap: 8px;">
|
|
432
|
+
<input type="file" id="file-picker" />
|
|
433
|
+
<button id="btn-zoom-in">Zoom In</button>
|
|
434
|
+
<button id="btn-zoom-out">Zoom Out</button>
|
|
435
|
+
<button id="btn-download">Download</button>
|
|
436
|
+
</div>
|
|
437
|
+
|
|
438
|
+
<div id="viewer-container"></div>
|
|
439
|
+
|
|
440
|
+
<script type="module">
|
|
441
|
+
import { FilePreviewViewer } from './node_modules/@files-preview-app/preview-file/dist/index.js';
|
|
442
|
+
|
|
443
|
+
const container = document.getElementById('viewer-container');
|
|
444
|
+
const filePicker = document.getElementById('file-picker');
|
|
445
|
+
|
|
446
|
+
// 1. Instantiate viewer
|
|
447
|
+
const viewer = new FilePreviewViewer();
|
|
448
|
+
|
|
449
|
+
// 2. Listen to lifecycle events
|
|
450
|
+
viewer.on('loading', () => console.log('File loading started'));
|
|
451
|
+
viewer.on('loaded', (info) => console.log('File loaded:', info));
|
|
452
|
+
viewer.on('error', (err) => console.error('Preview error:', err));
|
|
453
|
+
viewer.on('page-change', (data) => console.log('Page switched:', data));
|
|
454
|
+
|
|
455
|
+
// 3. Render initial file
|
|
456
|
+
let instance = await viewer.preview(
|
|
457
|
+
container,
|
|
458
|
+
'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf',
|
|
459
|
+
{
|
|
460
|
+
theme: 'light',
|
|
461
|
+
showToolbar: true,
|
|
462
|
+
toolbarPosition: 'top'
|
|
463
|
+
}
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
// 4. Handle file selection from local disk
|
|
467
|
+
filePicker.addEventListener('change', async (e) => {
|
|
468
|
+
const file = e.target.files[0];
|
|
469
|
+
if (file) {
|
|
470
|
+
instance = await viewer.preview(container, file, { theme: 'light' });
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// 5. Connect custom buttons to instance methods
|
|
475
|
+
document.getElementById('btn-zoom-in').addEventListener('click', () => instance?.zoomIn?.());
|
|
476
|
+
document.getElementById('btn-zoom-out').addEventListener('click', () => instance?.zoomOut?.());
|
|
477
|
+
document.getElementById('btn-download').addEventListener('click', () => instance?.download?.());
|
|
478
|
+
</script>
|
|
479
|
+
</body>
|
|
480
|
+
</html>
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## 🎛️ Complete Methods Reference
|
|
486
|
+
|
|
487
|
+
### 1. `FilePreviewViewer` (Viewer Class Methods)
|
|
488
|
+
|
|
489
|
+
| Method | Parameters | Returns | Description |
|
|
490
|
+
|---|---|---|---|
|
|
491
|
+
| `preview()` | `container: HTMLElement`, `source: FileSource`, `options?: PreviewViewerOptions` | `Promise<PreviewInstance>` | Renders any supported file into the target DOM element. Cleans up previous renders automatically. |
|
|
492
|
+
| `getInstance()` | None | `PreviewInstance \| null` | Returns the active preview instance, exposing zoom, navigation, export, and rotation methods. |
|
|
493
|
+
| `on()` | `event: string`, `handler: (data: any) => void` | `Unsubscribe: () => void` | Subscribes to lifecycle events. Returns an unsubscribe cleanup function. |
|
|
494
|
+
| `registerPlugin()` | `plugin: PreviewPlugin` | `this` | Registers a custom renderer plugin. |
|
|
495
|
+
| `registerPlugins()` | `plugins: PreviewPlugin[]` | `this` | Registers multiple renderer plugins at once. |
|
|
496
|
+
| `destroy()` | None | `void` | Destroys the active instance, removes toolbar DOM, cancels network abort controllers, and clears listeners. |
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
### 2. `PreviewInstance` (Active Document Instance Methods)
|
|
501
|
+
|
|
502
|
+
Retrieved via `viewer.getInstance()` or `previewRef.current.getInstance()`.
|
|
503
|
+
|
|
504
|
+
| Category | Method | Return Type | Description | Example Usage |
|
|
505
|
+
|---|---|---|---|---|
|
|
506
|
+
| **Zoom** | `zoomIn()` | `void` | Increments zoom level by 20% | `instance.zoomIn()` |
|
|
507
|
+
| **Zoom** | `zoomOut()` | `void` | Decrements zoom level by 20% | `instance.zoomOut()` |
|
|
508
|
+
| **Zoom** | `setZoom(level)` | `void` | Sets absolute zoom scale (e.g. `1.5` = 150%) | `instance.setZoom(1.5)` |
|
|
509
|
+
| **Zoom** | `getZoom()` | `number` | Gets current zoom scale number | `const z = instance.getZoom()` |
|
|
510
|
+
| **Zoom** | `fitToPage()` | `void` | Resets zoom to fit container viewport | `instance.fitToPage()` |
|
|
511
|
+
| **Pagination** | `goToPage(page)` | `void` | Jumps to specific page, sheet, or slide (1-indexed) | `instance.goToPage(3)` |
|
|
512
|
+
| **Pagination** | `getPageCount()` | `number` | Returns total page, sheet, or slide count | `const total = instance.getPageCount()` |
|
|
513
|
+
| **Pagination** | `getCurrentPage()` | `number` | Returns current 1-indexed page or sheet | `const cur = instance.getCurrentPage()` |
|
|
514
|
+
| **Rotation** | `rotateCW()` | `void` | Rotates document, image, or video 90° clockwise | `instance.rotateCW()` |
|
|
515
|
+
| **Rotation** | `rotateCCW()` | `void` | Rotates 90° counter-clockwise | `instance.rotateCCW()` |
|
|
516
|
+
| **Rotation** | `getRotation()` | `number` | Returns rotation angle in degrees (0, 90, 180, 270) | `const deg = instance.getRotation()` |
|
|
517
|
+
| **Media** | `play()` | `void` | Starts video or audio playback | `instance.play()` |
|
|
518
|
+
| **Media** | `pause()` | `void` | Pauses video or audio playback | `instance.pause()` |
|
|
519
|
+
| **Media** | `isPlaying()` | `boolean` | Checks if media is currently playing | `if (instance.isPlaying()) ...` |
|
|
520
|
+
| **Thumbnails** | `getThumbnails()` | `Thumbnail[]` | Returns list of thumbnails for sidebar | `const thumbs = instance.getThumbnails()` |
|
|
521
|
+
| **Thumbnails** | `toggleThumbnails()`| `void` | Toggles the page thumbnails sidebar panel | `instance.toggleThumbnails()` |
|
|
522
|
+
| **Export** | `download()` | `void` | Downloads original file with proper name & MIME | `instance.download()` |
|
|
523
|
+
| **Export** | `print()` | `void` | Opens browser print dialog formatted for clean output | `instance.print()` |
|
|
524
|
+
| **Lifecycle** | `destroy()` | `void` | Releases memory, cancels rendering, revokes blob URLs | `instance.destroy()` |
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## 📡 Complete Events Reference
|
|
529
|
+
|
|
530
|
+
All events can be listened to via framework bindings (`onLoaded`, `(loaded)`, `@loaded`) or `viewer.on('event', handler)`:
|
|
531
|
+
|
|
532
|
+
| Event Name | Framework Prop / Event | Payload Type | Description |
|
|
533
|
+
|---|---|---|---|
|
|
534
|
+
| `'loading'` | `onLoading` / `(loading)` / `@loading` | `{ source: FileSource }` | Emitted immediately when file parsing and decoding starts. |
|
|
535
|
+
| `'loaded'` | `onLoaded` / `(loaded)` / `@loaded` | `{ metadata: FileMetadata, plugin: string }` | Emitted when file rendering completes successfully. Contains detected metadata. |
|
|
536
|
+
| `'error'` | `onError` / `(error)` / `@error` | `Error` | Emitted if file download, decoding, or rendering fails. |
|
|
537
|
+
| `'page-change'` | `onPageChange` / `(pageChange)` / `@page-change` | `{ page: number, totalPages?: number }` | Emitted when user navigates to another page, Excel sheet, or PPT slide. |
|
|
538
|
+
| `'zoom-change'` | `onZoomChange` / `(zoomChange)` / `@zoom-change` | `{ zoom: number }` | Emitted whenever zoom level changes. |
|
|
539
|
+
| `'rotate'` | `onRotate` / `(rotate)` / `@rotate` | `{ rotation: number }` | Emitted when orientation rotates (0°, 90°, 180°, 270°). |
|
|
540
|
+
| `'destroy'` | `onDestroy` / `(destroy)` / `@destroy` | `null` | Emitted when viewer is cleaned up. |
|
|
541
|
+
|
|
542
|
+
### Practical Event Examples
|
|
543
|
+
|
|
544
|
+
#### 1. Show File Metadata Badge on Loaded
|
|
545
|
+
```typescript
|
|
546
|
+
viewer.on('loaded', ({ metadata, plugin }) => {
|
|
547
|
+
console.log('File Name:', metadata.name);
|
|
548
|
+
console.log('File Size:', (metadata.size / 1024).toFixed(1) + ' KB');
|
|
549
|
+
console.log('Detected MIME:', metadata.mimeType);
|
|
550
|
+
console.log('Renderer Plugin:', plugin);
|
|
551
|
+
});
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
#### 2. Display Custom Error Toast Notification
|
|
555
|
+
```typescript
|
|
556
|
+
viewer.on('error', (err) => {
|
|
557
|
+
showToastNotification(`Cannot open file: ${err.message}`, { type: 'error' });
|
|
558
|
+
});
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
#### 3. Synchronize External Page Counter
|
|
562
|
+
```typescript
|
|
563
|
+
viewer.on('page-change', ({ page, totalPages }) => {
|
|
564
|
+
pageIndicatorEl.innerText = `Page ${page} of ${totalPages || '?'}`;
|
|
565
|
+
});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## ⚙️ Complete Properties & Options Reference
|
|
571
|
+
|
|
572
|
+
### 1. `src` Property (Accepts 5 Source Formats)
|
|
573
|
+
|
|
574
|
+
The `src` prop accepts any of the following types:
|
|
575
|
+
|
|
576
|
+
| Format | Type | Example |
|
|
577
|
+
|---|---|---|
|
|
578
|
+
| **Local File** | `File` | From `<input type="file">` event: `e.target.files[0]` |
|
|
579
|
+
| **URL String** | `string` | Remote or local URL: `'https://example.com/file.pdf'` |
|
|
580
|
+
| **Blob** | `Blob` | `new Blob([binaryData], { type: 'application/pdf' })` |
|
|
581
|
+
| **ArrayBuffer** | `ArrayBuffer` | Direct binary buffer: `await response.arrayBuffer()` |
|
|
582
|
+
| **TypedArray** | `Uint8Array` | Byte array: `new Uint8Array(buffer)` |
|
|
583
|
+
| **Base64 URI** | `string` | Data URI: `'data:image/png;base64,iVBORw0...'` |
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
### 2. `options` Object Reference
|
|
588
|
+
|
|
589
|
+
Passed to `options` prop in React/Angular/Vue or third argument to `viewer.preview(container, src, options)`:
|
|
590
|
+
|
|
591
|
+
| Option Property | Type | Default | Description |
|
|
592
|
+
|---|---|---|---|
|
|
593
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` | UI theme. `'auto'` adapts to system dark mode preferences. |
|
|
594
|
+
| `showToolbar` | `boolean` | `true` | Set `false` to hide built-in toolbar (e.g. when using your own custom buttons). |
|
|
595
|
+
| `toolbarPosition` | `'top' \| 'bottom'` | `'top'` | Positions toolbar at the top or bottom of the viewer container. |
|
|
596
|
+
| `showThumbnails` | `boolean` | `false` | Opens page thumbnails sidebar panel automatically on load. |
|
|
597
|
+
| `className` | `string` | `''` | Custom CSS class attached to the root viewer container element. |
|
|
598
|
+
| `zoom` | `number` | `1.0` | Initial zoom multiplier (`1.0` = 100%, `1.5` = 150%). |
|
|
599
|
+
| `page` | `number` | `1` | Initial page, slide, or sheet number to display on load (1-based). |
|
|
600
|
+
| `locale` | `string` | `'en'` | UI label language localization. |
|
|
601
|
+
| `pluginOptions` | `Record<string, unknown>` | `{}` | Custom options passed directly to underlying format renderer plugins. |
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## 🎨 CSS Variables (Theming & Custom Styling)
|
|
606
|
+
|
|
607
|
+
Customize colors, borders, and typography using standard CSS custom properties:
|
|
608
|
+
|
|
609
|
+
```css
|
|
610
|
+
/* Custom Brand Theme */
|
|
611
|
+
.fp-viewer {
|
|
612
|
+
--fp-bg: #ffffff; /* Viewer background */
|
|
613
|
+
--fp-toolbar-bg: #f8fafc; /* Toolbar background */
|
|
614
|
+
--fp-border: #e2e8f0; /* Borders and dividers */
|
|
615
|
+
--fp-text: #0f172a; /* Text color */
|
|
616
|
+
--fp-primary: #3b82f6; /* Active buttons and highlights */
|
|
617
|
+
--fp-btn-hover: #f1f5f9; /* Toolbar button hover color */
|
|
618
|
+
--fp-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/* Dark Theme Overrides */
|
|
622
|
+
.fp-theme-dark {
|
|
623
|
+
--fp-bg: #0f172a;
|
|
624
|
+
--fp-toolbar-bg: #1e293b;
|
|
625
|
+
--fp-border: #334155;
|
|
626
|
+
--fp-text: #f8fafc;
|
|
627
|
+
--fp-primary: #60a5fa;
|
|
628
|
+
--fp-btn-hover: #334155;
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## 📂 Supported Formats Matrix (All 10 Categories)
|
|
635
|
+
|
|
636
|
+
Every file format is rendered 100% in the browser using permissive open-source engines:
|
|
637
|
+
|
|
638
|
+
| Category | File Extensions | Engine | License | Supported Features |
|
|
639
|
+
|---|---|---|---|---|
|
|
640
|
+
| **PDF** | `.pdf` | PDF.js (`pdfjs-dist`) | Apache-2.0 | Multi-page canvas rendering, Zoom In/Out, Fit to page, Rotate CW/CCW, Page jump, Thumbnails sidebar, Print, Download |
|
|
641
|
+
| **Word Document** | `.docx` | `docx-preview` | Apache-2.0 | Preserves styles, tables, bullets, images, fonts, Zoom In/Out, Fit to page, Print, Download |
|
|
642
|
+
| **Excel Spreadsheet** | `.xlsx`, `.xls` | `exceljs` | MIT | Multi-sheet tab bar, styled grid cells, borders, formatting, Zoom, Print, Download |
|
|
643
|
+
| **PowerPoint** | `.pptx`, `.ppsx` | `pptx-browser` | MIT | Slide-by-slide canvas rendering, slide thumbnails sidebar, navigation jump, Zoom, Fit to slide, Print, Download |
|
|
644
|
+
| **CSV / TSV Data** | `.csv`, `.tsv` | `papaparse` | MIT | Auto-detects comma/tab delimiter, tabular grid with header styling, Zoom, Print, Download |
|
|
645
|
+
| **ZIP Archives** | `.zip` | `fflate` | MIT | Hierarchical file tree/table explorer, compression stats, instant search filter, single-file extract/download, download ZIP |
|
|
646
|
+
| **Rich Markdown** | `.md`, `.markdown` | `marked` + `dompurify` | MIT / Apache-2.0 | GitHub Flavored Markdown (tables, checklists, blockquotes), syntax-highlighted code blocks, XSS sanitized, font zoom, Print, Download |
|
|
647
|
+
| **3D Models** | `.stl`, `.obj` | `three` (Three.js) | MIT | 360° mouse orbit controls, perspective camera, ambient & directional lighting, wireframe vs solid toggle, reset view, Download |
|
|
648
|
+
| **Images & Vector** | `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.bmp`, `.svg`, `.ico`, `.tiff` | Native + `@panzoom/panzoom` + `dompurify` | MIT / Apache-2.0 | Smooth pan & zoom, rotate 90°, SVG DOM sanitization, Print, Download |
|
|
649
|
+
| **Video & Audio** | `.mp4`, `.webm`, `.ogg`, `.mov`, `.mp3`, `.wav`, `.flac`, `.aac` | Native HTML5 Media | MIT | Play/Pause, seek bar, volume control, video rotate, fullscreen, Download |
|
|
650
|
+
| **Code & Text** | `.js`, `.ts`, `.jsx`, `.tsx`, `.html`, `.css`, `.json`, `.xml`, `.yaml`, `.py`, `.java`, `.cpp`, `.sql`, `.sh`, etc. (190+ languages) | `highlight.js` | BSD-3-Clause | Syntax highlighting, line numbers gutter, font zoom in/out, Print, Download |
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## 🛡️ Security & Privacy Guarantee
|
|
655
|
+
|
|
656
|
+
- 🔒 **100% Client-Side**: Files never leave the user's browser. No documents are uploaded to third-party clouds or external rendering servers.
|
|
657
|
+
- 🛡️ **XSS Protection**: All HTML, Markdown, and SVG inputs are strictly sanitized with `DOMPurify`.
|
|
658
|
+
- 🆓 **100% Permissive Open-Source**: All libraries used are audited under **MIT**, **Apache-2.0**, or **BSD-3-Clause**. No GPL, AGPL, copyleft claims, or paid commercial subscriptions. See [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md).
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## 👨💻 Author & Community
|
|
663
|
+
|
|
664
|
+
**Sumit Patel**
|
|
665
|
+
- 🌐 GitHub: [@patelsumit5192](https://github.com/patelsumit5192)
|
|
666
|
+
- 📦 NPM: [patel.sumit51](https://www.npmjs.com/~patel.sumit51)
|
|
667
|
+
- 💻 Repository: [https://github.com/patelsumit5192/preview-file](https://github.com/patelsumit5192/preview-file)
|
|
668
|
+
- 🚀 Live Demo: [https://patelsumit5192.github.io/preview-file/](https://patelsumit5192.github.io/preview-file/)
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
## 📄 License
|
|
673
|
+
|
|
674
|
+
MIT © 2026 Sumit Patel
|