@forgeroute/ui 0.3.7 → 0.3.9

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/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@forgeroute/ui",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=22.0.0",
6
6
  "@angular/core": ">=22.0.0",
7
7
  "@angular/forms": ">=22.0.0",
8
8
  "@angular/router": ">=22.0.0",
9
9
  "@angular/platform-browser": ">=22.0.0",
10
- "chart.js": ">=4.0.0"
10
+ "chart.js": ">=4.0.0",
11
+ "pdfjs-dist": ">=5.0.0"
11
12
  },
12
13
  "peerDependenciesMeta": {
13
14
  "@angular/forms": {
@@ -15,6 +16,9 @@
15
16
  },
16
17
  "chart.js": {
17
18
  "optional": true
19
+ },
20
+ "pdfjs-dist": {
21
+ "optional": true
18
22
  }
19
23
  },
20
24
  "publishConfig": {
@@ -40,6 +44,10 @@
40
44
  "./charts": {
41
45
  "types": "./types/forgeroute-ui-charts.d.ts",
42
46
  "default": "./fesm2022/forgeroute-ui-charts.mjs"
47
+ },
48
+ "./pdf": {
49
+ "types": "./types/forgeroute-ui-pdf.d.ts",
50
+ "default": "./fesm2022/forgeroute-ui-pdf.mjs"
43
51
  }
44
52
  },
45
53
  "sideEffects": false,
