@rt-tools/ui-kit-v2 0.25.0 → 0.26.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 +10 -0
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs +9 -0
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs +677 -0
- package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs.map +1 -0
- package/package.json +9 -1
- package/src/lib/components/CONTEXT.md +1 -1
- package/src/lib/components/pdf-viewer/CONTEXT.md +54 -0
- package/src/lib/components/pdf-viewer/rt-pdf-viewer.component.scss +231 -0
- package/types/rt-tools-ui-kit-v2-core.d.ts +9 -0
- package/types/rt-tools-ui-kit-v2-pdf-viewer.d.ts +243 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ElementRef, InjectionToken, Provider, Signal, WritableSignal } from "@angular/core";
|
|
3
|
+
import { TRtKitLabelMap } from "@rt-tools/ui-kit-v2/core";
|
|
4
|
+
/**
|
|
5
|
+
* Контракты полноэкранного просмотрщика документа PDF. Один корневой неймспейс с префиксом `I`.
|
|
6
|
+
*/
|
|
7
|
+
export declare namespace IRtPdfViewer {
|
|
8
|
+
/**
|
|
9
|
+
* Откуда взять документ: байты или адрес. Байты просмотрщик не отдаёт рисовальщику как есть —
|
|
10
|
+
* тот забирает буфер себе в поток, и скачать файл после этого было бы нечем. Отдаётся копия.
|
|
11
|
+
*/
|
|
12
|
+
type Source = Uint8Array | ArrayBuffer | string;
|
|
13
|
+
/**
|
|
14
|
+
* Данные открытия: документ и имя файла.
|
|
15
|
+
*
|
|
16
|
+
* Имя показывается в полосе сверху и становится именем скачанного файла: адрес документа
|
|
17
|
+
* часто бывает подписанной ссылкой, и имени в нём нет.
|
|
18
|
+
*/
|
|
19
|
+
interface Data {
|
|
20
|
+
readonly source: Source;
|
|
21
|
+
readonly fileName: string;
|
|
22
|
+
}
|
|
23
|
+
/** Что сейчас на месте страниц: индикатор, сами страницы или отказ. */
|
|
24
|
+
type Status = 'loading' | 'ready' | 'error';
|
|
25
|
+
/**
|
|
26
|
+
* Масштаб. «По ширине» хранится как режим, а не как число: окно меняет ширину, и страница
|
|
27
|
+
* обязана подстроиться под новую, а не остаться на числе, посчитанном для прежней.
|
|
28
|
+
*/
|
|
29
|
+
type Zoom = {
|
|
30
|
+
readonly kind: 'fit';
|
|
31
|
+
} | {
|
|
32
|
+
readonly kind: 'percent';
|
|
33
|
+
readonly percent: number;
|
|
34
|
+
};
|
|
35
|
+
/** Размер страницы в пунктах документа — в единицах, в которых его пишет сам PDF. */
|
|
36
|
+
interface PageSize {
|
|
37
|
+
readonly width: number;
|
|
38
|
+
readonly height: number;
|
|
39
|
+
}
|
|
40
|
+
/** Размер места под страницу на экране, в CSS-пикселях. */
|
|
41
|
+
interface PageBox {
|
|
42
|
+
readonly index: number;
|
|
43
|
+
readonly width: number;
|
|
44
|
+
readonly height: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Настройки рисовальщика. Даёт их приложение через `provideRtPdfViewer()`: только оно знает,
|
|
48
|
+
* куда при сборке положен файл воркера.
|
|
49
|
+
*/
|
|
50
|
+
interface Config {
|
|
51
|
+
/**
|
|
52
|
+
* Адрес файла воркера `pdf.worker.min.mjs`. Относительный адрес считается от `<base href>`
|
|
53
|
+
* страницы. Версия воркера обязана совпадать с версией `pdfjs-dist`, поэтому файл копируется
|
|
54
|
+
* из того же `node_modules`, а не берётся с чужого адреса.
|
|
55
|
+
*/
|
|
56
|
+
readonly workerSrc: string;
|
|
57
|
+
/** Как загрузить рисовальщик. Умолчание — динамический `import('pdfjs-dist')`. */
|
|
58
|
+
readonly load: () => Promise<PdfJs>;
|
|
59
|
+
/** Каталог `cmaps/` пакета — нужен документам с азиатскими шрифтами без вложенных карт. */
|
|
60
|
+
readonly cMapUrl?: string;
|
|
61
|
+
/** Каталог `standard_fonts/` пакета — нужен документам на стандартных шрифтах без вложения. */
|
|
62
|
+
readonly standardFontDataUrl?: string;
|
|
63
|
+
/** Каталог `wasm/` пакета — нужен документам со снимками в JPEG 2000. */
|
|
64
|
+
readonly wasmUrl?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Та часть `pdfjs-dist`, которой пользуется просмотрщик. Описана своими типами, а не взята из
|
|
68
|
+
* пакета: тогда типы кита не требуют пакета у того, кто просмотрщик не ставит, а в тесте
|
|
69
|
+
* рисовальщик подменяется объектом из нескольких функций.
|
|
70
|
+
*/
|
|
71
|
+
interface PdfJs {
|
|
72
|
+
readonly GlobalWorkerOptions: {
|
|
73
|
+
workerSrc: string;
|
|
74
|
+
};
|
|
75
|
+
getDocument(params: DocumentParams): LoadingTask;
|
|
76
|
+
}
|
|
77
|
+
interface DocumentParams {
|
|
78
|
+
readonly url?: string;
|
|
79
|
+
readonly data?: Uint8Array;
|
|
80
|
+
readonly cMapUrl?: string;
|
|
81
|
+
readonly cMapPacked?: boolean;
|
|
82
|
+
readonly standardFontDataUrl?: string;
|
|
83
|
+
readonly wasmUrl?: string;
|
|
84
|
+
}
|
|
85
|
+
interface LoadingTask {
|
|
86
|
+
readonly promise: Promise<PdfDocument>;
|
|
87
|
+
destroy(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
interface PdfDocument {
|
|
90
|
+
readonly numPages: number;
|
|
91
|
+
getPage(pageNumber: number): Promise<PdfPage>;
|
|
92
|
+
getData(): Promise<Uint8Array>;
|
|
93
|
+
}
|
|
94
|
+
interface PdfPage {
|
|
95
|
+
getViewport(params: {
|
|
96
|
+
scale: number;
|
|
97
|
+
}): Viewport;
|
|
98
|
+
render(params: RenderParams): RenderTask;
|
|
99
|
+
}
|
|
100
|
+
interface Viewport {
|
|
101
|
+
readonly width: number;
|
|
102
|
+
readonly height: number;
|
|
103
|
+
}
|
|
104
|
+
interface RenderParams {
|
|
105
|
+
readonly canvas: HTMLCanvasElement;
|
|
106
|
+
readonly viewport: Viewport;
|
|
107
|
+
readonly intent?: string;
|
|
108
|
+
}
|
|
109
|
+
interface RenderTask {
|
|
110
|
+
readonly promise: Promise<void>;
|
|
111
|
+
cancel(): void;
|
|
112
|
+
}
|
|
113
|
+
/** Печатный лист: разметка страниц картинками и уборка за ней. */
|
|
114
|
+
interface PrintSheet {
|
|
115
|
+
dispose(): void;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Полноэкранный просмотр документа PDF поверх `RtDialogService`.
|
|
120
|
+
*
|
|
121
|
+
* Страницы рисует `pdfjs-dist` — необязательная зависимость кита. Он грузится динамическим импортом
|
|
122
|
+
* только при открытии окна, поэтому вход `@rt-tools/ui-kit-v2/pdf-viewer` не утяжеляет бандл, пока
|
|
123
|
+
* окно не открыто. Рисуются только видимые страницы и их соседи, с плотностью точек экрана.
|
|
124
|
+
*
|
|
125
|
+
* `Esc`, блокировку прокрутки фона и затемнение даёт сам диалог; фокус после закрытия
|
|
126
|
+
* просмотрщик возвращает туда, откуда его открыли.
|
|
127
|
+
*/
|
|
128
|
+
export declare class RtPdfViewerComponent {
|
|
129
|
+
#private;
|
|
130
|
+
protected readonly t: Signal<TRtKitLabelMap>;
|
|
131
|
+
protected readonly scroller: Signal<ElementRef<HTMLElement> | undefined>;
|
|
132
|
+
protected readonly column: Signal<ElementRef<HTMLElement> | undefined>;
|
|
133
|
+
protected readonly pageNodes: Signal<readonly ElementRef<HTMLElement>[]>;
|
|
134
|
+
protected readonly canvases: Signal<readonly ElementRef<HTMLCanvasElement>[]>;
|
|
135
|
+
protected readonly fileName: string;
|
|
136
|
+
protected readonly status: WritableSignal<IRtPdfViewer.Status>;
|
|
137
|
+
protected readonly printing: WritableSignal<boolean>;
|
|
138
|
+
protected readonly zoom: WritableSignal<IRtPdfViewer.Zoom>;
|
|
139
|
+
/** Масштаб на экране в процентах — и для «по ширине», который хранится режимом */
|
|
140
|
+
protected readonly percent: Signal<number>;
|
|
141
|
+
protected readonly isFit: Signal<boolean>;
|
|
142
|
+
protected readonly zoomLabel: Signal<string>;
|
|
143
|
+
protected readonly canZoomIn: Signal<boolean>;
|
|
144
|
+
protected readonly canZoomOut: Signal<boolean>;
|
|
145
|
+
protected readonly boxes: Signal<IRtPdfViewer.PageBox[]>;
|
|
146
|
+
/** Видимая сейчас страница, с нуля */
|
|
147
|
+
protected readonly currentPage: WritableSignal<number>;
|
|
148
|
+
protected readonly counter: Signal<string>;
|
|
149
|
+
protected readonly pageOfLabel: Signal<string>;
|
|
150
|
+
constructor();
|
|
151
|
+
close(): void;
|
|
152
|
+
/** Esc закрывает только окно: окно под ним, например боковая панель, остаётся открытым */
|
|
153
|
+
protected onEscape(event: Event): void;
|
|
154
|
+
protected zoomIn(): void;
|
|
155
|
+
protected zoomOut(): void;
|
|
156
|
+
protected fitWidth(): void;
|
|
157
|
+
protected onScroll(): void;
|
|
158
|
+
protected onResize(): void;
|
|
159
|
+
/** Байты уходят как пришли, а адрес — байтами документа, если он уже загружен */
|
|
160
|
+
protected download(): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Печать документа целиком, без полосы и плашки: страницы рисуются картинками в отдельный лист,
|
|
163
|
+
* и на время печати страница прячет всё, кроме него. Лист убирается после печати.
|
|
164
|
+
*/
|
|
165
|
+
protected print(): Promise<void>;
|
|
166
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RtPdfViewerComponent, never>;
|
|
167
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RtPdfViewerComponent, "rt-pdf-viewer", never, {}, {}, never, never, true, never>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Чистая логика просмотрщика документа: шаги масштаба, начальный масштаб, номер видимой страницы и
|
|
171
|
+
* то, какие страницы стоит держать нарисованными.
|
|
172
|
+
*/
|
|
173
|
+
/** Ступени масштаба в процентах. Кнопки «−» и «+» ходят только по ним. */
|
|
174
|
+
export declare const RT_PDF_ZOOM_STEPS: readonly number[];
|
|
175
|
+
export declare const RT_PDF_ZOOM_MIN: number;
|
|
176
|
+
export declare const RT_PDF_ZOOM_MAX: number;
|
|
177
|
+
/**
|
|
178
|
+
* Сколько CSS-пикселей в пункте документа. Пункт — 1/72 дюйма, CSS-пиксель — 1/96: при 100%
|
|
179
|
+
* страница A4 на экране той же ширины, что на бумаге.
|
|
180
|
+
*/
|
|
181
|
+
export declare const RT_PDF_CSS_UNITS: number;
|
|
182
|
+
/** Ширина окна, до которой документ открывается «по ширине» при любом размере страницы. */
|
|
183
|
+
export declare const RT_PDF_NARROW_WIDTH: number;
|
|
184
|
+
/**
|
|
185
|
+
* Следующая ступень масштаба. Шаг идёт от того, что на экране сейчас: из «по ширине» в 83% кнопка
|
|
186
|
+
* «+» ведёт на 100%, а «−» — на 75%, а не на ступень, соседнюю с последней выбранной руками.
|
|
187
|
+
*/
|
|
188
|
+
export declare function nextZoomStep(current: number, direction: 1 | -1): number;
|
|
189
|
+
/** Есть ли куда увеличивать: на верхней границе кнопка «+» выключена. */
|
|
190
|
+
export declare function canZoomIn(current: number): boolean;
|
|
191
|
+
/** Есть ли куда уменьшать: на нижней границе кнопка «−» выключена. */
|
|
192
|
+
export declare function canZoomOut(current: number): boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Масштаб «по ширине» в процентах: самая широкая страница занимает всё место столбца.
|
|
195
|
+
*
|
|
196
|
+
* Границами ступеней он не зажат. На телефоне страница A4 «по ширине» — около 45%, и зажать её до
|
|
197
|
+
* 50% значило бы вернуть горизонтальную прокрутку, ради которой режим и существует.
|
|
198
|
+
*/
|
|
199
|
+
export declare function fitWidthPercent(availableWidth: number, pages: readonly IRtPdfViewer.PageSize[]): number;
|
|
200
|
+
/**
|
|
201
|
+
* С какого масштаба открыть документ. Узкий экран и страница, которая в 100% не влезает, —
|
|
202
|
+
* «по ширине»: иначе человек сначала видит обрезанный край листа. Остальные — в 100%.
|
|
203
|
+
*/
|
|
204
|
+
export declare function initialZoom(viewportWidth: number, availableWidth: number, pages: readonly IRtPdfViewer.PageSize[]): IRtPdfViewer.Zoom;
|
|
205
|
+
/** Места под страницы на экране: от размера в пунктах и масштаба, в целых пикселях. */
|
|
206
|
+
export declare function pageBoxes(pages: readonly IRtPdfViewer.PageSize[], percent: number): IRtPdfViewer.PageBox[];
|
|
207
|
+
/**
|
|
208
|
+
* Номер страницы, которая видна сейчас, — с нуля. Это та, что занимает больше всего высоты окна;
|
|
209
|
+
* при прокрутке до конца — последняя, даже если она короче соседки: иначе счётчик никогда не
|
|
210
|
+
* показал бы «M / M» у документа с маленькой последней страницей. Документ, который виден целиком
|
|
211
|
+
* без прокрутки, стоит на первой: до конца его никто не прокручивал.
|
|
212
|
+
*/
|
|
213
|
+
export declare function visiblePageIndex(tops: readonly number[], heights: readonly number[], scrollTop: number, viewportHeight: number): number;
|
|
214
|
+
/**
|
|
215
|
+
* Страницы, которые стоит нарисовать: видимые и по `overscan` соседних с каждой стороны. Документ
|
|
216
|
+
* в сотню страниц разом не рисуется — каждая страница это холст в мегабайты памяти.
|
|
217
|
+
*/
|
|
218
|
+
export declare function pagesToRender(tops: readonly number[], heights: readonly number[], scrollTop: number, viewportHeight: number, overscan?: number): number[];
|
|
219
|
+
/**
|
|
220
|
+
* Куда прокрутить после смены масштаба, чтобы на экране осталось то же место той же страницы.
|
|
221
|
+
* Без этого увеличение уводило бы человека на несколько страниц вниз от того, что он читал.
|
|
222
|
+
*/
|
|
223
|
+
export declare function anchoredScrollTop(oldTop: number, oldHeight: number, oldScrollTop: number, newTop: number, newHeight: number): number;
|
|
224
|
+
/** Подпись масштаба для плашки в процентах: «83%», а не «83.47%». */
|
|
225
|
+
export declare function zoomPercentLabel(percent: number): string;
|
|
226
|
+
/**
|
|
227
|
+
* Адрес воркера по умолчанию. Относительный: считается от `<base href>`, поэтому приложение под
|
|
228
|
+
* своим префиксом не правит его руками. Файл туда кладёт сборка приложения — см. обзор компонента.
|
|
229
|
+
*/
|
|
230
|
+
export declare const RT_PDF_VIEWER_WORKER_SRC: string;
|
|
231
|
+
/** Настройки рисовальщика просмотрщика. Без провайдера — умолчания выше. */
|
|
232
|
+
export declare const RT_PDF_VIEWER_CONFIG: InjectionToken<IRtPdfViewer.Config>;
|
|
233
|
+
/**
|
|
234
|
+
* Настраивает просмотрщик: адрес воркера и каталоги данных `pdfjs-dist`. Незаданное берётся из
|
|
235
|
+
* умолчаний.
|
|
236
|
+
*
|
|
237
|
+
* ```typescript
|
|
238
|
+
* export const appConfig: ApplicationConfig = {
|
|
239
|
+
* providers: [provideRtPdfViewer({ workerSrc: 'static/pdf.worker.min.mjs' })],
|
|
240
|
+
* };
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
export declare function provideRtPdfViewer(config: Partial<IRtPdfViewer.Config>): Provider;
|