ngx-file-peek 1.0.0

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 ADDED
@@ -0,0 +1,64 @@
1
+ # NgxFilePreview
2
+
3
+ This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.2.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8
+
9
+ ```bash
10
+ ng generate component component-name
11
+ ```
12
+
13
+ For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14
+
15
+ ```bash
16
+ ng generate --help
17
+ ```
18
+
19
+ ## Building
20
+
21
+ To build the library, run:
22
+
23
+ ```bash
24
+ ng build ngx-file-preview
25
+ ```
26
+
27
+ This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28
+
29
+ ### Publishing the Library
30
+
31
+ Once the project is built, you can publish your library by following these steps:
32
+
33
+ 1. Navigate to the `dist` directory:
34
+
35
+ ```bash
36
+ cd dist/ngx-file-preview
37
+ ```
38
+
39
+ 2. Run the `npm publish` command to publish your library to the npm registry:
40
+ ```bash
41
+ npm publish
42
+ ```
43
+
44
+ ## Running unit tests
45
+
46
+ To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
47
+
48
+ ```bash
49
+ ng test
50
+ ```
51
+
52
+ ## Running end-to-end tests
53
+
54
+ For end-to-end (e2e) testing, run:
55
+
56
+ ```bash
57
+ ng e2e
58
+ ```
59
+
60
+ Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
61
+
62
+ ## Additional Resources
63
+
64
+ For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
@@ -0,0 +1,636 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, input, ChangeDetectionStrategy, Component, InjectionToken, inject, signal, viewChild, afterNextRender, computed, ElementRef, ViewContainerRef, Directive } from '@angular/core';
3
+ import { DomSanitizer } from '@angular/platform-browser';
4
+ import { Overlay } from '@angular/cdk/overlay';
5
+ import { ComponentPortal } from '@angular/cdk/portal';
6
+
7
+ var FileType;
8
+ (function (FileType) {
9
+ FileType["Image"] = "image";
10
+ FileType["Pdf"] = "pdf";
11
+ FileType["Word"] = "word";
12
+ FileType["Excel"] = "excel";
13
+ FileType["Unknown"] = "unknown";
14
+ })(FileType || (FileType = {}));
15
+ const THUMBNAIL_SIZE_MAP = {
16
+ sm: 80,
17
+ md: 120,
18
+ lg: 200,
19
+ };
20
+
21
+ const EXTENSION_MAP = {
22
+ jpg: FileType.Image,
23
+ jpeg: FileType.Image,
24
+ png: FileType.Image,
25
+ gif: FileType.Image,
26
+ webp: FileType.Image,
27
+ svg: FileType.Image,
28
+ bmp: FileType.Image,
29
+ pdf: FileType.Pdf,
30
+ doc: FileType.Word,
31
+ docx: FileType.Word,
32
+ xls: FileType.Excel,
33
+ xlsx: FileType.Excel,
34
+ };
35
+ class FileTypeService {
36
+ detectType(url) {
37
+ try {
38
+ const parsed = new URL(url, 'https://placeholder.local');
39
+ const pathname = parsed.pathname;
40
+ const lastDot = pathname.lastIndexOf('.');
41
+ if (lastDot === -1)
42
+ return FileType.Unknown;
43
+ const ext = pathname.substring(lastDot + 1).toLowerCase();
44
+ return EXTENSION_MAP[ext] ?? FileType.Unknown;
45
+ }
46
+ catch {
47
+ return FileType.Unknown;
48
+ }
49
+ }
50
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FileTypeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
51
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FileTypeService, providedIn: 'root' });
52
+ }
53
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FileTypeService, decorators: [{
54
+ type: Injectable,
55
+ args: [{ providedIn: 'root' }]
56
+ }] });
57
+
58
+ class ImageRendererComponent {
59
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
60
+ size = input(120, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
61
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ImageRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
62
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.6", type: ImageRendererComponent, isStandalone: true, selector: "fp-image-renderer", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
63
+ <img
64
+ [src]="url()"
65
+ [width]="size()"
66
+ [height]="size()"
67
+ loading="lazy"
68
+ alt="File preview"
69
+ />
70
+ `, isInline: true, styles: [":host{display:block;overflow:hidden;line-height:0}img{object-fit:cover;display:block;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
71
+ }
72
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ImageRendererComponent, decorators: [{
73
+ type: Component,
74
+ args: [{ selector: 'fp-image-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
75
+ <img
76
+ [src]="url()"
77
+ [width]="size()"
78
+ [height]="size()"
79
+ loading="lazy"
80
+ alt="File preview"
81
+ />
82
+ `, styles: [":host{display:block;overflow:hidden;line-height:0}img{object-fit:cover;display:block;width:100%;height:100%}\n"] }]
83
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
84
+
85
+ const DEFAULT_CONFIG = {
86
+ tooltipDelay: 300,
87
+ placeholderTheme: 'minimal',
88
+ };
89
+ const FILE_PREVIEW_CONFIG = new InjectionToken('FILE_PREVIEW_CONFIG', { factory: () => DEFAULT_CONFIG });
90
+ function provideFilePreview(config = {}) {
91
+ return { provide: FILE_PREVIEW_CONFIG, useValue: { ...DEFAULT_CONFIG, ...config } };
92
+ }
93
+
94
+ class PdfRendererService {
95
+ config = inject(FILE_PREVIEW_CONFIG);
96
+ async renderFirstPage(url, canvas, maxSize) {
97
+ const pdfjs = await import('pdfjs-dist');
98
+ if (this.config.pdfWorkerUrl) {
99
+ pdfjs.GlobalWorkerOptions.workerSrc = this.config.pdfWorkerUrl;
100
+ }
101
+ const pdf = await pdfjs.getDocument(url).promise;
102
+ const page = await pdf.getPage(1);
103
+ const unscaledViewport = page.getViewport({ scale: 1 });
104
+ const scale = maxSize / Math.max(unscaledViewport.width, unscaledViewport.height);
105
+ const viewport = page.getViewport({ scale });
106
+ canvas.width = viewport.width;
107
+ canvas.height = viewport.height;
108
+ await page.render({ canvas, viewport }).promise;
109
+ }
110
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PdfRendererService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
111
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PdfRendererService, providedIn: 'root' });
112
+ }
113
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PdfRendererService, decorators: [{
114
+ type: Injectable,
115
+ args: [{ providedIn: 'root' }]
116
+ }] });
117
+
118
+ class PdfRendererComponent {
119
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
120
+ size = input(120, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
121
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
122
+ error = signal(false, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
123
+ pdfService = inject(PdfRendererService);
124
+ canvasRef = viewChild('pdfCanvas', ...(ngDevMode ? [{ debugName: "canvasRef" }] : /* istanbul ignore next */ []));
125
+ constructor() {
126
+ afterNextRender(() => this.render());
127
+ }
128
+ async render() {
129
+ const canvasEl = this.canvasRef()?.nativeElement;
130
+ if (!canvasEl)
131
+ return;
132
+ try {
133
+ await this.pdfService.renderFirstPage(this.url(), canvasEl, this.size());
134
+ this.loading.set(false);
135
+ }
136
+ catch {
137
+ this.loading.set(false);
138
+ this.error.set(true);
139
+ }
140
+ }
141
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PdfRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
142
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: PdfRendererComponent, isStandalone: true, selector: "fp-pdf-renderer", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["pdfCanvas"], descendants: true, isSignal: true }], ngImport: i0, template: `
143
+ @if (loading()) {
144
+ <div class="spinner" [style.width.px]="size()" [style.height.px]="size()">
145
+ <div class="spinner-icon"></div>
146
+ </div>
147
+ }
148
+ @if (error()) {
149
+ <div class="error" [style.width.px]="size()" [style.height.px]="size()">
150
+ <svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="#e53e3e" stroke-width="2">
151
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
152
+ <polyline points="14 2 14 8 20 8"/>
153
+ <line x1="12" y1="12" x2="12" y2="16"/>
154
+ <circle cx="12" cy="18" r="0.5"/>
155
+ </svg>
156
+ <span>PDF Error</span>
157
+ </div>
158
+ }
159
+ <canvas #pdfCanvas [style.display]="loading() || error() ? 'none' : 'block'"></canvas>
160
+ `, isInline: true, styles: [":host{display:block;overflow:hidden;line-height:0}canvas{display:block}.spinner,.error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8)}.spinner-icon{width:24px;height:24px;border:3px solid #e2e2e5;border-top-color:#6366f1;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{color:#e53e3e;font-size:12px;font-family:sans-serif}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
161
+ }
162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PdfRendererComponent, decorators: [{
163
+ type: Component,
164
+ args: [{ selector: 'fp-pdf-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
165
+ @if (loading()) {
166
+ <div class="spinner" [style.width.px]="size()" [style.height.px]="size()">
167
+ <div class="spinner-icon"></div>
168
+ </div>
169
+ }
170
+ @if (error()) {
171
+ <div class="error" [style.width.px]="size()" [style.height.px]="size()">
172
+ <svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="#e53e3e" stroke-width="2">
173
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
174
+ <polyline points="14 2 14 8 20 8"/>
175
+ <line x1="12" y1="12" x2="12" y2="16"/>
176
+ <circle cx="12" cy="18" r="0.5"/>
177
+ </svg>
178
+ <span>PDF Error</span>
179
+ </div>
180
+ }
181
+ <canvas #pdfCanvas [style.display]="loading() || error() ? 'none' : 'block'"></canvas>
182
+ `, styles: [":host{display:block;overflow:hidden;line-height:0}canvas{display:block}.spinner,.error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8)}.spinner-icon{width:24px;height:24px;border:3px solid #e2e2e5;border-top-color:#6366f1;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{color:#e53e3e;font-size:12px;font-family:sans-serif}\n"] }]
183
+ }], ctorParameters: () => [], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], canvasRef: [{ type: i0.ViewChild, args: ['pdfCanvas', { isSignal: true }] }] } });
184
+
185
+ class WordRendererService {
186
+ async renderToHtml(url) {
187
+ const response = await fetch(url);
188
+ const arrayBuffer = await response.arrayBuffer();
189
+ const mammoth = await import('mammoth');
190
+ const result = await mammoth.convertToHtml({ arrayBuffer });
191
+ return result.value;
192
+ }
193
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: WordRendererService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
194
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: WordRendererService, providedIn: 'root' });
195
+ }
196
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: WordRendererService, decorators: [{
197
+ type: Injectable,
198
+ args: [{ providedIn: 'root' }]
199
+ }] });
200
+
201
+ class WordRendererComponent {
202
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
203
+ size = input(120, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
204
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
205
+ error = signal(false, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
206
+ htmlContent = signal('', ...(ngDevMode ? [{ debugName: "htmlContent" }] : /* istanbul ignore next */ []));
207
+ wordService = inject(WordRendererService);
208
+ sanitizer = inject(DomSanitizer);
209
+ constructor() {
210
+ afterNextRender(() => this.render());
211
+ }
212
+ async render() {
213
+ try {
214
+ const html = await this.wordService.renderToHtml(this.url());
215
+ this.htmlContent.set(this.sanitizer.bypassSecurityTrustHtml(html));
216
+ this.loading.set(false);
217
+ }
218
+ catch {
219
+ this.loading.set(false);
220
+ this.error.set(true);
221
+ }
222
+ }
223
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: WordRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
224
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: WordRendererComponent, isStandalone: true, selector: "fp-word-renderer", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
225
+ @if (loading()) {
226
+ <div class="spinner" [style.width.px]="size()" [style.height.px]="size()">
227
+ <div class="spinner-icon"></div>
228
+ </div>
229
+ }
230
+ @if (error()) {
231
+ <div class="error" [style.width.px]="size()" [style.height.px]="size()">
232
+ <svg viewBox="0 0 64 64" width="32" height="32">
233
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
234
+ fill="#2b579a" opacity="0.12" stroke="none"/>
235
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
236
+ fill="none" stroke="#2b579a" stroke-width="2"/>
237
+ <text x="32" y="44" text-anchor="middle" fill="#2b579a"
238
+ font-size="20" font-weight="700" font-family="sans-serif">W</text>
239
+ </svg>
240
+ <span>Cannot load</span>
241
+ </div>
242
+ }
243
+ @if (!loading() && !error()) {
244
+ <div class="doc-content"
245
+ #contentEl
246
+ [style.width.px]="size()"
247
+ [style.height.px]="size()"
248
+ [innerHTML]="htmlContent()">
249
+ </div>
250
+ }
251
+ `, isInline: true, styles: [":host{display:block;overflow:hidden;line-height:0}.doc-content{overflow:hidden;padding:8px;font-size:4px;line-height:1.4;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;color:#1a1a2e;background:#fff;box-sizing:border-box;pointer-events:none}.doc-content ::ng-deep p{margin:0 0 2px}.doc-content ::ng-deep h1,.doc-content ::ng-deep h2,.doc-content ::ng-deep h3,.doc-content ::ng-deep h4,.doc-content ::ng-deep h5,.doc-content ::ng-deep h6{margin:2px 0 1px;font-size:6px}.doc-content ::ng-deep h1{font-size:8px}.doc-content ::ng-deep h2{font-size:7px}.doc-content ::ng-deep img{max-width:100%;height:auto}.doc-content ::ng-deep table{width:100%;border-collapse:collapse;font-size:3px}.doc-content ::ng-deep table td,.doc-content ::ng-deep table th{border:.5px solid #d1d5db;padding:1px}.doc-content ::ng-deep ul,.doc-content ::ng-deep ol{margin:0;padding-left:6px}.spinner,.error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8)}.spinner-icon{width:24px;height:24px;border:3px solid #e2e2e5;border-top-color:#2b579a;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{color:#2b579a;font-size:11px;font-family:sans-serif}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
252
+ }
253
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: WordRendererComponent, decorators: [{
254
+ type: Component,
255
+ args: [{ selector: 'fp-word-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
256
+ @if (loading()) {
257
+ <div class="spinner" [style.width.px]="size()" [style.height.px]="size()">
258
+ <div class="spinner-icon"></div>
259
+ </div>
260
+ }
261
+ @if (error()) {
262
+ <div class="error" [style.width.px]="size()" [style.height.px]="size()">
263
+ <svg viewBox="0 0 64 64" width="32" height="32">
264
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
265
+ fill="#2b579a" opacity="0.12" stroke="none"/>
266
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
267
+ fill="none" stroke="#2b579a" stroke-width="2"/>
268
+ <text x="32" y="44" text-anchor="middle" fill="#2b579a"
269
+ font-size="20" font-weight="700" font-family="sans-serif">W</text>
270
+ </svg>
271
+ <span>Cannot load</span>
272
+ </div>
273
+ }
274
+ @if (!loading() && !error()) {
275
+ <div class="doc-content"
276
+ #contentEl
277
+ [style.width.px]="size()"
278
+ [style.height.px]="size()"
279
+ [innerHTML]="htmlContent()">
280
+ </div>
281
+ }
282
+ `, styles: [":host{display:block;overflow:hidden;line-height:0}.doc-content{overflow:hidden;padding:8px;font-size:4px;line-height:1.4;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;color:#1a1a2e;background:#fff;box-sizing:border-box;pointer-events:none}.doc-content ::ng-deep p{margin:0 0 2px}.doc-content ::ng-deep h1,.doc-content ::ng-deep h2,.doc-content ::ng-deep h3,.doc-content ::ng-deep h4,.doc-content ::ng-deep h5,.doc-content ::ng-deep h6{margin:2px 0 1px;font-size:6px}.doc-content ::ng-deep h1{font-size:8px}.doc-content ::ng-deep h2{font-size:7px}.doc-content ::ng-deep img{max-width:100%;height:auto}.doc-content ::ng-deep table{width:100%;border-collapse:collapse;font-size:3px}.doc-content ::ng-deep table td,.doc-content ::ng-deep table th{border:.5px solid #d1d5db;padding:1px}.doc-content ::ng-deep ul,.doc-content ::ng-deep ol{margin:0;padding-left:6px}.spinner,.error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8)}.spinner-icon{width:24px;height:24px;border:3px solid #e2e2e5;border-top-color:#2b579a;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{color:#2b579a;font-size:11px;font-family:sans-serif}\n"] }]
283
+ }], ctorParameters: () => [], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
284
+
285
+ class ExcelRendererService {
286
+ async renderToTable(url) {
287
+ const response = await fetch(url);
288
+ const arrayBuffer = await response.arrayBuffer();
289
+ const XLSX = await import('xlsx');
290
+ const workbook = XLSX.read(arrayBuffer, { type: 'array' });
291
+ const firstSheetName = workbook.SheetNames[0];
292
+ const sheet = workbook.Sheets[firstSheetName];
293
+ const json = XLSX.utils.sheet_to_json(sheet, { header: 1 });
294
+ if (json.length === 0) {
295
+ return { headers: [], rows: [] };
296
+ }
297
+ const headers = (json[0] ?? []).map(cell => String(cell ?? ''));
298
+ const rows = json.slice(1, 20).map(row => headers.map((_, i) => String(row[i] ?? '')));
299
+ return { headers, rows };
300
+ }
301
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ExcelRendererService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
302
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ExcelRendererService, providedIn: 'root' });
303
+ }
304
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ExcelRendererService, decorators: [{
305
+ type: Injectable,
306
+ args: [{ providedIn: 'root' }]
307
+ }] });
308
+
309
+ class ExcelRendererComponent {
310
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
311
+ size = input(120, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
312
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
313
+ error = signal(false, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
314
+ sheetData = signal(null, ...(ngDevMode ? [{ debugName: "sheetData" }] : /* istanbul ignore next */ []));
315
+ excelService = inject(ExcelRendererService);
316
+ constructor() {
317
+ afterNextRender(() => this.render());
318
+ }
319
+ async render() {
320
+ try {
321
+ const data = await this.excelService.renderToTable(this.url());
322
+ this.sheetData.set(data);
323
+ this.loading.set(false);
324
+ }
325
+ catch {
326
+ this.loading.set(false);
327
+ this.error.set(true);
328
+ }
329
+ }
330
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ExcelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: ExcelRendererComponent, isStandalone: true, selector: "fp-excel-renderer", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
332
+ @if (loading()) {
333
+ <div class="spinner" [style.width.px]="size()" [style.height.px]="size()">
334
+ <div class="spinner-icon"></div>
335
+ </div>
336
+ }
337
+ @if (error()) {
338
+ <div class="error" [style.width.px]="size()" [style.height.px]="size()">
339
+ <svg viewBox="0 0 64 64" width="32" height="32">
340
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
341
+ fill="#217346" opacity="0.12" stroke="none"/>
342
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
343
+ fill="none" stroke="#217346" stroke-width="2"/>
344
+ <text x="32" y="44" text-anchor="middle" fill="#217346"
345
+ font-size="20" font-weight="700" font-family="sans-serif">X</text>
346
+ </svg>
347
+ <span>Cannot load</span>
348
+ </div>
349
+ }
350
+ @if (!loading() && !error() && sheetData()) {
351
+ <div class="table-wrapper" [style.width.px]="size()" [style.height.px]="size()">
352
+ <table>
353
+ @if (sheetData()!.headers.length > 0) {
354
+ <thead>
355
+ <tr>
356
+ @for (header of sheetData()!.headers; track $index) {
357
+ <th>{{ header }}</th>
358
+ }
359
+ </tr>
360
+ </thead>
361
+ }
362
+ <tbody>
363
+ @for (row of sheetData()!.rows; track $index) {
364
+ <tr>
365
+ @for (cell of row; track $index) {
366
+ <td>{{ cell }}</td>
367
+ }
368
+ </tr>
369
+ }
370
+ </tbody>
371
+ </table>
372
+ </div>
373
+ }
374
+ `, isInline: true, styles: [":host{display:block;overflow:hidden;line-height:0}.table-wrapper{overflow:hidden;padding:4px;background:#fff;box-sizing:border-box;pointer-events:none}table{width:100%;border-collapse:collapse;font-size:4px;line-height:1.3;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;color:#1a1a2e}thead{background:#217346;color:#fff}thead th{padding:1.5px 2px;font-weight:600;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40px;border:.5px solid #1a5c37}tbody tr:nth-child(2n){background:#f0faf4}tbody td{padding:1px 2px;border:.5px solid #d1d5db;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40px}.spinner,.error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8)}.spinner-icon{width:24px;height:24px;border:3px solid #e2e2e5;border-top-color:#217346;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{color:#217346;font-size:11px;font-family:sans-serif}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
375
+ }
376
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ExcelRendererComponent, decorators: [{
377
+ type: Component,
378
+ args: [{ selector: 'fp-excel-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
379
+ @if (loading()) {
380
+ <div class="spinner" [style.width.px]="size()" [style.height.px]="size()">
381
+ <div class="spinner-icon"></div>
382
+ </div>
383
+ }
384
+ @if (error()) {
385
+ <div class="error" [style.width.px]="size()" [style.height.px]="size()">
386
+ <svg viewBox="0 0 64 64" width="32" height="32">
387
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
388
+ fill="#217346" opacity="0.12" stroke="none"/>
389
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
390
+ fill="none" stroke="#217346" stroke-width="2"/>
391
+ <text x="32" y="44" text-anchor="middle" fill="#217346"
392
+ font-size="20" font-weight="700" font-family="sans-serif">X</text>
393
+ </svg>
394
+ <span>Cannot load</span>
395
+ </div>
396
+ }
397
+ @if (!loading() && !error() && sheetData()) {
398
+ <div class="table-wrapper" [style.width.px]="size()" [style.height.px]="size()">
399
+ <table>
400
+ @if (sheetData()!.headers.length > 0) {
401
+ <thead>
402
+ <tr>
403
+ @for (header of sheetData()!.headers; track $index) {
404
+ <th>{{ header }}</th>
405
+ }
406
+ </tr>
407
+ </thead>
408
+ }
409
+ <tbody>
410
+ @for (row of sheetData()!.rows; track $index) {
411
+ <tr>
412
+ @for (cell of row; track $index) {
413
+ <td>{{ cell }}</td>
414
+ }
415
+ </tr>
416
+ }
417
+ </tbody>
418
+ </table>
419
+ </div>
420
+ }
421
+ `, styles: [":host{display:block;overflow:hidden;line-height:0}.table-wrapper{overflow:hidden;padding:4px;background:#fff;box-sizing:border-box;pointer-events:none}table{width:100%;border-collapse:collapse;font-size:4px;line-height:1.3;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;color:#1a1a2e}thead{background:#217346;color:#fff}thead th{padding:1.5px 2px;font-weight:600;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40px;border:.5px solid #1a5c37}tbody tr:nth-child(2n){background:#f0faf4}tbody td{padding:1px 2px;border:.5px solid #d1d5db;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40px}.spinner,.error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8)}.spinner-icon{width:24px;height:24px;border:3px solid #e2e2e5;border-top-color:#217346;border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{color:#217346;font-size:11px;font-family:sans-serif}\n"] }]
422
+ }], ctorParameters: () => [], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
423
+
424
+ const META = {
425
+ [FileType.Word]: { label: 'Word Document', color: '#2b579a', letter: 'W' },
426
+ [FileType.Excel]: { label: 'Excel Spreadsheet', color: '#217346', letter: 'X' },
427
+ [FileType.Unknown]: { label: 'File', color: '#6b7280', letter: '?' },
428
+ };
429
+ class PlaceholderRendererComponent {
430
+ fileType = input(FileType.Unknown, ...(ngDevMode ? [{ debugName: "fileType" }] : /* istanbul ignore next */ []));
431
+ size = input(120, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
432
+ meta = computed(() => META[this.fileType()] ?? META[FileType.Unknown], ...(ngDevMode ? [{ debugName: "meta" }] : /* istanbul ignore next */ []));
433
+ iconSize = computed(() => Math.round(this.size() * 0.45), ...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
434
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PlaceholderRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
435
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.6", type: PlaceholderRendererComponent, isStandalone: true, selector: "fp-placeholder-renderer", inputs: { fileType: { classPropertyName: "fileType", publicName: "fileType", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
436
+ <div class="placeholder" [style.width.px]="size()" [style.height.px]="size()">
437
+ <svg viewBox="0 0 64 64" [attr.width]="iconSize()" [attr.height]="iconSize()">
438
+ <!-- File shape -->
439
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
440
+ [attr.fill]="meta().color" opacity="0.12" stroke="none"/>
441
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
442
+ fill="none" [attr.stroke]="meta().color" stroke-width="2"/>
443
+ <!-- Folded corner -->
444
+ <path d="M38 4v10a4 4 0 0 0 4 4h10" fill="none" [attr.stroke]="meta().color" stroke-width="2"/>
445
+ <!-- Letter -->
446
+ <text x="32" y="44" text-anchor="middle" [attr.fill]="meta().color"
447
+ font-size="20" font-weight="700" font-family="sans-serif">
448
+ {{ meta().letter }}
449
+ </text>
450
+ </svg>
451
+ <span class="label" [style.color]="meta().color">{{ meta().label }}</span>
452
+ </div>
453
+ `, isInline: true, styles: [":host{display:block;overflow:hidden}.placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8);border-radius:var(--ngx-fp-border-radius, 8px)}.label{font-size:11px;font-weight:600;font-family:sans-serif;text-align:center;line-height:1.2}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
454
+ }
455
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PlaceholderRendererComponent, decorators: [{
456
+ type: Component,
457
+ args: [{ selector: 'fp-placeholder-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
458
+ <div class="placeholder" [style.width.px]="size()" [style.height.px]="size()">
459
+ <svg viewBox="0 0 64 64" [attr.width]="iconSize()" [attr.height]="iconSize()">
460
+ <!-- File shape -->
461
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
462
+ [attr.fill]="meta().color" opacity="0.12" stroke="none"/>
463
+ <path d="M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z"
464
+ fill="none" [attr.stroke]="meta().color" stroke-width="2"/>
465
+ <!-- Folded corner -->
466
+ <path d="M38 4v10a4 4 0 0 0 4 4h10" fill="none" [attr.stroke]="meta().color" stroke-width="2"/>
467
+ <!-- Letter -->
468
+ <text x="32" y="44" text-anchor="middle" [attr.fill]="meta().color"
469
+ font-size="20" font-weight="700" font-family="sans-serif">
470
+ {{ meta().letter }}
471
+ </text>
472
+ </svg>
473
+ <span class="label" [style.color]="meta().color">{{ meta().label }}</span>
474
+ </div>
475
+ `, styles: [":host{display:block;overflow:hidden}.placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:var(--ngx-fp-placeholder-bg, #f7f7f8);border-radius:var(--ngx-fp-border-radius, 8px)}.label{font-size:11px;font-weight:600;font-family:sans-serif;text-align:center;line-height:1.2}\n"] }]
476
+ }], propDecorators: { fileType: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileType", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
477
+
478
+ class FileThumbnailComponent {
479
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
480
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
481
+ tooltip = input(false, ...(ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []));
482
+ fileTypeService = inject(FileTypeService);
483
+ fileType = computed(() => this.fileTypeService.detectType(this.url()), ...(ngDevMode ? [{ debugName: "fileType" }] : /* istanbul ignore next */ []));
484
+ pixelSize = computed(() => THUMBNAIL_SIZE_MAP[this.size()], ...(ngDevMode ? [{ debugName: "pixelSize" }] : /* istanbul ignore next */ []));
485
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FileThumbnailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
486
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FileThumbnailComponent, isStandalone: true, selector: "fp-file-thumbnail", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"thumbnail-wrapper\"\r\n [style.width.px]=\"pixelSize()\"\r\n [style.height.px]=\"pixelSize()\">\r\n @switch (fileType()) {\r\n @case ('image') {\r\n <fp-image-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('pdf') {\r\n <fp-pdf-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('word') {\r\n <fp-word-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('excel') {\r\n <fp-excel-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @default {\r\n <fp-placeholder-renderer [fileType]=\"fileType()\" [size]=\"pixelSize()\" />\r\n }\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.thumbnail-wrapper{overflow:hidden;border-radius:var(--ngx-fp-border-radius, 8px);border:1px solid var(--ngx-fp-border-color, #e2e2e5);background:var(--ngx-fp-bg, #ffffff)}\n"], dependencies: [{ kind: "component", type: ImageRendererComponent, selector: "fp-image-renderer", inputs: ["url", "size"] }, { kind: "component", type: PdfRendererComponent, selector: "fp-pdf-renderer", inputs: ["url", "size"] }, { kind: "component", type: WordRendererComponent, selector: "fp-word-renderer", inputs: ["url", "size"] }, { kind: "component", type: ExcelRendererComponent, selector: "fp-excel-renderer", inputs: ["url", "size"] }, { kind: "component", type: PlaceholderRendererComponent, selector: "fp-placeholder-renderer", inputs: ["fileType", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
487
+ }
488
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FileThumbnailComponent, decorators: [{
489
+ type: Component,
490
+ args: [{ selector: 'fp-file-thumbnail', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
491
+ ImageRendererComponent,
492
+ PdfRendererComponent,
493
+ WordRendererComponent,
494
+ ExcelRendererComponent,
495
+ PlaceholderRendererComponent,
496
+ ], template: "<div class=\"thumbnail-wrapper\"\r\n [style.width.px]=\"pixelSize()\"\r\n [style.height.px]=\"pixelSize()\">\r\n @switch (fileType()) {\r\n @case ('image') {\r\n <fp-image-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('pdf') {\r\n <fp-pdf-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('word') {\r\n <fp-word-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('excel') {\r\n <fp-excel-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @default {\r\n <fp-placeholder-renderer [fileType]=\"fileType()\" [size]=\"pixelSize()\" />\r\n }\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.thumbnail-wrapper{overflow:hidden;border-radius:var(--ngx-fp-border-radius, 8px);border:1px solid var(--ngx-fp-border-color, #e2e2e5);background:var(--ngx-fp-bg, #ffffff)}\n"] }]
497
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }] } });
498
+
499
+ class PreviewTooltipComponent {
500
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
501
+ fileType = input.required(...(ngDevMode ? [{ debugName: "fileType" }] : /* istanbul ignore next */ []));
502
+ previewSize = THUMBNAIL_SIZE_MAP.lg;
503
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PreviewTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
504
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: PreviewTooltipComponent, isStandalone: true, selector: "fp-preview-tooltip", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, fileType: { classPropertyName: "fileType", publicName: "fileType", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
505
+ <div class="tooltip-panel">
506
+ @switch (fileType()) {
507
+ @case ('image') {
508
+ <fp-image-renderer [url]="url()" [size]="previewSize" />
509
+ }
510
+ @case ('pdf') {
511
+ <fp-pdf-renderer [url]="url()" [size]="previewSize" />
512
+ }
513
+ @case ('word') {
514
+ <fp-word-renderer [url]="url()" [size]="previewSize" />
515
+ }
516
+ @case ('excel') {
517
+ <fp-excel-renderer [url]="url()" [size]="previewSize" />
518
+ }
519
+ @default {
520
+ <fp-placeholder-renderer [fileType]="fileType()" [size]="previewSize" />
521
+ }
522
+ }
523
+ </div>
524
+ `, isInline: true, styles: [":host{display:block}.tooltip-panel{background:var(--ngx-fp-bg, #ffffff);border-radius:var(--ngx-fp-border-radius, 8px);box-shadow:0 8px 24px #00000026;overflow:hidden;animation:fadeIn .15s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "component", type: ImageRendererComponent, selector: "fp-image-renderer", inputs: ["url", "size"] }, { kind: "component", type: PdfRendererComponent, selector: "fp-pdf-renderer", inputs: ["url", "size"] }, { kind: "component", type: WordRendererComponent, selector: "fp-word-renderer", inputs: ["url", "size"] }, { kind: "component", type: ExcelRendererComponent, selector: "fp-excel-renderer", inputs: ["url", "size"] }, { kind: "component", type: PlaceholderRendererComponent, selector: "fp-placeholder-renderer", inputs: ["fileType", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
525
+ }
526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PreviewTooltipComponent, decorators: [{
527
+ type: Component,
528
+ args: [{ selector: 'fp-preview-tooltip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
529
+ ImageRendererComponent,
530
+ PdfRendererComponent,
531
+ WordRendererComponent,
532
+ ExcelRendererComponent,
533
+ PlaceholderRendererComponent,
534
+ ], template: `
535
+ <div class="tooltip-panel">
536
+ @switch (fileType()) {
537
+ @case ('image') {
538
+ <fp-image-renderer [url]="url()" [size]="previewSize" />
539
+ }
540
+ @case ('pdf') {
541
+ <fp-pdf-renderer [url]="url()" [size]="previewSize" />
542
+ }
543
+ @case ('word') {
544
+ <fp-word-renderer [url]="url()" [size]="previewSize" />
545
+ }
546
+ @case ('excel') {
547
+ <fp-excel-renderer [url]="url()" [size]="previewSize" />
548
+ }
549
+ @default {
550
+ <fp-placeholder-renderer [fileType]="fileType()" [size]="previewSize" />
551
+ }
552
+ }
553
+ </div>
554
+ `, styles: [":host{display:block}.tooltip-panel{background:var(--ngx-fp-bg, #ffffff);border-radius:var(--ngx-fp-border-radius, 8px);box-shadow:0 8px 24px #00000026;overflow:hidden;animation:fadeIn .15s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
555
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], fileType: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileType", required: true }] }] } });
556
+
557
+ class FilePreviewTooltipDirective {
558
+ filePreviewTooltip = input.required(...(ngDevMode ? [{ debugName: "filePreviewTooltip" }] : /* istanbul ignore next */ []));
559
+ overlay = inject(Overlay);
560
+ elementRef = inject(ElementRef);
561
+ viewContainerRef = inject(ViewContainerRef);
562
+ fileTypeService = inject(FileTypeService);
563
+ config = inject(FILE_PREVIEW_CONFIG);
564
+ overlayRef = null;
565
+ delayTimer = null;
566
+ onMouseEnter() {
567
+ const delay = this.config.tooltipDelay ?? 300;
568
+ this.delayTimer = setTimeout(() => this.show(), delay);
569
+ }
570
+ onMouseLeave() {
571
+ this.clearTimer();
572
+ this.hide();
573
+ }
574
+ ngOnDestroy() {
575
+ this.clearTimer();
576
+ this.hide();
577
+ }
578
+ show() {
579
+ if (this.overlayRef)
580
+ return;
581
+ const positionStrategy = this.overlay
582
+ .position()
583
+ .flexibleConnectedTo(this.elementRef)
584
+ .withPositions([
585
+ { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -8 },
586
+ { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 8 },
587
+ ]);
588
+ this.overlayRef = this.overlay.create({
589
+ positionStrategy,
590
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
591
+ panelClass: 'fp-tooltip-panel',
592
+ });
593
+ const portal = new ComponentPortal(PreviewTooltipComponent, this.viewContainerRef);
594
+ const componentRef = this.overlayRef.attach(portal);
595
+ const url = this.filePreviewTooltip();
596
+ componentRef.setInput('url', url);
597
+ componentRef.setInput('fileType', this.fileTypeService.detectType(url));
598
+ }
599
+ hide() {
600
+ if (this.overlayRef) {
601
+ this.overlayRef.detach();
602
+ this.overlayRef.dispose();
603
+ this.overlayRef = null;
604
+ }
605
+ }
606
+ clearTimer() {
607
+ if (this.delayTimer !== null) {
608
+ clearTimeout(this.delayTimer);
609
+ this.delayTimer = null;
610
+ }
611
+ }
612
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FilePreviewTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
613
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.6", type: FilePreviewTooltipDirective, isStandalone: true, selector: "[filePreviewTooltip]", inputs: { filePreviewTooltip: { classPropertyName: "filePreviewTooltip", publicName: "filePreviewTooltip", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, ngImport: i0 });
614
+ }
615
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FilePreviewTooltipDirective, decorators: [{
616
+ type: Directive,
617
+ args: [{
618
+ selector: '[filePreviewTooltip]',
619
+ standalone: true,
620
+ host: {
621
+ '(mouseenter)': 'onMouseEnter()',
622
+ '(mouseleave)': 'onMouseLeave()',
623
+ },
624
+ }]
625
+ }], propDecorators: { filePreviewTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "filePreviewTooltip", required: true }] }] } });
626
+
627
+ /*
628
+ * Public API Surface of ngx-file-preview
629
+ */
630
+
631
+ /**
632
+ * Generated bundle index. Do not edit.
633
+ */
634
+
635
+ export { FilePreviewTooltipDirective, FileThumbnailComponent, FileType, provideFilePreview };
636
+ //# sourceMappingURL=ngx-file-peek.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-file-peek.mjs","sources":["../../../projects/ngx-file-peek/src/lib/models/file-preview.models.ts","../../../projects/ngx-file-peek/src/lib/services/file-type.service.ts","../../../projects/ngx-file-peek/src/lib/components/renderers/image-renderer/image-renderer.component.ts","../../../projects/ngx-file-peek/src/lib/models/file-preview.tokens.ts","../../../projects/ngx-file-peek/src/lib/services/pdf-renderer.service.ts","../../../projects/ngx-file-peek/src/lib/components/renderers/pdf-renderer/pdf-renderer.component.ts","../../../projects/ngx-file-peek/src/lib/services/word-renderer.service.ts","../../../projects/ngx-file-peek/src/lib/components/renderers/word-renderer/word-renderer.component.ts","../../../projects/ngx-file-peek/src/lib/services/excel-renderer.service.ts","../../../projects/ngx-file-peek/src/lib/components/renderers/excel-renderer/excel-renderer.component.ts","../../../projects/ngx-file-peek/src/lib/components/renderers/placeholder-renderer/placeholder-renderer.component.ts","../../../projects/ngx-file-peek/src/lib/components/file-thumbnail/file-thumbnail.component.ts","../../../projects/ngx-file-peek/src/lib/components/file-thumbnail/file-thumbnail.component.html","../../../projects/ngx-file-peek/src/lib/components/preview-tooltip/preview-tooltip.component.ts","../../../projects/ngx-file-peek/src/lib/directives/file-preview-tooltip.directive.ts","../../../projects/ngx-file-peek/src/public-api.ts","../../../projects/ngx-file-peek/src/ngx-file-peek.ts"],"sourcesContent":["export enum FileType {\r\n Image = 'image',\r\n Pdf = 'pdf',\r\n Word = 'word',\r\n Excel = 'excel',\r\n Unknown = 'unknown',\r\n}\r\n\r\nexport type ThumbnailSize = 'sm' | 'md' | 'lg';\r\n\r\nexport const THUMBNAIL_SIZE_MAP: Record<ThumbnailSize, number> = {\r\n sm: 80,\r\n md: 120,\r\n lg: 200,\r\n};\r\n\r\nexport interface FilePreviewConfig {\r\n pdfWorkerUrl?: string;\r\n tooltipDelay?: number;\r\n placeholderTheme?: 'minimal' | 'branded';\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { FileType } from '../models/file-preview.models';\r\n\r\nconst EXTENSION_MAP: Record<string, FileType> = {\r\n jpg: FileType.Image,\r\n jpeg: FileType.Image,\r\n png: FileType.Image,\r\n gif: FileType.Image,\r\n webp: FileType.Image,\r\n svg: FileType.Image,\r\n bmp: FileType.Image,\r\n pdf: FileType.Pdf,\r\n doc: FileType.Word,\r\n docx: FileType.Word,\r\n xls: FileType.Excel,\r\n xlsx: FileType.Excel,\r\n};\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class FileTypeService {\r\n detectType(url: string): FileType {\r\n try {\r\n const parsed = new URL(url, 'https://placeholder.local');\r\n const pathname = parsed.pathname;\r\n const lastDot = pathname.lastIndexOf('.');\r\n if (lastDot === -1) return FileType.Unknown;\r\n const ext = pathname.substring(lastDot + 1).toLowerCase();\r\n return EXTENSION_MAP[ext] ?? FileType.Unknown;\r\n } catch {\r\n return FileType.Unknown;\r\n }\r\n }\r\n}\r\n","import { Component, ChangeDetectionStrategy, input } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'fp-image-renderer',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <img\r\n [src]=\"url()\"\r\n [width]=\"size()\"\r\n [height]=\"size()\"\r\n loading=\"lazy\"\r\n alt=\"File preview\"\r\n />\r\n `,\r\n styleUrl: './image-renderer.component.scss',\r\n})\r\nexport class ImageRendererComponent {\r\n url = input.required<string>();\r\n size = input<number>(120);\r\n}\r\n","import { InjectionToken, Provider } from '@angular/core';\r\nimport { FilePreviewConfig } from './file-preview.models';\r\n\r\nconst DEFAULT_CONFIG: FilePreviewConfig = {\r\n tooltipDelay: 300,\r\n placeholderTheme: 'minimal',\r\n};\r\n\r\nexport const FILE_PREVIEW_CONFIG = new InjectionToken<FilePreviewConfig>(\r\n 'FILE_PREVIEW_CONFIG',\r\n { factory: () => DEFAULT_CONFIG }\r\n);\r\n\r\nexport function provideFilePreview(config: Partial<FilePreviewConfig> = {}): Provider {\r\n return { provide: FILE_PREVIEW_CONFIG, useValue: { ...DEFAULT_CONFIG, ...config } };\r\n}\r\n","import { inject, Injectable } from '@angular/core';\r\nimport { FILE_PREVIEW_CONFIG } from '../models/file-preview.tokens';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class PdfRendererService {\r\n private readonly config = inject(FILE_PREVIEW_CONFIG);\r\n\r\n async renderFirstPage(url: string, canvas: HTMLCanvasElement, maxSize: number): Promise<void> {\r\n const pdfjs = await import('pdfjs-dist');\r\n\r\n if (this.config.pdfWorkerUrl) {\r\n pdfjs.GlobalWorkerOptions.workerSrc = this.config.pdfWorkerUrl;\r\n }\r\n\r\n const pdf = await pdfjs.getDocument(url).promise;\r\n const page = await pdf.getPage(1);\r\n\r\n const unscaledViewport = page.getViewport({ scale: 1 });\r\n const scale = maxSize / Math.max(unscaledViewport.width, unscaledViewport.height);\r\n const viewport = page.getViewport({ scale });\r\n\r\n canvas.width = viewport.width;\r\n canvas.height = viewport.height;\r\n\r\n await page.render({ canvas, viewport }).promise;\r\n }\r\n}\r\n","import {\r\n Component,\r\n ChangeDetectionStrategy,\r\n input,\r\n inject,\r\n viewChild,\r\n ElementRef,\r\n signal,\r\n afterNextRender,\r\n} from '@angular/core';\r\nimport { PdfRendererService } from '../../../services/pdf-renderer.service';\r\n\r\n@Component({\r\n selector: 'fp-pdf-renderer',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n @if (loading()) {\r\n <div class=\"spinner\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <div class=\"spinner-icon\"></div>\r\n </div>\r\n }\r\n @if (error()) {\r\n <div class=\"error\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <svg viewBox=\"0 0 24 24\" width=\"32\" height=\"32\" fill=\"none\" stroke=\"#e53e3e\" stroke-width=\"2\">\r\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/>\r\n <polyline points=\"14 2 14 8 20 8\"/>\r\n <line x1=\"12\" y1=\"12\" x2=\"12\" y2=\"16\"/>\r\n <circle cx=\"12\" cy=\"18\" r=\"0.5\"/>\r\n </svg>\r\n <span>PDF Error</span>\r\n </div>\r\n }\r\n <canvas #pdfCanvas [style.display]=\"loading() || error() ? 'none' : 'block'\"></canvas>\r\n `,\r\n styleUrl: './pdf-renderer.component.scss',\r\n})\r\nexport class PdfRendererComponent {\r\n url = input.required<string>();\r\n size = input<number>(120);\r\n\r\n loading = signal(true);\r\n error = signal(false);\r\n\r\n private readonly pdfService = inject(PdfRendererService);\r\n private readonly canvasRef = viewChild<ElementRef<HTMLCanvasElement>>('pdfCanvas');\r\n\r\n constructor() {\r\n afterNextRender(() => this.render());\r\n }\r\n\r\n private async render(): Promise<void> {\r\n const canvasEl = this.canvasRef()?.nativeElement;\r\n if (!canvasEl) return;\r\n\r\n try {\r\n await this.pdfService.renderFirstPage(this.url(), canvasEl, this.size());\r\n this.loading.set(false);\r\n } catch {\r\n this.loading.set(false);\r\n this.error.set(true);\r\n }\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class WordRendererService {\r\n async renderToHtml(url: string): Promise<string> {\r\n const response = await fetch(url);\r\n const arrayBuffer = await response.arrayBuffer();\r\n const mammoth = await import('mammoth');\r\n const result = await mammoth.convertToHtml({ arrayBuffer });\r\n return result.value;\r\n }\r\n}\r\n","import {\r\n Component,\r\n ChangeDetectionStrategy,\r\n input,\r\n inject,\r\n signal,\r\n afterNextRender,\r\n ElementRef,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { WordRendererService } from '../../../services/word-renderer.service';\r\n\r\n@Component({\r\n selector: 'fp-word-renderer',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n @if (loading()) {\r\n <div class=\"spinner\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <div class=\"spinner-icon\"></div>\r\n </div>\r\n }\r\n @if (error()) {\r\n <div class=\"error\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <svg viewBox=\"0 0 64 64\" width=\"32\" height=\"32\">\r\n <path d=\"M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z\"\r\n fill=\"#2b579a\" opacity=\"0.12\" stroke=\"none\"/>\r\n <path d=\"M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z\"\r\n fill=\"none\" stroke=\"#2b579a\" stroke-width=\"2\"/>\r\n <text x=\"32\" y=\"44\" text-anchor=\"middle\" fill=\"#2b579a\"\r\n font-size=\"20\" font-weight=\"700\" font-family=\"sans-serif\">W</text>\r\n </svg>\r\n <span>Cannot load</span>\r\n </div>\r\n }\r\n @if (!loading() && !error()) {\r\n <div class=\"doc-content\"\r\n #contentEl\r\n [style.width.px]=\"size()\"\r\n [style.height.px]=\"size()\"\r\n [innerHTML]=\"htmlContent()\">\r\n </div>\r\n }\r\n `,\r\n styleUrl: './word-renderer.component.scss',\r\n})\r\nexport class WordRendererComponent {\r\n url = input.required<string>();\r\n size = input<number>(120);\r\n\r\n loading = signal(true);\r\n error = signal(false);\r\n htmlContent = signal<SafeHtml>('');\r\n\r\n private readonly wordService = inject(WordRendererService);\r\n private readonly sanitizer = inject(DomSanitizer);\r\n\r\n constructor() {\r\n afterNextRender(() => this.render());\r\n }\r\n\r\n private async render(): Promise<void> {\r\n try {\r\n const html = await this.wordService.renderToHtml(this.url());\r\n this.htmlContent.set(this.sanitizer.bypassSecurityTrustHtml(html));\r\n this.loading.set(false);\r\n } catch {\r\n this.loading.set(false);\r\n this.error.set(true);\r\n }\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\nexport interface SheetData {\r\n headers: string[];\r\n rows: string[][];\r\n}\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class ExcelRendererService {\r\n async renderToTable(url: string): Promise<SheetData> {\r\n const response = await fetch(url);\r\n const arrayBuffer = await response.arrayBuffer();\r\n const XLSX = await import('xlsx');\r\n const workbook = XLSX.read(arrayBuffer, { type: 'array' });\r\n const firstSheetName = workbook.SheetNames[0];\r\n const sheet = workbook.Sheets[firstSheetName];\r\n const json: string[][] = XLSX.utils.sheet_to_json(sheet, { header: 1 });\r\n\r\n if (json.length === 0) {\r\n return { headers: [], rows: [] };\r\n }\r\n\r\n const headers = (json[0] ?? []).map(cell => String(cell ?? ''));\r\n const rows = json.slice(1, 20).map(row =>\r\n headers.map((_, i) => String(row[i] ?? ''))\r\n );\r\n\r\n return { headers, rows };\r\n }\r\n}\r\n","import {\r\n Component,\r\n ChangeDetectionStrategy,\r\n input,\r\n inject,\r\n signal,\r\n afterNextRender,\r\n} from '@angular/core';\r\nimport { ExcelRendererService, SheetData } from '../../../services/excel-renderer.service';\r\n\r\n@Component({\r\n selector: 'fp-excel-renderer',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n @if (loading()) {\r\n <div class=\"spinner\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <div class=\"spinner-icon\"></div>\r\n </div>\r\n }\r\n @if (error()) {\r\n <div class=\"error\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <svg viewBox=\"0 0 64 64\" width=\"32\" height=\"32\">\r\n <path d=\"M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z\"\r\n fill=\"#217346\" opacity=\"0.12\" stroke=\"none\"/>\r\n <path d=\"M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z\"\r\n fill=\"none\" stroke=\"#217346\" stroke-width=\"2\"/>\r\n <text x=\"32\" y=\"44\" text-anchor=\"middle\" fill=\"#217346\"\r\n font-size=\"20\" font-weight=\"700\" font-family=\"sans-serif\">X</text>\r\n </svg>\r\n <span>Cannot load</span>\r\n </div>\r\n }\r\n @if (!loading() && !error() && sheetData()) {\r\n <div class=\"table-wrapper\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <table>\r\n @if (sheetData()!.headers.length > 0) {\r\n <thead>\r\n <tr>\r\n @for (header of sheetData()!.headers; track $index) {\r\n <th>{{ header }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n }\r\n <tbody>\r\n @for (row of sheetData()!.rows; track $index) {\r\n <tr>\r\n @for (cell of row; track $index) {\r\n <td>{{ cell }}</td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n `,\r\n styleUrl: './excel-renderer.component.scss',\r\n})\r\nexport class ExcelRendererComponent {\r\n url = input.required<string>();\r\n size = input<number>(120);\r\n\r\n loading = signal(true);\r\n error = signal(false);\r\n sheetData = signal<SheetData | null>(null);\r\n\r\n private readonly excelService = inject(ExcelRendererService);\r\n\r\n constructor() {\r\n afterNextRender(() => this.render());\r\n }\r\n\r\n private async render(): Promise<void> {\r\n try {\r\n const data = await this.excelService.renderToTable(this.url());\r\n this.sheetData.set(data);\r\n this.loading.set(false);\r\n } catch {\r\n this.loading.set(false);\r\n this.error.set(true);\r\n }\r\n }\r\n}\r\n","import { Component, ChangeDetectionStrategy, input, computed } from '@angular/core';\r\nimport { FileType } from '../../../models/file-preview.models';\r\n\r\ninterface PlaceholderMeta {\r\n label: string;\r\n color: string;\r\n letter: string;\r\n}\r\n\r\nconst META: Record<string, PlaceholderMeta> = {\r\n [FileType.Word]: { label: 'Word Document', color: '#2b579a', letter: 'W' },\r\n [FileType.Excel]: { label: 'Excel Spreadsheet', color: '#217346', letter: 'X' },\r\n [FileType.Unknown]: { label: 'File', color: '#6b7280', letter: '?' },\r\n};\r\n\r\n@Component({\r\n selector: 'fp-placeholder-renderer',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"placeholder\" [style.width.px]=\"size()\" [style.height.px]=\"size()\">\r\n <svg viewBox=\"0 0 64 64\" [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\">\r\n <!-- File shape -->\r\n <path d=\"M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z\"\r\n [attr.fill]=\"meta().color\" opacity=\"0.12\" stroke=\"none\"/>\r\n <path d=\"M16 4h22l14 14v38a4 4 0 0 1-4 4H16a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4z\"\r\n fill=\"none\" [attr.stroke]=\"meta().color\" stroke-width=\"2\"/>\r\n <!-- Folded corner -->\r\n <path d=\"M38 4v10a4 4 0 0 0 4 4h10\" fill=\"none\" [attr.stroke]=\"meta().color\" stroke-width=\"2\"/>\r\n <!-- Letter -->\r\n <text x=\"32\" y=\"44\" text-anchor=\"middle\" [attr.fill]=\"meta().color\"\r\n font-size=\"20\" font-weight=\"700\" font-family=\"sans-serif\">\r\n {{ meta().letter }}\r\n </text>\r\n </svg>\r\n <span class=\"label\" [style.color]=\"meta().color\">{{ meta().label }}</span>\r\n </div>\r\n `,\r\n styleUrl: './placeholder-renderer.component.scss',\r\n})\r\nexport class PlaceholderRendererComponent {\r\n fileType = input<FileType>(FileType.Unknown);\r\n size = input<number>(120);\r\n\r\n meta = computed<PlaceholderMeta>(() => META[this.fileType()] ?? META[FileType.Unknown]);\r\n iconSize = computed(() => Math.round(this.size() * 0.45));\r\n}\r\n","import { Component, ChangeDetectionStrategy, input, computed, inject } from '@angular/core';\r\nimport { FileType, ThumbnailSize, THUMBNAIL_SIZE_MAP } from '../../models/file-preview.models';\r\nimport { FileTypeService } from '../../services/file-type.service';\r\nimport { ImageRendererComponent } from '../renderers/image-renderer/image-renderer.component';\r\nimport { PdfRendererComponent } from '../renderers/pdf-renderer/pdf-renderer.component';\r\nimport { WordRendererComponent } from '../renderers/word-renderer/word-renderer.component';\r\nimport { ExcelRendererComponent } from '../renderers/excel-renderer/excel-renderer.component';\r\nimport { PlaceholderRendererComponent } from '../renderers/placeholder-renderer/placeholder-renderer.component';\r\n\r\n@Component({\r\n selector: 'fp-file-thumbnail',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [\r\n ImageRendererComponent,\r\n PdfRendererComponent,\r\n WordRendererComponent,\r\n ExcelRendererComponent,\r\n PlaceholderRendererComponent,\r\n ],\r\n templateUrl: './file-thumbnail.component.html',\r\n styleUrl: './file-thumbnail.component.scss',\r\n})\r\nexport class FileThumbnailComponent {\r\n url = input.required<string>();\r\n size = input<ThumbnailSize>('md');\r\n tooltip = input<boolean>(false);\r\n\r\n private readonly fileTypeService = inject(FileTypeService);\r\n\r\n fileType = computed(() => this.fileTypeService.detectType(this.url()));\r\n pixelSize = computed(() => THUMBNAIL_SIZE_MAP[this.size()]);\r\n}\r\n","<div class=\"thumbnail-wrapper\"\r\n [style.width.px]=\"pixelSize()\"\r\n [style.height.px]=\"pixelSize()\">\r\n @switch (fileType()) {\r\n @case ('image') {\r\n <fp-image-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('pdf') {\r\n <fp-pdf-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('word') {\r\n <fp-word-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @case ('excel') {\r\n <fp-excel-renderer [url]=\"url()\" [size]=\"pixelSize()\" />\r\n }\r\n @default {\r\n <fp-placeholder-renderer [fileType]=\"fileType()\" [size]=\"pixelSize()\" />\r\n }\r\n }\r\n</div>\r\n","import { Component, ChangeDetectionStrategy, input } from '@angular/core';\r\nimport { FileType, THUMBNAIL_SIZE_MAP } from '../../models/file-preview.models';\r\nimport { ImageRendererComponent } from '../renderers/image-renderer/image-renderer.component';\r\nimport { PdfRendererComponent } from '../renderers/pdf-renderer/pdf-renderer.component';\r\nimport { WordRendererComponent } from '../renderers/word-renderer/word-renderer.component';\r\nimport { ExcelRendererComponent } from '../renderers/excel-renderer/excel-renderer.component';\r\nimport { PlaceholderRendererComponent } from '../renderers/placeholder-renderer/placeholder-renderer.component';\r\n\r\n@Component({\r\n selector: 'fp-preview-tooltip',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [\r\n ImageRendererComponent,\r\n PdfRendererComponent,\r\n WordRendererComponent,\r\n ExcelRendererComponent,\r\n PlaceholderRendererComponent,\r\n ],\r\n template: `\r\n <div class=\"tooltip-panel\">\r\n @switch (fileType()) {\r\n @case ('image') {\r\n <fp-image-renderer [url]=\"url()\" [size]=\"previewSize\" />\r\n }\r\n @case ('pdf') {\r\n <fp-pdf-renderer [url]=\"url()\" [size]=\"previewSize\" />\r\n }\r\n @case ('word') {\r\n <fp-word-renderer [url]=\"url()\" [size]=\"previewSize\" />\r\n }\r\n @case ('excel') {\r\n <fp-excel-renderer [url]=\"url()\" [size]=\"previewSize\" />\r\n }\r\n @default {\r\n <fp-placeholder-renderer [fileType]=\"fileType()\" [size]=\"previewSize\" />\r\n }\r\n }\r\n </div>\r\n `,\r\n styleUrl: './preview-tooltip.component.scss',\r\n})\r\nexport class PreviewTooltipComponent {\r\n url = input.required<string>();\r\n fileType = input.required<FileType>();\r\n\r\n readonly previewSize = THUMBNAIL_SIZE_MAP.lg;\r\n}\r\n","import {\r\n Directive,\r\n ElementRef,\r\n inject,\r\n input,\r\n OnDestroy,\r\n Injector,\r\n ViewContainerRef,\r\n} from '@angular/core';\r\nimport { Overlay, OverlayRef, FlexibleConnectedPositionStrategy } from '@angular/cdk/overlay';\r\nimport { ComponentPortal } from '@angular/cdk/portal';\r\nimport { PreviewTooltipComponent } from '../components/preview-tooltip/preview-tooltip.component';\r\nimport { FileTypeService } from '../services/file-type.service';\r\nimport { FILE_PREVIEW_CONFIG } from '../models/file-preview.tokens';\r\n\r\n@Directive({\r\n selector: '[filePreviewTooltip]',\r\n standalone: true,\r\n host: {\r\n '(mouseenter)': 'onMouseEnter()',\r\n '(mouseleave)': 'onMouseLeave()',\r\n },\r\n})\r\nexport class FilePreviewTooltipDirective implements OnDestroy {\r\n filePreviewTooltip = input.required<string>();\r\n\r\n private readonly overlay = inject(Overlay);\r\n private readonly elementRef = inject(ElementRef);\r\n private readonly viewContainerRef = inject(ViewContainerRef);\r\n private readonly fileTypeService = inject(FileTypeService);\r\n private readonly config = inject(FILE_PREVIEW_CONFIG);\r\n\r\n private overlayRef: OverlayRef | null = null;\r\n private delayTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n onMouseEnter(): void {\r\n const delay = this.config.tooltipDelay ?? 300;\r\n this.delayTimer = setTimeout(() => this.show(), delay);\r\n }\r\n\r\n onMouseLeave(): void {\r\n this.clearTimer();\r\n this.hide();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.clearTimer();\r\n this.hide();\r\n }\r\n\r\n private show(): void {\r\n if (this.overlayRef) return;\r\n\r\n const positionStrategy: FlexibleConnectedPositionStrategy = this.overlay\r\n .position()\r\n .flexibleConnectedTo(this.elementRef)\r\n .withPositions([\r\n { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -8 },\r\n { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 8 },\r\n ]);\r\n\r\n this.overlayRef = this.overlay.create({\r\n positionStrategy,\r\n scrollStrategy: this.overlay.scrollStrategies.reposition(),\r\n panelClass: 'fp-tooltip-panel',\r\n });\r\n\r\n const portal = new ComponentPortal(\r\n PreviewTooltipComponent,\r\n this.viewContainerRef,\r\n );\r\n\r\n const componentRef = this.overlayRef.attach(portal);\r\n const url = this.filePreviewTooltip();\r\n componentRef.setInput('url', url);\r\n componentRef.setInput('fileType', this.fileTypeService.detectType(url));\r\n }\r\n\r\n private hide(): void {\r\n if (this.overlayRef) {\r\n this.overlayRef.detach();\r\n this.overlayRef.dispose();\r\n this.overlayRef = null;\r\n }\r\n }\r\n\r\n private clearTimer(): void {\r\n if (this.delayTimer !== null) {\r\n clearTimeout(this.delayTimer);\r\n this.delayTimer = null;\r\n }\r\n }\r\n}\r\n","/*\r\n * Public API Surface of ngx-file-preview\r\n */\r\n\r\nexport { FileThumbnailComponent } from './lib/components/file-thumbnail/file-thumbnail.component';\r\nexport { FilePreviewTooltipDirective } from './lib/directives/file-preview-tooltip.directive';\r\nexport { provideFilePreview } from './lib/models/file-preview.tokens';\r\nexport { FileType } from './lib/models/file-preview.models';\r\nexport type { ThumbnailSize, FilePreviewConfig } from './lib/models/file-preview.models';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "ngx-file-peek",
3
+ "version": "1.0.0",
4
+ "description": "Angular component that renders file content thumbnails from any URL (images, PDF, Word, Excel)",
5
+ "author": "valtonngara",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/valtonngara/ngx-file-peek"
10
+ },
11
+ "homepage": "https://github.com/valtonngara/ngx-file-peek#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/valtonngara/ngx-file-peek/issues"
14
+ },
15
+ "keywords": [
16
+ "angular",
17
+ "file-peek",
18
+ "thumbnail",
19
+ "pdf-preview",
20
+ "word-preview",
21
+ "excel-preview",
22
+ "image-preview",
23
+ "ngx",
24
+ "standalone-component"
25
+ ],
26
+ "peerDependencies": {
27
+ "@angular/common": "^21.2.0",
28
+ "@angular/core": "^21.2.0",
29
+ "@angular/cdk": "^21.2.0",
30
+ "pdfjs-dist": "^5.0.0",
31
+ "mammoth": "^1.0.0",
32
+ "xlsx": "^0.18.0"
33
+ },
34
+ "dependencies": {
35
+ "tslib": "^2.3.0"
36
+ },
37
+ "sideEffects": false,
38
+ "module": "fesm2022/ngx-file-peek.mjs",
39
+ "typings": "types/ngx-file-peek.d.ts",
40
+ "exports": {
41
+ "./package.json": {
42
+ "default": "./package.json"
43
+ },
44
+ ".": {
45
+ "types": "./types/ngx-file-peek.d.ts",
46
+ "default": "./fesm2022/ngx-file-peek.mjs"
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,51 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { OnDestroy, Provider } from '@angular/core';
3
+
4
+ declare enum FileType {
5
+ Image = "image",
6
+ Pdf = "pdf",
7
+ Word = "word",
8
+ Excel = "excel",
9
+ Unknown = "unknown"
10
+ }
11
+ type ThumbnailSize = 'sm' | 'md' | 'lg';
12
+ interface FilePreviewConfig {
13
+ pdfWorkerUrl?: string;
14
+ tooltipDelay?: number;
15
+ placeholderTheme?: 'minimal' | 'branded';
16
+ }
17
+
18
+ declare class FileThumbnailComponent {
19
+ url: _angular_core.InputSignal<string>;
20
+ size: _angular_core.InputSignal<ThumbnailSize>;
21
+ tooltip: _angular_core.InputSignal<boolean>;
22
+ private readonly fileTypeService;
23
+ fileType: _angular_core.Signal<FileType>;
24
+ pixelSize: _angular_core.Signal<number>;
25
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FileThumbnailComponent, never>;
26
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FileThumbnailComponent, "fp-file-thumbnail", never, { "url": { "alias": "url"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "tooltip": { "alias": "tooltip"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
27
+ }
28
+
29
+ declare class FilePreviewTooltipDirective implements OnDestroy {
30
+ filePreviewTooltip: _angular_core.InputSignal<string>;
31
+ private readonly overlay;
32
+ private readonly elementRef;
33
+ private readonly viewContainerRef;
34
+ private readonly fileTypeService;
35
+ private readonly config;
36
+ private overlayRef;
37
+ private delayTimer;
38
+ onMouseEnter(): void;
39
+ onMouseLeave(): void;
40
+ ngOnDestroy(): void;
41
+ private show;
42
+ private hide;
43
+ private clearTimer;
44
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FilePreviewTooltipDirective, never>;
45
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FilePreviewTooltipDirective, "[filePreviewTooltip]", never, { "filePreviewTooltip": { "alias": "filePreviewTooltip"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
46
+ }
47
+
48
+ declare function provideFilePreview(config?: Partial<FilePreviewConfig>): Provider;
49
+
50
+ export { FilePreviewTooltipDirective, FileThumbnailComponent, FileType, provideFilePreview };
51
+ export type { FilePreviewConfig, ThumbnailSize };