@@ -0,0 +1,206 @@
1
+ import * as i0 from "@angular/core";
2
+ import { InjectionToken } from "@angular/core";
3
+ import { PDFDocumentProxy } from "pdfjs-dist";
4
+ /** Where pdf.js finds its worker script. Provide it once in the app (`{ provide: PDF_VIEWER_WORKER_SRC, useValue: '/assets/pdf.worker.min.mjs' }`). */
5
+ export declare const PDF_VIEWER_WORKER_SRC: InjectionToken<string>;
6
+ /** Colour of an overlay badge. */
7
+ export type PdfViewerTone = 'blue' | 'green' | 'amber' | 'red' | 'slate';
8
+ /** A labelled box drawn over a page. Positions are PDF points with the origin at the page's bottom-left corner. */
9
+ export interface PdfViewerField {
10
+ id: string;
11
+ /** 1-based page number; a field on a page that does not exist is ignored. */
12
+ page: number;
13
+ /** Bottom-left corner of the box, in PDF points. */
14
+ x: number;
15
+ y: number;
16
+ /** Size in PDF points. Without a width the box fits its label; the default height is 14. */
17
+ width?: number;
18
+ height?: number;
19
+ label: string;
20
+ tone?: PdfViewerTone;
21
+ }
22
+ export interface PdfViewerLoadedEvent {
23
+ pageCount: number;
24
+ /** Every page's size in PDF points at scale 1. */
25
+ pages: {
26
+ width: number;
27
+ height: number;
28
+ }[];
29
+ /** The loaded pdf.js document, so the host can read text content. The viewer destroys it when it is replaced or the viewer goes away. */
30
+ document: PDFDocumentProxy;
31
+ }
32
+ export interface PdfViewerRenderedEvent {
33
+ pageCount: number;
34
+ /** CSS px per PDF point of the first page. */
35
+ scale: number;
36
+ /** Displayed (CSS px) width of every page. */
37
+ pageWidths: number[];
38
+ }
39
+ type PdfJsModule = typeof import('pdfjs-dist');
40
+ type Status = 'idle' | 'loading' | 'ready' | 'error';
41
+ interface PageView {
42
+ number: number;
43
+ cssWidth: number;
44
+ cssHeight: number;
45
+ canvasWidth: number;
46
+ canvasHeight: number;
47
+ fields: FieldView[];
48
+ }
49
+ interface FieldView {
50
+ id: string;
51
+ label: string;
52
+ tone: PdfViewerTone;
53
+ left: number;
54
+ top: number;
55
+ width: number | null;
56
+ maxWidth: number;
57
+ height: number;
58
+ fontPx: number;
59
+ }
60
+ /**
61
+ * Renders every page of a PDF into a canvas (crisp on high-density screens), with optional labelled boxes overlaid in PDF coordinates.
62
+ * Needs `pdfjs-dist` (loaded on first use, so it stays out of bundles that never show a PDF).
63
+ *
64
+ * <ui-pdf-viewer [data]="buffer()" [fields]="badges()" ariaLabel="Contract preview" (loaded)="onLoaded($event)" />
65
+ * <ui-pdf-viewer src="/files/contract.pdf" [httpHeaders]="{ Authorization: 'Bearer ' + token }" />
66
+ *
67
+ * - `src` / `data`: a URL, or the bytes (`data` wins). The bytes are copied, so your buffer stays usable.
68
+ * - `workerSrc` or the `PDF_VIEWER_WORKER_SRC` token: the pdf.js worker URL. Without either the viewer shows "PDF worker is not configured."
69
+ * - `maxPageWidth` (default 700): pages are drawn this wide, or the container's width when narrower; never larger.
70
+ * - `pixelRatio`: canvas pixels per CSS pixel; default is the screen's ratio between 1 and 3.
71
+ * - `fields`: badges positioned in PDF points (origin bottom-left); they scale with the page.
72
+ * - `loaded` / `pagesRendered` / `loadFailed`: see the event types. A new `src` / `data` replaces the document; a slow older load never paints.
73
+ * A page that fails to draw after `loaded` also emits `loadFailed`, shows the error state and destroys the document that `loaded` handed to the host.
74
+ * - A page's canvas never exceeds 16,000,000 pixels (Safari limit); the pixel ratio is lowered for such a page, its CSS size is unchanged.
75
+ * - All canvases together never exceed 48,000,000 pixels (iOS Safari limits total canvas memory): a long document is drawn at a lower
76
+ * density, the same for every page and never below 1 pixel per CSS pixel. CSS sizes are unchanged.
77
+ * - `httpHeaders` and `withCredentials` apply to `src` only; they are not used when `data` is given.
78
+ * - `fields[].id` is only a display / test hook; duplicates are tolerated. `httpHeaders` is compared by content, but a stable reference is still preferred.
79
+ * - The worker-missing message is fixed text and ignores `errorText`, because it is a setup problem for the developer.
80
+ * - Needs pdf.js 5 (`pdfjs-dist` >= 5), which needs Safari 17.4+; the legacy pdf.js build is not supported by this component.
81
+ * - The public typings reference `pdfjs-dist` types: apps that type-check the library without `pdfjs-dist` installed need `skipLibCheck` or the
82
+ * package (the same trade-off as `@forgeroute/ui/charts` and chart.js).
83
+ */
84
+ export declare class PdfViewerComponent {
85
+ /** PDF URL. Ignored while `data` is set. */
86
+ readonly src: import("@angular/core").InputSignal<string | null>;
87
+ /** PDF bytes. Wins over `src`. */
88
+ readonly data: import("@angular/core").InputSignal<ArrayBuffer | Uint8Array<ArrayBufferLike> | null>;
89
+ /** Request headers for `src`. Changes are detected by content, but pass a stable reference when you can. */
90
+ readonly httpHeaders: import("@angular/core").InputSignal<Record<string, string>>;
91
+ readonly withCredentials: import("@angular/core").InputSignal<boolean>;
92
+ /** pdf.js worker URL; falls back to the `PDF_VIEWER_WORKER_SRC` token. */
93
+ readonly workerSrc: import("@angular/core").InputSignal<string>;
94
+ /** Widest a page is drawn, in CSS px. */
95
+ readonly maxPageWidth: import("@angular/core").InputSignal<number>;
96
+ /** Canvas pixels per CSS pixel; null = the screen's ratio, limited to 1..3. */
97
+ readonly pixelRatio: import("@angular/core").InputSignal<number | null>;
98
+ readonly fields: import("@angular/core").InputSignal<PdfViewerField[]>;
99
+ /** Accessible name of the viewer. */
100
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
101
+ readonly loadingText: import("@angular/core").InputSignal<string>;
102
+ readonly errorText: import("@angular/core").InputSignal<string>;
103
+ readonly loaded: import("@angular/core").OutputEmitterRef<PdfViewerLoadedEvent>;
104
+ readonly loadFailed: import("@angular/core").OutputEmitterRef<unknown>;
105
+ readonly pagesRendered: import("@angular/core").OutputEmitterRef<PdfViewerRenderedEvent>;
106
+ protected readonly status: import("@angular/core").WritableSignal<Status>;
107
+ private readonly pageSizes;
108
+ private readonly containerWidth;
109
+ private readonly customError;
110
+ protected readonly errorMessage: import("@angular/core").Signal<string>;
111
+ /** Changes exactly when some canvas bitmap changes size (and so is cleared). */
112
+ private readonly drawKey;
113
+ private readonly effectiveWidth;
114
+ protected readonly views: import("@angular/core").Signal<PageView[]>;
115
+ private readonly host;
116
+ private readonly injector;
117
+ private readonly tokenWorkerSrc;
118
+ private readonly isBrowser;
119
+ private readonly headersKey;
120
+ /** Bumped by every new load, replacement and destroy; an async step whose token no longer matches stops. */
121
+ private loadToken;
122
+ /** Bumped by every (re)draw so only the newest draw paints. */
123
+ private drawToken;
124
+ private doc;
125
+ private loadingTask;
126
+ private pageProxies;
127
+ private renderTasks;
128
+ private observer;
129
+ private frame;
130
+ private lastDrawKey;
131
+ constructor();
132
+ /** Test seam: loads pdf.js on first use so apps that never show a PDF do not bundle or fetch it. */
133
+ protected loadPdfJs(): Promise<PdfJsModule>;
134
+ private resolvedRatio;
135
+ private widthFor;
136
+ private startLoad;
137
+ private fail;
138
+ private scheduleDraw;
139
+ private draw;
140
+ private onResize;
141
+ private cancelRenders;
142
+ private teardown;
143
+ private destroyDoc;
144
+ static ɵfac: i0.ɵɵFactoryDeclaration<PdfViewerComponent, never>;
145
+ static ɵcmp: i0.ɵɵComponentDeclaration<PdfViewerComponent, "ui-pdf-viewer", never, {
146
+ "src": {
147
+ "alias": "src";
148
+ "required": false;
149
+ "isSignal": true;
150
+ };
151
+ "data": {
152
+ "alias": "data";
153
+ "required": false;
154
+ "isSignal": true;
155
+ };
156
+ "httpHeaders": {
157
+ "alias": "httpHeaders";
158
+ "required": false;
159
+ "isSignal": true;
160
+ };
161
+ "withCredentials": {
162
+ "alias": "withCredentials";
163
+ "required": false;
164
+ "isSignal": true;
165
+ };
166
+ "workerSrc": {
167
+ "alias": "workerSrc";
168
+ "required": false;
169
+ "isSignal": true;
170
+ };
171
+ "maxPageWidth": {
172
+ "alias": "maxPageWidth";
173
+ "required": false;
174
+ "isSignal": true;
175
+ };
176
+ "pixelRatio": {
177
+ "alias": "pixelRatio";
178
+ "required": false;
179
+ "isSignal": true;
180
+ };
181
+ "fields": {
182
+ "alias": "fields";
183
+ "required": false;
184
+ "isSignal": true;
185
+ };
186
+ "ariaLabel": {
187
+ "alias": "ariaLabel";
188
+ "required": false;
189
+ "isSignal": true;
190
+ };
191
+ "loadingText": {
192
+ "alias": "loadingText";
193
+ "required": false;
194
+ "isSignal": true;
195
+ };
196
+ "errorText": {
197
+ "alias": "errorText";
198
+ "required": false;
199
+ "isSignal": true;
200
+ };
201
+ }, {
202
+ "loaded": "loaded";
203
+ "loadFailed": "loadFailed";
204
+ "pagesRendered": "pagesRendered";
205
+ }, never, never, true, never>;
206
+ }