@forgeroute/ui 0.3.6 → 0.3.8
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/fesm2022/forgeroute-ui-charts.mjs +1 -1
- package/fesm2022/forgeroute-ui-charts.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-pdf.mjs +582 -0
- package/fesm2022/forgeroute-ui-pdf.mjs.map +1 -0
- package/fesm2022/forgeroute-ui.mjs +134 -3
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +10 -2
- package/types/forgeroute-ui-pdf.d.ts +206 -0
- package/types/forgeroute-ui.d.ts +50 -5
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeroute/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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
|
+
}
|
package/types/forgeroute-ui.d.ts
CHANGED
|
@@ -834,7 +834,7 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
|
|
|
834
834
|
readonly error: import("@angular/core").InputSignal<string>;
|
|
835
835
|
/** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
|
|
836
836
|
readonly showErrors: import("@angular/core").InputSignal<boolean>;
|
|
837
|
-
readonly size: import("@angular/core").InputSignal<"
|
|
837
|
+
readonly size: import("@angular/core").InputSignal<"sm" | "default">;
|
|
838
838
|
readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
|
|
839
839
|
private readonly _cvaDisabled;
|
|
840
840
|
protected readonly disabled: import("@angular/core").Signal<boolean>;
|
|
@@ -1685,7 +1685,7 @@ export declare class ModalComponent implements OnInit, OnDestroy {
|
|
|
1685
1685
|
readonly title: import("@angular/core").InputSignal<string>;
|
|
1686
1686
|
readonly description: import("@angular/core").InputSignal<string>;
|
|
1687
1687
|
readonly maxWidth: import("@angular/core").InputSignal<string>;
|
|
1688
|
-
readonly bodyOverflow: import("@angular/core").InputSignal<"
|
|
1688
|
+
readonly bodyOverflow: import("@angular/core").InputSignal<"auto" | "visible" | "hidden">;
|
|
1689
1689
|
readonly close: import("@angular/core").OutputEmitterRef<void>;
|
|
1690
1690
|
protected readonly titleId: string;
|
|
1691
1691
|
private readonly el;
|
|
@@ -1825,6 +1825,51 @@ export declare class ProgressBarComponent {
|
|
|
1825
1825
|
};
|
|
1826
1826
|
}, {}, never, never, true, never>;
|
|
1827
1827
|
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Audio player for a recording (a call, a voicemail, a message): the browser's own controls (play / pause, seek, time, volume,
|
|
1830
|
+
* keyboard and screen-reader support, the same in Chrome, Edge, Firefox and Safari) in the library's look, plus a readable message
|
|
1831
|
+
* when the file can't be played.
|
|
1832
|
+
*
|
|
1833
|
+
* <ui-audio-player [src]="blobUrl()" ariaLabel="Call recording playback" />
|
|
1834
|
+
*
|
|
1835
|
+
* - `src`: the audio URL (an object URL from a fetched blob works). An empty `src` renders the player with nothing to play.
|
|
1836
|
+
* - `ariaLabel`: the accessible name of the player. Give it one; without it assistive tech just hears "audio".
|
|
1837
|
+
* - `preload`: 'metadata' (default; loads the length only), 'auto' or 'none'.
|
|
1838
|
+
* - `playbackError` fires once per failed source; the message "Audio could not be played." replaces the player until `src` changes.
|
|
1839
|
+
*/
|
|
1840
|
+
export declare class AudioPlayerComponent {
|
|
1841
|
+
/** The audio URL. */
|
|
1842
|
+
readonly src: import("@angular/core").InputSignal<string>;
|
|
1843
|
+
/** Accessible name of the player. */
|
|
1844
|
+
readonly ariaLabel: import("@angular/core").InputSignal<string>;
|
|
1845
|
+
/** How much to load before play: 'metadata' (default), 'auto' or 'none'. */
|
|
1846
|
+
readonly preload: import("@angular/core").InputSignal<"auto" | "none" | "metadata">;
|
|
1847
|
+
/** Fires when the browser can't load or decode the source. */
|
|
1848
|
+
readonly playbackError: import("@angular/core").OutputEmitterRef<void>;
|
|
1849
|
+
protected readonly failed: import("@angular/core").WritableSignal<boolean>;
|
|
1850
|
+
constructor();
|
|
1851
|
+
protected onError(): void;
|
|
1852
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AudioPlayerComponent, never>;
|
|
1853
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<AudioPlayerComponent, "ui-audio-player", never, {
|
|
1854
|
+
"src": {
|
|
1855
|
+
"alias": "src";
|
|
1856
|
+
"required": false;
|
|
1857
|
+
"isSignal": true;
|
|
1858
|
+
};
|
|
1859
|
+
"ariaLabel": {
|
|
1860
|
+
"alias": "ariaLabel";
|
|
1861
|
+
"required": false;
|
|
1862
|
+
"isSignal": true;
|
|
1863
|
+
};
|
|
1864
|
+
"preload": {
|
|
1865
|
+
"alias": "preload";
|
|
1866
|
+
"required": false;
|
|
1867
|
+
"isSignal": true;
|
|
1868
|
+
};
|
|
1869
|
+
}, {
|
|
1870
|
+
"playbackError": "playbackError";
|
|
1871
|
+
}, never, never, true, never>;
|
|
1872
|
+
}
|
|
1828
1873
|
export declare class SkeletonComponent {
|
|
1829
1874
|
readonly height: import("@angular/core").InputSignal<number>;
|
|
1830
1875
|
readonly width: import("@angular/core").InputSignal<string>;
|
|
@@ -2066,7 +2111,7 @@ export declare class ButtonComponent {
|
|
|
2066
2111
|
readonly color: import("@angular/core").InputSignal<string | undefined>;
|
|
2067
2112
|
readonly active: import("@angular/core").InputSignal<boolean>;
|
|
2068
2113
|
readonly size: import("@angular/core").InputSignal<"sm" | "md" | "xs" | "lg">;
|
|
2069
|
-
readonly type: import("@angular/core").InputSignal<"
|
|
2114
|
+
readonly type: import("@angular/core").InputSignal<"button" | "reset" | "submit">;
|
|
2070
2115
|
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
2071
2116
|
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
2072
2117
|
readonly fullWidth: import("@angular/core").InputSignal<boolean>;
|
|
@@ -4771,7 +4816,7 @@ export declare class FormSectionComponent {
|
|
|
4771
4816
|
}, {}, never, ["*"], true, never>;
|
|
4772
4817
|
}
|
|
4773
4818
|
export declare class FormRowComponent {
|
|
4774
|
-
readonly cols: import("@angular/core").InputSignal<
|
|
4819
|
+
readonly cols: import("@angular/core").InputSignal<2 | 1 | 3>;
|
|
4775
4820
|
static ɵfac: i0.ɵɵFactoryDeclaration<FormRowComponent, never>;
|
|
4776
4821
|
static ɵcmp: i0.ɵɵComponentDeclaration<FormRowComponent, "ui-form-row", never, {
|
|
4777
4822
|
"cols": {
|
|
@@ -6101,7 +6146,7 @@ export declare class DetailCardComponent {
|
|
|
6101
6146
|
/** Bold uppercase title. Empty = no title text. */
|
|
6102
6147
|
readonly title: import("@angular/core").InputSignal<string>;
|
|
6103
6148
|
/** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
|
|
6104
|
-
readonly headingLevel: import("@angular/core").InputSignal<
|
|
6149
|
+
readonly headingLevel: import("@angular/core").InputSignal<2 | 1 | 5 | 3 | 6 | 4 | null>;
|
|
6105
6150
|
/** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
|
|
6106
6151
|
readonly titleId: import("@angular/core").InputSignal<string>;
|
|
6107
6152
|
/** Grey line under the title. */
|