@embedpdf-editor/react-chapter-viewer 0.1.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.
@@ -0,0 +1,803 @@
1
+ import { AnnotationCapability } from '@embedpdf/plugin-annotation';
2
+ import { BasePlugin } from '@embedpdf/core';
3
+ import { BasePluginConfig } from '@embedpdf/core';
4
+ import { ChapterPdfViewer } from '../chapter-pdf-viewer';
5
+ import { ChapterPdfViewerProps } from '../chapter-pdf-viewer';
6
+ import { Command } from '@embedpdf/plugin-commands';
7
+ import { EmbedPDF } from '@embedpdf/core/react';
8
+ import { EventHook } from '@embedpdf/core';
9
+ import { JSX as JSX_2 } from 'react/jsx-runtime';
10
+ import { PdfChapterViewport } from '../pdf-chapter-viewport';
11
+ import { PdfChapterViewportProps } from '../pdf-chapter-viewport';
12
+ import { PluginBatchRegistration } from '@embedpdf/core';
13
+ import { PluginRegistry } from '@embedpdf/core';
14
+ import { ReactNode } from 'react';
15
+ import { Rect } from '@embedpdf/models';
16
+ import { SelectionCapability } from '@embedpdf/plugin-selection';
17
+ import { ToolbarSchema } from '@embedpdf/plugin-ui';
18
+ import { UISchema } from '@embedpdf/plugin-ui';
19
+ import { useCapability } from '@embedpdf/core/react';
20
+ import { usePdfiumEngine } from '@embedpdf/engines/react';
21
+
22
+ /** 对当前选区应用 PDF 划线/高亮,支持按类型自定义颜色、粗细与偏移 */
23
+ export declare function applySelectionMarkup(documentId: string, kind: SelectionMarkupKind, annotation: AnnotationCapability, selection: SelectionCapability, styles?: MarkupStylesConfig): boolean;
24
+
25
+ declare interface BookmarkMarkerUiConfig {
26
+ /** 自定义图标;提供时仅渲染图标,无默认蓝色背景按钮 */
27
+ renderIcon?: (ctx: {
28
+ bookmark: ParagraphBookmark;
29
+ }) => ReactNode;
30
+ iconSize?: number;
31
+ }
32
+
33
+ declare interface BookmarkMarkerUiConfig_2 {
34
+ /** 自定义图标;提供时仅渲染图标,无默认蓝色圆角背景 */
35
+ renderIcon?: (ctx: {
36
+ bookmark: ParagraphBookmark;
37
+ }) => unknown;
38
+ iconSize?: number;
39
+ }
40
+
41
+ export declare function buildParagraphBookmarkAnchor(chapterId: string, localPageIndex: number, rectsPdfCoord: Rect[], virtualPage?: {
42
+ globalPageIndex: number;
43
+ globalPageNumber: number;
44
+ }): ParagraphBookmark['anchor'];
45
+
46
+ /** 选区浮窗 card 内置操作 */
47
+ declare type BuiltinSelectionToolbarAction = 'highlight' | 'underline' | 'squiggly' | 'strikeout' | 'note';
48
+
49
+ /**
50
+ * 回调型:把决策交给业务侧异步函数(最常用)。
51
+ */
52
+ export declare class CallbackPasswordProvider implements IPasswordProvider {
53
+ private readonly cb;
54
+ constructor(cb: (chapter: ChapterDescriptor, attempt: number) => Promise<string | null>);
55
+ resolvePassword(chapter: ChapterDescriptor, attempt: number): Promise<string | null>;
56
+ }
57
+
58
+ export declare interface ChapterDescriptor {
59
+ /** 业务唯一 ID;同时复用作 documentManager 的 documentId */
60
+ chapterId: string;
61
+ title: string;
62
+ /**
63
+ * 该章节在「整本」中的全局页范围(闭区间,业务页码,可 1-based 也可 0-based,
64
+ * 只要全局一致即可)。允许相邻章节重叠:`[a, b]` ∩ `[c, d]` ≠ ∅。
65
+ */
66
+ globalPageRange: [number, number];
67
+ /**
68
+ * 该章节 PDF 文件内部的本地页范围(0-based 闭区间)。
69
+ * 必须满足:`localPageRange[1] - localPageRange[0] === globalPageRange[1] - globalPageRange[0]`
70
+ */
71
+ localPageRange: [number, number];
72
+ /**
73
+ * PDF 来源。可省略:须在 ChapterManager 配置 `chapterPdfLoader` 中统一加载。
74
+ */
75
+ source?: ChapterSource;
76
+ encrypted?: boolean;
77
+ /**
78
+ * 仅当 OverlapOwnerStrategy = 'explicit' 时使用:
79
+ * 该章节"声明拥有"的全局页号集合。
80
+ */
81
+ ownedGlobalPages?: number[];
82
+ }
83
+
84
+ /**
85
+ * 章节级加载状态。区别于 `@embedpdf/core` 的 DocumentState:
86
+ * - `idle` = manifest 已注册但尚未触发 open
87
+ * - `password-required` = 用户取消/密码错误后停在等密码态
88
+ */
89
+ export declare type ChapterLoadStatus = 'idle' | 'loading' | 'loaded' | 'error' | 'password-required' | 'closed';
90
+
91
+ declare interface ChapterManagerCapability {
92
+ /** 替换 manifest(会触发已不存在章节的卸载) */
93
+ setManifest(manifest: ChapterManifest, strategy?: OverlapOwnerStrategy): void;
94
+ getManifest(): ChapterManifest;
95
+ getVirtualPageMap(): VirtualPageMap;
96
+ /** ChapterScrollPlugin 在可见页位变化时调用,用以驱动按需加载 */
97
+ setVisibleGlobalPages(visiblePageIndices: number[]): void;
98
+ /** 显式触发某章节加载(如点击章节标题跳转时) */
99
+ ensureChapterLoaded(chapterId: string): Promise<ChapterLoadStatus>;
100
+ /** 状态查询 */
101
+ getChapterStatus(chapterId: string): ChapterLoadStatus;
102
+ getChapter(chapterId: string): ChapterDescriptor | null;
103
+ /** 事件 */
104
+ onChapterStatusChange: EventHook<ChapterStatusEvent>;
105
+ onManifestChange: EventHook<{
106
+ manifest: ChapterManifest;
107
+ map: VirtualPageMap;
108
+ }>;
109
+ }
110
+
111
+ /**
112
+ * 章节生命周期管理:以章节为粒度懒加载/预取/卸载 PDF 文件,并屏蔽密码协议细节。
113
+ *
114
+ * 关键不变量:
115
+ * - 每个章节对 DocumentManager 用 `documentId === chapterId`,从而保持 1:1 缓存。
116
+ * - 视觉上的「activeDocumentId」由本插件根据当前可见页位维护;上层无须感知。
117
+ * - 渲染层最终始终通过 `(chapterId, localPageIndex)` 索引到 owner 章节的 PDF 文档。
118
+ */
119
+ export declare class ChapterManagerPlugin extends BasePlugin<ChapterManagerPluginConfig, ChapterManagerCapability> {
120
+ static readonly id: "chapter-manager";
121
+ private readonly statusChange$;
122
+ private readonly manifestChange$;
123
+ private config;
124
+ private documentManager;
125
+ private passwordProvider?;
126
+ private manifest;
127
+ private overlapStrategy;
128
+ private virtualPageMap;
129
+ /** 每个章节当前状态(in-memory;不需要 redux 同步) */
130
+ private readonly chapterStatus;
131
+ /** 章节最近一次进入视口或被显式请求的时间戳,用于卸载判断 */
132
+ private readonly chapterLastUsed;
133
+ /** 章节密码累计尝试次数 */
134
+ private readonly passwordAttempts;
135
+ /** 等待 ensureChapterLoaded 完成的 Promise 列表(按章节去重) */
136
+ private readonly pendingLoadPromises;
137
+ /** unload tick 句柄 */
138
+ private unloadTimer;
139
+ private documentManagerUnsubs;
140
+ constructor(id: string, registry: PluginRegistry);
141
+ initialize(config: ChapterManagerPluginConfig): Promise<void>;
142
+ protected buildCapability(): ChapterManagerCapability;
143
+ destroy(): void;
144
+ private setManifestInternal;
145
+ /** manifest 就绪后预取前 N 章(不依赖滚动视口是否已算出可见页) */
146
+ private eagerPrefetchFromManifest;
147
+ private findChapter;
148
+ private isOwnedChapter;
149
+ private handleVisibleChange;
150
+ private collectIdleChapters;
151
+ ensureChapterLoaded(chapterId: string): Promise<ChapterLoadStatus>;
152
+ private resolvePdfPayload;
153
+ private startLoad;
154
+ /** 阻塞等待该章节状态进入 loaded / error / password-required / closed */
155
+ private waitForTerminalStatus;
156
+ private handleDocumentError;
157
+ private closeChapter;
158
+ private updateStatus;
159
+ }
160
+
161
+ declare interface ChapterManagerPluginConfig extends BasePluginConfig {
162
+ manifest: ChapterManifest;
163
+ overlapStrategy?: OverlapOwnerStrategy;
164
+ passwordProvider?: IPasswordProvider;
165
+ /** 未在 descriptor.source 中指定 PDF 时,由此统一加载 */
166
+ chapterPdfLoader?: IChapterPdfLoader;
167
+ /** 视口前后预取多少章节,默认 1 */
168
+ prefetchChapters?: number;
169
+ /** 章节空闲多久后卸载(毫秒),默认 60s。设为 0 关闭卸载 */
170
+ unloadTimeoutMs?: number;
171
+ /** 第一个加载的章节是否自动设为 active,默认 true */
172
+ autoActivateOnLoad?: boolean;
173
+ }
174
+
175
+ export declare interface ChapterManifest {
176
+ chapters: ChapterDescriptor[];
177
+ /**
178
+ * 整本去重后的总页数。当未提供时由 VirtualPageMap 自动推导
179
+ * (取所有章节 globalPageRange 的并集大小)。
180
+ */
181
+ totalGlobalPages?: number;
182
+ }
183
+
184
+ /** 单页布局(用于 ChapterScroller 渲染) */
185
+ declare interface ChapterPageItem {
186
+ /** 0-based 紧凑虚拟索引 */
187
+ globalPageIndex: number;
188
+ /** 后端业务页号 */
189
+ globalPageNumber: number;
190
+ chapterId: string;
191
+ localPageIndex: number;
192
+ /** 渲染尺寸(CSS 像素,含 scale) */
193
+ width: number;
194
+ height: number;
195
+ /** 在内容容器内的纵向偏移(CSS 像素) */
196
+ offsetTop: number;
197
+ /** owner 章节尚未加载完成;UI 通常画一个 skeleton */
198
+ isPlaceholder: boolean;
199
+ }
200
+
201
+ /**
202
+ * Backend-supplied chapter contract.
203
+ *
204
+ * 一个 PDF 整体被后端按章节切成若干独立 PDF 文件;前端将它们组装成一条
205
+ * 连续滚动流。相邻章节在 `globalPageRange` 上**允许重叠**(业务上下章
206
+ * 经常各含一个过渡页),由 OverlapResolver 决定每个全局页归属的「owner
207
+ * chapter」,渲染与标注都落在 owner 上以保持唯一性。
208
+ */
209
+ /** 章节 PDF 解析结果 */
210
+ export declare type ChapterPdfPayload = {
211
+ url: string;
212
+ } | {
213
+ buffer: ArrayBuffer;
214
+ };
215
+
216
+ export { ChapterPdfViewer }
217
+
218
+ export { ChapterPdfViewerProps }
219
+
220
+ declare interface ChapterScrollCapability {
221
+ /** 绑定/解绑滚动容器(由 ChapterScroller 内部调用) */
222
+ registerViewport(el: HTMLElement | null): void;
223
+ /** 当某章节 PDF 加载完成时,由 ChapterRenderLayer 等汇报真实页尺寸 */
224
+ reportChapterPageSizes(chapterId: string, sizes: Array<{
225
+ localPageIndex: number;
226
+ width: number;
227
+ height: number;
228
+ }>): void;
229
+ /** 当前布局 */
230
+ getLayout(): ChapterScrollLayout;
231
+ getCurrentGlobalPageIndex(): number;
232
+ getVisibleGlobalPageIndices(): number[];
233
+ /** 跳转 */
234
+ scrollToGlobalPageIndex(idx: number, options?: ChapterScrollScrollToOptions): void;
235
+ scrollToChapter(chapterId: string, options?: ChapterScrollScrollToOptions): void;
236
+ scrollToGlobalPageNumber(globalPageNumber: number, options?: ChapterScrollScrollToOptions): void;
237
+ /**
238
+ * 滚动到虚拟页内某 PDF 坐标点(y 为 PDF 坐标,原点在页左下)。
239
+ * 比 topOffset 更直观,附注/书签定位应优先使用。
240
+ */
241
+ scrollToGlobalPdfPoint(globalPageIndex: number, pdfY: number, options?: ChapterScrollScrollToPdfPointOptions): void;
242
+ /** 事件 */
243
+ onLayoutChange: EventHook<ChapterScrollLayout>;
244
+ onVisibleChange: EventHook<VisibleChangeEvent>;
245
+ }
246
+
247
+ declare interface ChapterScrollLayout {
248
+ totalHeight: number;
249
+ totalWidth: number;
250
+ items: ChapterPageItem[];
251
+ pageGap: number;
252
+ }
253
+
254
+ /**
255
+ * 跨章节虚拟滚动。
256
+ *
257
+ * 设计:
258
+ * - 维护一个「整本」页位序列(来自 `chapter-manager.getVirtualPageMap()`,已 dedup)。
259
+ * - 每个页位先用占位尺寸;当章节加载完成后由 ChapterRenderLayer 上报真实尺寸 → 重排。
260
+ * - 监听容器 scroll/resize,计算 visible + buffer 范围 → 输出 `ChapterScrollLayout`。
261
+ * - 把 `visibleGlobalPageIndices` 反向回传给 chapter-manager 驱动按需加载/卸载。
262
+ *
263
+ * 不直接持有 @embedpdf/plugin-viewport / plugin-scroll —— 它在 `ChapterScroller`
264
+ * 组件内部自己挂滚动监听,避免与单文档版本冲突。
265
+ */
266
+ export declare class ChapterScrollPlugin extends BasePlugin<ChapterScrollPluginConfig, ChapterScrollCapability> {
267
+ static readonly id: "chapter-scroll";
268
+ private readonly layoutChange$;
269
+ private readonly visibleChange$;
270
+ private config;
271
+ private chapterManager;
272
+ private documentManager;
273
+ private virtualPageMap;
274
+ /** 每个页位的真实尺寸(key = globalPageIndex),未上报前用占位 */
275
+ private readonly pageSizes;
276
+ /** 累计后的纵向偏移缓存(key = globalPageIndex) */
277
+ private offsets;
278
+ private totalHeight;
279
+ private totalWidth;
280
+ private viewportEl;
281
+ private viewportObservers;
282
+ private currentVisible;
283
+ private currentGlobalPageIndex;
284
+ private chapterManagerUnsubs;
285
+ constructor(id: string, registry: PluginRegistry);
286
+ initialize(config: ChapterScrollPluginConfig): Promise<void>;
287
+ /** 章节 PDF 在 document-manager 中是否已可渲染(不依赖 chapter-manager.status,避免事件丢失) */
288
+ private isChapterDocumentReady;
289
+ private refreshLayout;
290
+ /** 对已打开且可渲染的章节补采页尺寸 */
291
+ private syncReadyChapterSizes;
292
+ protected onDocumentLoaded(documentId: string): void;
293
+ protected onDocumentClosed(documentId: string): void;
294
+ protected buildCapability(): ChapterScrollCapability;
295
+ destroy(): void;
296
+ private getPageSize;
297
+ private rebuildOffsets;
298
+ private applyChapterPageSizes;
299
+ /** 章节 document 在 core store 中的缩放(与 RenderLayer / Annotation 一致) */
300
+ private getChapterDocumentScale;
301
+ /** 从已加载的 PdfDocumentObject 拉取章节内所有页尺寸并上报 */
302
+ private harvestChapterSizes;
303
+ /** core SET_SCALE 后重算布局,使滚动占位与 PDF 渲染尺寸一致 */
304
+ protected onScaleChanged(documentId: string): void;
305
+ private dropChapterSizes;
306
+ private bindViewport;
307
+ private recomputeVisible;
308
+ private findFirstVisibleIndex;
309
+ private computeLayout;
310
+ private scrollToIndex;
311
+ private scrollToGlobalPdfPoint;
312
+ private scrollToChapter;
313
+ private scrollToGlobalNumber;
314
+ }
315
+
316
+ declare interface ChapterScrollPluginConfig extends BasePluginConfig {
317
+ /** 章节尚未加载时占位页高度(CSS 像素),默认 1200 */
318
+ placeholderPageHeight?: number;
319
+ /** 占位页宽度(CSS 像素),默认 900 */
320
+ placeholderPageWidth?: number;
321
+ /** 上下 buffer 页数,默认 2 */
322
+ bufferSize?: number;
323
+ /** 页间距,默认 20 */
324
+ pageGap?: number;
325
+ }
326
+
327
+ declare interface ChapterScrollScrollToOptions {
328
+ /** behavior 默认 'auto' */
329
+ behavior?: ScrollBehavior;
330
+ /** 距离顶部的偏移(CSS 像素),默认 0 */
331
+ topOffset?: number;
332
+ }
333
+
334
+ declare interface ChapterScrollScrollToPdfPointOptions {
335
+ behavior?: ScrollBehavior;
336
+ /** 目标点距视口顶部的留白(CSS 像素),默认 80 */
337
+ marginTop?: number;
338
+ }
339
+
340
+ /**
341
+ * 章节 PDF 来源(由业务在 manifest 中提供):
342
+ * - `url`:直接打开该地址
343
+ * - `buffer`:已取回的 PDF 二进制
344
+ * - `load`:按章节自定义拉取(鉴权、本地 FS 等)
345
+ */
346
+ export declare type ChapterSource = {
347
+ url: string;
348
+ } | {
349
+ buffer: ArrayBuffer;
350
+ } | {
351
+ load: () => Promise<ChapterPdfPayload>;
352
+ };
353
+
354
+ declare interface ChapterStatusEvent {
355
+ chapterId: string;
356
+ status: ChapterLoadStatus;
357
+ /** 仅在 status === 'error' 时有意义 */
358
+ error?: {
359
+ message: string;
360
+ code?: number;
361
+ };
362
+ }
363
+
364
+ /** 章节目录树节点(仅 UI;内容由业务构造) */
365
+ export declare type ChapterTreeNode = {
366
+ id: string;
367
+ title: string;
368
+ startPage: number;
369
+ endPage: number;
370
+ children?: ChapterTreeNode[];
371
+ };
372
+
373
+ export declare function ChapterTreePanel({ tree, activeChapterId, onActiveChapterChange, }: ChapterTreePanelProps): JSX_2.Element;
374
+
375
+ export declare type ChapterTreePanelProps = {
376
+ tree: ChapterTreeNode[];
377
+ activeChapterId: string;
378
+ onActiveChapterChange?: (chapterId: string) => void;
379
+ };
380
+
381
+ /** 目录树 + 章节 manifest,由业务组装后传入阅读器 */
382
+ export declare type ChapterViewerCatalog = {
383
+ tree: ChapterTreeNode[];
384
+ manifest: ChapterManifest;
385
+ };
386
+
387
+ /** 章节渲染器集成功能开关(与 demo 默认样式对齐) */
388
+ export declare interface ChapterViewerFeaturesConfig {
389
+ /** 划线/高亮 */
390
+ markup?: {
391
+ enabled?: boolean;
392
+ styles?: MarkupStylesConfig;
393
+ };
394
+ /** 段落书签(含悬停添加) */
395
+ bookmarks?: {
396
+ enabled?: boolean;
397
+ marker?: BookmarkMarkerUiConfig_2;
398
+ hover?: HoverBookmarkUiConfig_2;
399
+ };
400
+ /** 笔记 */
401
+ notes?: {
402
+ enabled?: boolean;
403
+ marker?: NoteMarkerUiConfig;
404
+ };
405
+ /** 选区浮窗 */
406
+ selectionToolbar?: SelectionToolbarConfig;
407
+ /** 缩放 */
408
+ zoom?: ChapterViewerZoomConfig;
409
+ }
410
+
411
+ declare interface ChapterViewerZoomConfig {
412
+ /** 是否启用 pinch/滑块缩放容器,默认 true */
413
+ enabled?: boolean;
414
+ min?: number;
415
+ max?: number;
416
+ initial?: number;
417
+ }
418
+
419
+ /**
420
+ * 创建带默认划线/笔记/书签/选区 card 的章节编辑器插件包。
421
+ * 传入的 `features` 与默认值浅合并。
422
+ */
423
+ export declare function createChapterViewerEditor(options: CreatePdfChapterEditorOptions): PdfChapterEditorBundle;
424
+
425
+ export declare function createChapterViewerEditorOptions(input: CreateChapterViewerEditorOptionsInput): Omit<CreatePdfChapterEditorOptions, 'features'>;
426
+
427
+ export declare type CreateChapterViewerEditorOptionsInput = {
428
+ manifest: ChapterManifest;
429
+ chapterPdfLoader?: IChapterPdfLoader;
430
+ bookmarks: PdfChapterEditorBookmarksConfig;
431
+ notes: PdfChapterEditorNotesConfig;
432
+ };
433
+
434
+ declare interface CreateEditorUiSchemaOptions {
435
+ /** 默认全开 */
436
+ enabledModes?: EditorModeId[];
437
+ customOperations?: OperationSpec[];
438
+ /** 合并进最终 schema 的额外 toolbars / menus 等 */
439
+ extend?: Partial<Pick<UISchema, 'toolbars' | 'menus' | 'sidebars' | 'modals' | 'selectionMenus'>>;
440
+ }
441
+
442
+ /**
443
+ * 组装章节 PDF 编辑器所需的插件注册列表与 UI Schema。
444
+ * 不挂载 `@embedpdf/plugin-scroll`;滚动由 `ChapterScrollPlugin` + `ChapterScroller` 负责。
445
+ */
446
+ export declare function createPdfChapterEditor(options: CreatePdfChapterEditorOptions): PdfChapterEditorBundle;
447
+
448
+ export declare interface CreatePdfChapterEditorOptions {
449
+ manifest: ChapterManifest;
450
+ overlapStrategy?: OverlapOwnerStrategy;
451
+ passwordProvider?: IPasswordProvider;
452
+ /** 章节未在 manifest 中写 source 时,由此加载 PDF */
453
+ chapterPdfLoader?: IChapterPdfLoader;
454
+ notes?: PdfChapterEditorNotesConfig;
455
+ bookmarks?: PdfChapterEditorBookmarksConfig;
456
+ toolbar?: PdfChapterEditorToolbarConfig;
457
+ /** 传给 chapter-manager;manifest 就绪后预取前 N 章 */
458
+ prefetchChapters?: number;
459
+ /** 为 false 时不拉取 CDN 默认图章库(@embedpdf/default-stamps) */
460
+ loadDefaultStampLibrary?: boolean;
461
+ unloadTimeoutMs?: number;
462
+ /** 传给 chapter-scroll */
463
+ placeholderPageHeight?: number;
464
+ placeholderPageWidth?: number;
465
+ /** 合并进 Commands 插件(如 mode / annotation / form 等) */
466
+ commands?: Record<string, Command>;
467
+ /**
468
+ * 章节阅读器集成功能(划线/笔记/书签/选区 card / 缩放)。
469
+ * 默认 demo 样式;各子项可单独关闭或扩展。
470
+ */
471
+ features?: ChapterViewerFeaturesConfig;
472
+ }
473
+
474
+ /** 与 demo 对齐的默认集成功能 */
475
+ export declare const DEFAULT_CHAPTER_VIEWER_FEATURES: ChapterViewerFeaturesConfig;
476
+
477
+ /** 与 snippet 主工具栏 mode tabs 对齐的编辑模式 */
478
+ declare type EditorModeId = 'view' | 'annotate' | 'shapes' | 'insert' | 'form' | 'redact';
479
+
480
+ /** Snippet-derived secondary toolbars for Annotate / Shapes / Insert / Form / Redact */
481
+ declare const editorSecondaryToolbars: Record<string, ToolbarSchema>;
482
+
483
+ export { EmbedPDF }
484
+
485
+ declare interface HoverBookmarkUiConfig {
486
+ renderAddIcon?: () => ReactNode;
487
+ iconSize?: number;
488
+ }
489
+
490
+ declare interface HoverBookmarkUiConfig_2 {
491
+ /** 悬停行末「添加书签」自定义图标;无背景 */
492
+ renderAddIcon?: () => unknown;
493
+ iconSize?: number;
494
+ }
495
+
496
+ /**
497
+ * 全局章节 PDF 加载器:当 `ChapterDescriptor.source` 未提供 url/buffer/load 时使用。
498
+ * 适合统一走业务 API、鉴权下载等场景。
499
+ */
500
+ export declare interface IChapterPdfLoader {
501
+ loadPdf(chapter: ChapterDescriptor): Promise<ChapterPdfPayload>;
502
+ }
503
+
504
+ /**
505
+ * 章节加密的抽象接口:当某章节首次或重试加载因密码失败时,
506
+ * `ChapterManagerPlugin` 会向 provider 询问密码。
507
+ *
508
+ * 返回 `null` 表示用户/系统放弃,对应章节进入 `password-required` 状态。
509
+ */
510
+ declare interface IPasswordProvider {
511
+ /**
512
+ * @param chapter 失败章节描述
513
+ * @param attempt 已经尝试次数(0 = 首次),可用于实现"输错三次锁定"等策略
514
+ */
515
+ resolvePassword(chapter: ChapterDescriptor, attempt: number): Promise<string | null>;
516
+ /** 可选:同步快查缓存,避免显式 await */
517
+ getCachedPassword?(chapterId: string): string | null;
518
+ }
519
+
520
+ /** 单种划线的样式(颜色、粗细、垂直偏移,PDF 点) */
521
+ export declare interface MarkupKindStyle {
522
+ /** 描边/填充色,如 #facc15 */
523
+ color?: string;
524
+ /** 线宽(下划线/删除线等),PDF 点 */
525
+ thickness?: number;
526
+ /** 相对字形底边的垂直偏移,正值向下(PDF 点) */
527
+ offsetY?: number;
528
+ opacity?: number;
529
+ }
530
+
531
+ export declare type MarkupStylesConfig = Partial<Record<SelectionMarkupKind, MarkupKindStyle>>;
532
+
533
+ /**
534
+ * 一条附注(note)的位置锚点。
535
+ * - `rectsPdfCoord` 来自 selection.getHighlightRectsForPage 的 PDF 坐标系
536
+ * - `endAnchor` 用于"末尾图标"渲染:取选区最后一行 right 边缘
537
+ * - `noteId` 由开发者回调返回(服务端 ID),插件本身不生成
538
+ */
539
+ export declare interface NoteAnchor {
540
+ noteId: string;
541
+ chapterId: string;
542
+ globalPageIndex: number;
543
+ globalPageNumber: number;
544
+ localPageIndex: number;
545
+ rectsPdfCoord: Rect[];
546
+ endAnchor: {
547
+ x: number;
548
+ y: number;
549
+ };
550
+ selectedText: string;
551
+ /** 用户填写的笔记正文(由业务持久化) */
552
+ content?: string;
553
+ }
554
+
555
+ export declare interface NoteCallbacks {
556
+ /** 初次加载已有附注 */
557
+ loadNotes?: () => Promise<NoteAnchor[]>;
558
+ /**
559
+ * 内置创建:持久化后返回 noteId。
560
+ * 与 onRequestCreateNote 二选一(至少配置其一)。
561
+ */
562
+ onCreateNote?: (draft: NoteDraft) => Promise<{
563
+ noteId: string;
564
+ } | null>;
565
+ /**
566
+ * 自定义创建弹窗:仅发出事件,由宿主 complete(noteId)。
567
+ * 配置后划词/默认流程不再调用 onCreateNote。
568
+ */
569
+ onRequestCreateNote?: (payload: NoteCreateRequestPayload_2) => void;
570
+ /** 自定义编辑:传出 noteId */
571
+ onRequestEditNote?: (noteId: string, anchor: NoteAnchor) => void;
572
+ onUpdateNote?: (note: NoteAnchor) => Promise<void>;
573
+ onDeleteNote?: (noteId: string) => Promise<void>;
574
+ /** 点击编辑且未配置 onRequestEditNote 时回退 */
575
+ onActivateNote?: (noteId: string, anchor: NoteAnchor) => void;
576
+ }
577
+
578
+ /** 笔记创建请求(划词选「笔记」或宿主触发) */
579
+ export declare interface NoteCreateRequestPayload {
580
+ draft: NoteDraft;
581
+ /** 用户完成创建后调用,传入业务 noteId */
582
+ complete: (noteId: string) => Promise<void>;
583
+ }
584
+
585
+ /** 自定义笔记创建:宿主打开 UI 后调用 complete(noteId) */
586
+ declare interface NoteCreateRequestPayload_2 {
587
+ draft: NoteDraft;
588
+ complete: (noteId: string) => Promise<void>;
589
+ }
590
+
591
+ /** 一个尚未持久化的草稿(开发者回调拿到的) */
592
+ export declare type NoteDraft = Omit<NoteAnchor, 'noteId'>;
593
+
594
+ declare interface NoteMarkerMenuActionCtx {
595
+ note: NoteAnchor;
596
+ onEdit: () => void;
597
+ onDelete: () => void;
598
+ }
599
+
600
+ declare interface NoteMarkerUiConfig {
601
+ /** 自定义笔记标识图标;提供时无圆形背景 */
602
+ renderIcon?: (ctx: {
603
+ note: NoteAnchor;
604
+ }) => unknown;
605
+ /** 完全自定义编辑/删除区域;不提供则使用默认 card */
606
+ renderMenuActions?: (ctx: NoteMarkerMenuActionCtx) => unknown;
607
+ iconSize?: number;
608
+ /** 笔记高亮底色的 CSS 颜色,默认 rgba(245,158,11,0.08) */
609
+ highlightColor?: string;
610
+ }
611
+
612
+ declare interface OperationHandlerContext {
613
+ documentId: string | null;
614
+ chapterId: string | null;
615
+ }
616
+
617
+ /**
618
+ * 收集开发者自定义操作,并把它们注入到 secondary toolbar 的 items 里。
619
+ * Commands 插件侧的 register 由宿主在引擎初始化时根据 spec.handler 完成。
620
+ */
621
+ declare class OperationRegistry {
622
+ private readonly specs;
623
+ register(operation: OperationSpec): void;
624
+ registerAll(operations: OperationSpec[]): void;
625
+ list(): readonly OperationSpec[];
626
+ /**
627
+ * 返回注入了 customOperations 的 toolbar 副本(不修改原始 fragment)。
628
+ */
629
+ buildToolbars(): typeof editorSecondaryToolbars;
630
+ }
631
+
632
+ /** 自定义操作挂载到某条 secondary toolbar */
633
+ declare interface OperationSpec {
634
+ id: string;
635
+ modeId: EditorModeId;
636
+ /** 对应 {@link editorSecondaryToolbars} 的 key */
637
+ toolbarSlot: 'annotation-toolbar' | 'shapes-toolbar' | 'insert-toolbar' | 'form-toolbar' | 'redaction-toolbar';
638
+ /** 插入到某 toolbar item 之后;缺省则追加到 tools group 末尾 */
639
+ position?: {
640
+ after?: string;
641
+ before?: string;
642
+ };
643
+ commandId: string;
644
+ icon?: string;
645
+ i18nKey?: string;
646
+ label?: string;
647
+ categories?: string[];
648
+ /** 注册到 Commands 插件时的执行体(由宿主在 createPdfChapterEditor 里注入) */
649
+ handler?: (ctx: OperationHandlerContext) => void | Promise<void>;
650
+ }
651
+
652
+ /**
653
+ * 决定相邻章节在重叠页上谁拥有该页(owner)。
654
+ * - first-wins / last-wins:按 manifest 顺序的先到/后到
655
+ * - explicit:依赖 `ChapterDescriptor.ownedGlobalPages`
656
+ * - custom:开发者完全接管
657
+ */
658
+ declare type OverlapOwnerStrategy = {
659
+ kind: 'first-wins';
660
+ } | {
661
+ kind: 'last-wins';
662
+ } | {
663
+ kind: 'explicit';
664
+ } | {
665
+ kind: 'custom';
666
+ resolve: (globalPage: number, candidates: ChapterDescriptor[]) => string;
667
+ };
668
+
669
+ export declare interface ParagraphBookmark {
670
+ id: string;
671
+ label: string;
672
+ /** 业务可选元数据;插件直接存不解释 */
673
+ metadata?: Record<string, unknown>;
674
+ anchor: {
675
+ chapterId: string;
676
+ localPageIndex: number;
677
+ /** 创建时虚拟页索引(与附注一致,避免 toGlobal 映射偏差) */
678
+ globalPageIndex?: number;
679
+ /** 创建时业务页号 */
680
+ globalPageNumber?: number;
681
+ /** PDF 坐标系包围盒(多行选区时为各行并集) */
682
+ rectPdfCoord: Rect;
683
+ /** 各行 PDF 矩形(划词书签时与选区高亮一致) */
684
+ rectsPdfCoord?: Rect[];
685
+ /** 书签图标锚点(通常为选区末行右下角,PDF 坐标) */
686
+ markerAnchor?: {
687
+ x: number;
688
+ y: number;
689
+ };
690
+ };
691
+ createdAt: number;
692
+ }
693
+
694
+ declare interface ParagraphBookmarkCallbacks {
695
+ /** 初次加载已有书签 */
696
+ load?: () => Promise<ParagraphBookmark[]>;
697
+ /** 任意变更(新增 / 删除 / 改名)后回调,便于持久化 */
698
+ persist?: (entries: ParagraphBookmark[]) => Promise<void>;
699
+ /**
700
+ * 用户请求删除书签:由外部完成持久化删除。
701
+ * 返回 true 时插件会从渲染层移除该书签。
702
+ */
703
+ onRequestRemove?: (bookmark: ParagraphBookmark) => Promise<boolean>;
704
+ /** 书签已从插件内存移除后通知(便于 UI 收尾) */
705
+ onRemoveSuccess?: (bookmarkId: string) => void;
706
+ }
707
+
708
+ declare interface ParagraphBookmarkPluginConfig extends BasePluginConfig {
709
+ callbacks?: ParagraphBookmarkCallbacks;
710
+ ui?: BookmarkMarkerUiConfig;
711
+ hover?: HoverBookmarkUiConfig;
712
+ }
713
+
714
+ export declare interface PdfChapterEditorBookmarksConfig {
715
+ callbacks: NonNullable<ParagraphBookmarkPluginConfig['callbacks']>;
716
+ }
717
+
718
+ declare interface PdfChapterEditorBundle {
719
+ plugins: PluginBatchRegistration<any, any, any, any>[];
720
+ uiSchema: UISchema;
721
+ operationRegistry: OperationRegistry;
722
+ }
723
+
724
+ export declare interface PdfChapterEditorNotesConfig {
725
+ callbacks: NoteCallbacks;
726
+ }
727
+
728
+ declare interface PdfChapterEditorToolbarConfig extends CreateEditorUiSchemaOptions {
729
+ }
730
+
731
+ export { PdfChapterViewport }
732
+
733
+ export { PdfChapterViewportProps }
734
+
735
+ /** 划线类型 */
736
+ declare type SelectionMarkupKind = 'highlight' | 'underline' | 'squiggly' | 'strikeout';
737
+
738
+ declare interface SelectionToolbarConfig {
739
+ /** 是否显示默认 card,默认 true */
740
+ enabled?: boolean;
741
+ /** 隐藏部分内置按钮 */
742
+ hiddenBuiltinActions?: BuiltinSelectionToolbarAction[];
743
+ /** 扩展操作(由宿主在 buildSelectionMenu 或 onExtraAction 中处理) */
744
+ extraActions?: SelectionToolbarExtraAction[];
745
+ }
746
+
747
+ /** 扩展选区操作 */
748
+ export declare interface SelectionToolbarExtraAction {
749
+ id: string;
750
+ label: string;
751
+ /** 排序权重,越小越靠前(在内置 markup 之后、note 之前) */
752
+ order?: number;
753
+ }
754
+
755
+ export { useCapability }
756
+
757
+ export { usePdfiumEngine }
758
+
759
+ /**
760
+ * 一个虚拟页位的解析结果。`localPageIndex` 是 owner 章节 PDF 内的 0-based 索引。
761
+ */
762
+ declare interface VirtualPageLocation {
763
+ globalPageIndex: number;
764
+ globalPageNumber: number;
765
+ chapterId: string;
766
+ localPageIndex: number;
767
+ }
768
+
769
+ /**
770
+ * 跨章节 PDF 的「全局页 ↔ (章节, 本地页)」映射。
771
+ *
772
+ * 设计要点:
773
+ * - 「globalPageNumber」是后端 manifest 里的业务页号,可能不连续(极端情况)。
774
+ * - 「globalPageIndex」是去重后排序的 0-based 紧凑索引,是滚动/虚拟列表使用的页位。
775
+ * 这样上层 `ChapterScroll` 不必关心业务页号是否连续。
776
+ */
777
+ declare class VirtualPageMap {
778
+ private readonly _pages;
779
+ private readonly _byChapter;
780
+ private readonly _byGlobalNumber;
781
+ constructor(pages: VirtualPageLocation[]);
782
+ get totalPages(): number;
783
+ /** 顺序返回所有去重后的页位 */
784
+ list(): readonly VirtualPageLocation[];
785
+ /** 由 0-based 紧凑索引取页位 */
786
+ atIndex(globalPageIndex: number): VirtualPageLocation | null;
787
+ /** 由后端业务页号取页位 */
788
+ byGlobalNumber(globalPageNumber: number): VirtualPageLocation | null;
789
+ /** 由 (章节, 本地页) 反查到 owner 视图下的全局位置;非 owner 章节会返回 null */
790
+ toGlobal(chapterId: string, localPageIndex: number): VirtualPageLocation | null;
791
+ /** 该章节在虚拟视图中实际「被采用」的页(owner 命中的) */
792
+ pagesOfChapter(chapterId: string): readonly VirtualPageLocation[];
793
+ /** 拿一个章节首次出现的虚拟索引(用于 scrollToChapter) */
794
+ firstIndexOfChapter(chapterId: string): number;
795
+ }
796
+
797
+ declare interface VisibleChangeEvent {
798
+ /** 当前可见页紧凑索引(去重后的全局序号),按顺序 */
799
+ visibleGlobalPageIndices: number[];
800
+ currentGlobalPageIndex: number;
801
+ }
802
+
803
+ export { }