@files-preview-app/preview-file 1.1.2 → 1.1.4

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/README.md CHANGED
@@ -1,66 +1,158 @@
1
1
  # @files-preview-app/preview-file
2
2
 
3
- > **Universal, all-in-one client-side file preview package for React, Angular, Vue, and Vanilla JS.**
4
- > Preview **PDF, Word (.docx), Excel (.xlsx), CSV, Images, Video, Audio, and Code/Text** with a built-in toolbar (zoom, rotate, thumbnails, page jump, download, print). 100% free, permissive open-source, and client-side (no cloud or server needed).
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).
5
20
 
6
- [![npm version](https://img.shields.io/npm/v/@files-preview-app/preview-file.svg)](https://www.npmjs.com/package/@files-preview-app/preview-file)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
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
8
32
 
9
33
  ---
10
34
 
11
35
  ## 📦 Installation
12
36
 
13
- Just install this **single package** in your project:
37
+ Install the **single all-in-one package** in your project:
14
38
 
15
39
  ```bash
16
40
  npm install @files-preview-app/preview-file
17
41
  ```
18
42
 
19
- Or using Yarn / pnpm:
43
+ Or using Yarn, pnpm, or Bun:
20
44
  ```bash
45
+ pnpm add @files-preview-app/preview-file
46
+ # or
21
47
  yarn add @files-preview-app/preview-file
22
48
  # or
23
- pnpm add @files-preview-app/preview-file
49
+ bun add @files-preview-app/preview-file
24
50
  ```
25
51
 
26
- Import the toolbar stylesheet in your main CSS or component:
52
+ Import the toolbar and viewer stylesheet in your global CSS or root component:
27
53
  ```css
28
54
  import '@files-preview-app/preview-file/styles.css';
29
55
  ```
30
56
 
31
57
  ---
32
58
 
33
- ## 🚀 Quick Start by Framework
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
34
74
 
35
75
  ### 1. React (`@files-preview-app/preview-file/react`)
36
76
 
77
+ #### Basic Usage
37
78
  ```tsx
38
79
  import React, { useState } from 'react';
39
80
  import { FilePreview } from '@files-preview-app/preview-file/react';
40
81
  import '@files-preview-app/preview-file/styles.css';
41
82
 
42
83
  export default function App() {
43
- const [selectedFile, setSelectedFile] = useState<File | string>('https://example.com/sample.pdf');
84
+ const [file, setFile] = useState<File | string>(
85
+ 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'
86
+ );
44
87
 
45
88
  return (
46
- <div>
47
- {/* File input for local files */}
89
+ <div style={{ padding: '20px' }}>
48
90
  <input
49
91
  type="file"
50
- onChange={(e) => e.target.files?.[0] && setSelectedFile(e.target.files[0])}
92
+ onChange={(e) => e.target.files?.[0] && setFile(e.target.files[0])}
51
93
  />
52
94
 
53
- {/* Preview container */}
54
- <div style={{ width: '100%', height: '800px', marginTop: '16px' }}>
95
+ <div style={{ width: '100%', height: '750px', marginTop: '16px' }}>
55
96
  <FilePreview
56
- src={selectedFile}
97
+ src={file}
57
98
  options={{
58
99
  theme: 'light', // 'light' | 'dark' | 'auto'
59
100
  showToolbar: true,
60
- toolbarPosition: 'top' // 'top' | 'bottom'
101
+ toolbarPosition: 'top', // 'top' | 'bottom'
102
+ showThumbnails: false,
61
103
  }}
62
- onLoaded={(info) => console.log('File loaded successfully:', info)}
63
- onError={(error) => console.error('Preview error:', error)}
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)}
64
156
  />
65
157
  </div>
66
158
  </div>
@@ -70,66 +162,169 @@ export default function App() {
70
162
 
71
163
  ---
72
164
 
73
- ### 2. Angular (`@files-preview-app/preview-file/angular`)
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`:
74
168
 
75
- In your standalone component or NgModule:
169
+ ```tsx
170
+ 'use client';
76
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)
77
198
  ```typescript
78
- import { Component } from '@angular/core';
199
+ import { Component, ViewChild } from '@angular/core';
200
+ import { CommonModule } from '@angular/common';
79
201
  import { FilePreviewComponent } from '@files-preview-app/preview-file/angular';
80
202
 
81
203
  @Component({
82
- selector: 'app-root',
204
+ selector: 'app-document-viewer',
83
205
  standalone: true,
84
- imports: [FilePreviewComponent],
206
+ imports: [CommonModule, FilePreviewComponent],
85
207
  template: `
86
- <div style="width: 100%; height: 800px;">
87
- <input type="file" (change)="onFileSelected($event)" />
88
-
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 -->
89
220
  <fp-file-preview
90
- [src]="fileSource"
91
- [options]="{ theme: 'light', showToolbar: true }"
221
+ #preview
222
+ [src]="selectedFile"
223
+ [options]="{ theme: 'light', showToolbar: true, toolbarPosition: 'top' }"
224
+ (loading)="onLoading()"
92
225
  (loaded)="onLoaded($event)"
93
226
  (error)="onError($event)"
227
+ (pageChange)="onPageChange($event)"
228
+ (zoomChange)="onZoomChange($event)"
94
229
  />
95
230
  </div>
96
231
  `,
97
232
  styleUrls: ['@files-preview-app/preview-file/styles.css']
98
233
  })
99
- export class AppComponent {
100
- fileSource: string | File = 'https://example.com/report.xlsx';
234
+ export class DocumentViewerComponent {
235
+ @ViewChild('preview') previewComponent!: FilePreviewComponent;
236
+
237
+ selectedFile: string | File = 'https://example.com/presentation.pptx';
101
238
 
102
- onFileSelected(event: Event) {
239
+ onFileChange(event: Event) {
103
240
  const input = event.target as HTMLInputElement;
104
241
  if (input.files?.[0]) {
105
- this.fileSource = input.files[0];
242
+ this.selectedFile = input.files[0];
106
243
  }
107
244
  }
108
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
+
109
264
  onLoaded(event: unknown) {
110
- console.log('Preview ready', event);
265
+ console.log('File successfully loaded:', event);
111
266
  }
112
267
 
113
268
  onError(err: Error) {
114
- console.error('Preview failed', err);
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);
115
278
  }
116
279
  }
117
280
  ```
118
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
+
119
297
  ---
120
298
 
121
- ### 3. Vue 3 (`@files-preview-app/preview-file/vue`)
299
+ ### 4. Vue 3 (`@files-preview-app/preview-file/vue`)
122
300
 
301
+ #### Composition API (`<script setup>`)
123
302
  ```vue
124
303
  <template>
125
- <div style="width: 100%; height: 800px;">
126
- <input type="file" @change="onFileChange" />
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>
127
313
 
314
+ <!-- Universal Preview Component -->
128
315
  <FilePreview
129
- :src="currentFile"
130
- :options="{ theme: 'dark', showToolbar: true }"
131
- @loaded="handleLoaded"
132
- @error="handleError"
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"
133
328
  />
134
329
  </div>
135
330
  </template>
@@ -139,162 +334,341 @@ import { ref } from 'vue';
139
334
  import { FilePreview } from '@files-preview-app/preview-file/vue';
140
335
  import '@files-preview-app/preview-file/styles.css';
141
336
 
142
- const currentFile = ref<File | string>('/sample.docx');
337
+ const previewRef = ref<InstanceType<typeof FilePreview> | null>(null);
338
+ const fileSource = ref<string | File>('https://example.com/archive.zip');
143
339
 
144
- function onFileChange(event: Event) {
145
- const target = event.target as HTMLInputElement;
340
+ function handleFileSelect(e: Event) {
341
+ const target = e.target as HTMLInputElement;
146
342
  if (target.files?.[0]) {
147
- currentFile.value = target.files[0];
343
+ fileSource.value = target.files[0];
148
344
  }
149
345
  }
150
346
 
151
- function handleLoaded(data: unknown) {
152
- console.log('Loaded:', data);
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);
153
379
  }
154
380
 
155
- function handleError(err: unknown) {
156
- console.error('Error:', err);
381
+ function onZoomChange(zoomData: unknown) {
382
+ console.log('Zoom changed:', zoomData);
157
383
  }
158
384
  </script>
159
385
  ```
160
386
 
161
- ---
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>
162
400
 
163
- ### 4. Vanilla JavaScript / TypeScript (`@files-preview-app/preview-file`)
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
+ ```
164
406
 
165
- ```html
166
- <link rel="stylesheet" href="node_modules/@files-preview-app/preview-file/dist/styles.css" />
407
+ ---
167
408
 
168
- <div id="viewer-container" style="width: 100%; height: 800px;"></div>
409
+ ### 5. Vanilla JavaScript / TypeScript (`@files-preview-app/preview-file`)
169
410
 
170
- <script type="module">
171
- import { FilePreviewViewer } from '@files-preview-app/preview-file';
411
+ Use directly with any build tool (Vite, Webpack, Rollup) or via `<script type="module">`:
172
412
 
173
- const container = document.getElementById('viewer-container');
174
- const viewer = new FilePreviewViewer();
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>
175
437
 
176
- // Preview from URL, File, Blob, or ArrayBuffer
177
- await viewer.preview(container, 'https://example.com/invoice.pdf', {
178
- theme: 'light',
179
- showToolbar: true
180
- });
181
- </script>
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>
182
481
  ```
183
482
 
184
483
  ---
185
484
 
186
- ## 📂 Supported Extensions & Built-in Controls
485
+ ## 🎛️ Complete Methods Reference
187
486
 
188
- The viewer automatically recognizes the file extension and magic binary bytes, activating the corresponding renderer and controls:
487
+ ### 1. `FilePreviewViewer` (Viewer Class Methods)
189
488
 
190
- | File Format | Extensions | Controls Available |
191
- |---|---|---|
192
- | **PDF** | `.pdf` | Zoom In/Out, Fit to Page, Rotate CW/CCW, Page Navigation Jump, Thumbnails Sidebar, Download, Print |
193
- | **Word Document** | `.docx` | Full layout rendering, Zoom In/Out, Fit to Page, Download, Print |
194
- | **Excel Spreadsheet** | `.xlsx`, `.xls` | Multi-Sheet Tabs Navigation, Formatted Grid Table, Zoom In/Out, Download, Print |
195
- | **PowerPoint** | `.pptx`, `.ppsx` | Slide-by-Slide Navigation, Slide Thumbnails Sidebar, Zoom In/Out, Fit to Slide, Download, Print |
196
- | **CSV / TSV Data** | `.csv`, `.tsv` | Tabular Grid with Header Styling, Comma/Tab auto-detection, Zoom In/Out, Download, Print |
197
- | **ZIP Archives** | `.zip` | File Tree & Table Explorer, Compression Stats, Search Filter, Individual File Download, Download Zip |
198
- | **Rich Markdown** | `.md`, `.markdown` | Rendered GitHub Markdown (Tables, Checklists, Blockquotes), Syntax Highlighted Code, Font Zoom, Download, Print |
199
- | **3D Models** | `.stl`, `.obj` | 360° Orbit Mouse Controls, Perspective Camera, Lighting, Wireframe Toggle, Zoom, Reset View, Download |
200
- | **Images** | `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.bmp`, `.svg`, `.ico`, `.tiff` | Pan & Zoom, Reset / Fit, Rotate 90°, Download, Print |
201
- | **Video** | `.mp4`, `.webm`, `.ogg`, `.mov` | Play / Pause, Rotate, Fullscreen, Download |
202
- | **Audio** | `.mp3`, `.wav`, `.ogg`, `.flac`, `.aac` | Play / Pause, Volume, Seek, Download |
203
- | **Code & Text** | `.js`, `.ts`, `.jsx`, `.tsx`, `.html`, `.css`, `.json`, `.xml`, `.yaml`, `.py`, `.java`, `.cpp`, `.sql`, `.md`, `.txt`, `.sh`, etc. (190+ languages) | Syntax Highlighting via highlight.js, Font Scaling Zoom In/Out, Download, Print |
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. |
204
497
 
205
498
  ---
206
499
 
207
- ## 📥 How to Pass Values (`src` prop)
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()` |
208
525
 
209
- You can pass the file source in **any** of the following formats:
526
+ ---
210
527
 
211
- ### 1. From HTML `<input type="file">` (File object)
212
- ```tsx
213
- const file = event.target.files[0];
214
- <FilePreview src={file} />
215
- ```
528
+ ## 📡 Complete Events Reference
216
529
 
217
- ### 2. URL String (Public URL or CDN)
218
- ```tsx
219
- <FilePreview src="https://example.com/documents/contract.pdf" />
220
- ```
530
+ All events can be listened to via framework bindings (`onLoaded`, `(loaded)`, `@loaded`) or `viewer.on('event', handler)`:
221
531
 
222
- ### 3. Blob Object
223
- ```tsx
224
- const blob = new Blob([data], { type: 'application/pdf' });
225
- <FilePreview src={blob} />
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
+ });
226
552
  ```
227
553
 
228
- ### 4. ArrayBuffer or Uint8Array
229
- ```tsx
230
- const buffer = await response.arrayBuffer();
231
- <FilePreview src={buffer} />
554
+ #### 2. Display Custom Error Toast Notification
555
+ ```typescript
556
+ viewer.on('error', (err) => {
557
+ showToastNotification(`Cannot open file: ${err.message}`, { type: 'error' });
558
+ });
232
559
  ```
233
560
 
234
- ### 5. Base64 Data URI
235
- ```tsx
236
- <FilePreview src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
561
+ #### 3. Synchronize External Page Counter
562
+ ```typescript
563
+ viewer.on('page-change', ({ page, totalPages }) => {
564
+ pageIndicatorEl.innerText = `Page ${page} of ${totalPages || '?'}`;
565
+ });
237
566
  ```
238
567
 
239
568
  ---
240
569
 
241
- ## 🎛️ Toolbar Features Matrix
570
+ ## ⚙️ Complete Properties & Options Reference
571
+
572
+ ### 1. `src` Property (Accepts 5 Source Formats)
242
573
 
243
- | Control | How it Works |
244
- |---|---|
245
- | **Thumbnails** | Toggles a collapsible sidebar showing miniature rendered previews of each page/sheet. |
246
- | **Zoom In / Zoom Out** | Dynamically scales document, canvas, or font size without pixelation. |
247
- | **Fit to Page** | Automatically fits the preview perfectly within your container dimensions. |
248
- | **Page Jump** | Numeric input field allowing users to type a page or sheet number and jump instantly. |
249
- | **Rotate** | Rotates documents, images, and videos 90 degrees clockwise or counterclockwise. |
250
- | **Play / Pause** | Controls video and audio playback directly from the unified toolbar. |
251
- | **Download** | Downloads the original file to the user's disk with proper filename and MIME type. |
252
- | **Print** | Opens the browser print dialog formatted specifically for clean printing. |
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...'` |
253
584
 
254
585
  ---
255
586
 
256
- ## 🎨 Viewer Options
587
+ ### 2. `options` Object Reference
257
588
 
258
- Pass configuration via the `options` object:
589
+ Passed to `options` prop in React/Angular/Vue or third argument to `viewer.preview(container, src, options)`:
259
590
 
260
- ```typescript
261
- interface PreviewViewerOptions {
262
- /** Color theme: 'light' | 'dark' | 'auto' (default: 'light') */
263
- theme?: 'light' | 'dark' | 'auto';
264
- /** Show top toolbar (default: true) */
265
- showToolbar?: boolean;
266
- /** Toolbar placement: 'top' | 'bottom' (default: 'top') */
267
- toolbarPosition?: 'top' | 'bottom';
268
- /** Show thumbnails panel on initial load (default: false) */
269
- showThumbnails?: boolean;
270
- /** Custom wrapper CSS class name */
271
- className?: string;
272
- /** Initial zoom multiplier (1.0 = 100%) */
273
- zoom?: number;
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;
274
629
  }
275
630
  ```
276
631
 
277
632
  ---
278
633
 
279
- ## 🛡️ Security & Licensing
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
+ ---
280
653
 
281
- - **100% Client-Side**: No document or file data is ever sent to any remote server or third-party cloud.
282
- - **XSS Protection**: HTML and SVG previews are sanitized with `DOMPurify`.
283
- - **Strictly Permissive Licenses**: Every dependency used is audited and verified under **MIT**, **Apache-2.0**, or **BSD-3-Clause**. No GPL, AGPL, commercial paywalls, or restrictive terms.
654
+ ## 🛡️ Security & Privacy Guarantee
284
655
 
285
- See [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md) for full licensing details.
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).
286
659
 
287
660
  ---
288
661
 
289
- ## 👨‍💻 Author
662
+ ## 👨‍💻 Author & Community
290
663
 
291
664
  **Sumit Patel**
292
- - GitHub: [@patelsumit5192](https://github.com/patelsumit5192)
293
- - npm: [patel.sumit51](https://www.npmjs.com/~patel.sumit51)
294
- - Repository: [https://github.com/patelsumit5192/preview-file](https://github.com/patelsumit5192/preview-file)
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/)
295
669
 
296
670
  ---
297
671
 
298
672
  ## 📄 License
299
673
 
300
- MIT © 2026 Sumit Patel
674
+ MIT © 2026 Sumit Patel