pdf-h5-react 0.0.0-stage → 0.3.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/LICENSE +21 -0
- package/README.md +430 -2
- package/dist/components/AnnotationLayer.d.ts +26 -0
- package/dist/components/LinkLayer.d.ts +17 -0
- package/dist/components/OutlinePanel.d.ts +8 -0
- package/dist/components/PageCanvas.d.ts +41 -0
- package/dist/components/PageThumbnail.d.ts +23 -0
- package/dist/components/PdfH5Reader.d.ts +101 -0
- package/dist/components/SearchPanel.d.ts +18 -0
- package/dist/components/StatusOverlay.d.ts +15 -0
- package/dist/components/TextLayer.d.ts +26 -0
- package/dist/components/ThumbnailPanel.d.ts +18 -0
- package/dist/components/Toolbar.d.ts +36 -0
- package/dist/core/annotations.d.ts +91 -0
- package/dist/core/cache.d.ts +96 -0
- package/dist/core/errors.d.ts +12 -0
- package/dist/core/eventEmitter.d.ts +43 -0
- package/dist/core/gestures.d.ts +71 -0
- package/dist/core/layout.d.ts +109 -0
- package/dist/core/layoutAdapter.d.ts +36 -0
- package/dist/core/lru.d.ts +57 -0
- package/dist/core/metrics.d.ts +22 -0
- package/dist/core/pdfjs.d.ts +51 -0
- package/dist/core/readerEvents.d.ts +116 -0
- package/dist/core/renderQueue.d.ts +45 -0
- package/dist/core/throttle.d.ts +40 -0
- package/dist/core/zoomAnimation.d.ts +33 -0
- package/dist/hooks/useElementSize.d.ts +18 -0
- package/dist/hooks/usePageMetrics.d.ts +27 -0
- package/dist/hooks/usePdfDocument.d.ts +19 -0
- package/dist/hooks/usePinchGesture.d.ts +41 -0
- package/dist/hooks/useVirtualPages.d.ts +48 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +3226 -0
- package/dist/lib/highlight.d.ts +9 -0
- package/dist/lib/outline.d.ts +35 -0
- package/dist/lib/search.d.ts +38 -0
- package/dist/lib/text.d.ts +40 -0
- package/dist/lib/thumbnail.d.ts +18 -0
- package/dist/pdf-h5-react.css +1 -0
- package/dist/types.d.ts +145 -0
- package/package.json +84 -4
- package/scripts/copy-pdfjs-assets.mjs +100 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PDFDocumentProxy, PDFDocumentLoadingTask } from 'pdfjs-dist';
|
|
2
|
+
import { PdfSource } from '../types';
|
|
3
|
+
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
|
+
/**
|
|
5
|
+
* pdf.js 的 DocumentInitParameters 在 6.x 里已不再从包根导出,
|
|
6
|
+
* 这里从类型声明的实际路径推导,避免把内部结构写死。
|
|
7
|
+
*/
|
|
8
|
+
type DocumentInitParameters = Parameters<typeof pdfjsLib.getDocument>[0];
|
|
9
|
+
/**
|
|
10
|
+
* pdf.js 运行时配置。
|
|
11
|
+
*
|
|
12
|
+
* 默认使用 jsDelivr CDN 上「与当前依赖版本严格一致」的 worker / cmaps /
|
|
13
|
+
* standard_fonts / wasm,因此库可以零配置直接跑起来。生产环境建议自托管:
|
|
14
|
+
* 运行 `npm run assets`(或手动拷贝 pdfjs-dist 的这几个目录),然后调用
|
|
15
|
+
* `configurePdfjs({ workerSrc: '/pdfjs/pdf.worker.min.mjs', ... })`。
|
|
16
|
+
*/
|
|
17
|
+
export declare const PDFJS_VERSION: string;
|
|
18
|
+
export interface PdfjsRuntimeOptions {
|
|
19
|
+
workerSrc?: string;
|
|
20
|
+
cMapUrl?: string;
|
|
21
|
+
standardFontDataUrl?: string;
|
|
22
|
+
wasmUrl?: string;
|
|
23
|
+
iccUrl?: string;
|
|
24
|
+
/** 0 = errors, 1 = warnings, 5 = infos(pdf.js VerbosityLevel) */
|
|
25
|
+
verbosity?: number;
|
|
26
|
+
}
|
|
27
|
+
/** 覆盖 pdf.js 的静态资源地址(worker / cmaps / 字体 / wasm) */
|
|
28
|
+
export declare function configurePdfjs(options: PdfjsRuntimeOptions): void;
|
|
29
|
+
export declare function getPdfjsRuntimeOptions(): Readonly<PdfjsRuntimeOptions>;
|
|
30
|
+
export { pdfjsLib };
|
|
31
|
+
/** 把各种 PdfSource 归一化成 pdf.js 的 DocumentInitParameters */
|
|
32
|
+
export declare function toDocumentParams(source: PdfSource, extra?: Record<string, unknown>): DocumentInitParameters;
|
|
33
|
+
export interface LoadPdfOptions {
|
|
34
|
+
password?: string;
|
|
35
|
+
onProgress?: (loaded: number, total: number) => void;
|
|
36
|
+
onPassword?: (reason: number) => void;
|
|
37
|
+
/** 允许 pdf.js 在解析出错时尽量恢复,默认 true */
|
|
38
|
+
stopAtErrors?: boolean;
|
|
39
|
+
/** 关闭 worker 端 OffscreenCanvas(部分老安卓内核更稳) */
|
|
40
|
+
disableOffscreenCanvas?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface LoadedPdf {
|
|
43
|
+
doc: PDFDocumentProxy;
|
|
44
|
+
task: PDFDocumentLoadingTask;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 加载 PDF。注意:调用方负责在卸载时销毁返回值里的 task。
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadPdf(source: PdfSource, options?: LoadPdfOptions): LoadedPdf;
|
|
50
|
+
/** 便捷方法:等待加载完成并返回文档代理 */
|
|
51
|
+
export declare function loadPdfDocument(source: PdfSource, options?: LoadPdfOptions): Promise<PDFDocumentProxy>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { PDFDocumentProxy } from 'pdfjs-dist';
|
|
2
|
+
/** 渲染一页的耗时信息 */
|
|
3
|
+
export interface RenderTiming {
|
|
4
|
+
pageNumber: number;
|
|
5
|
+
/** 本页渲染耗时(ms) */
|
|
6
|
+
pageTime: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ReaderStatus {
|
|
9
|
+
/** 文档是否已就绪 */
|
|
10
|
+
ready: boolean;
|
|
11
|
+
/** 是否正在加载 */
|
|
12
|
+
loading: boolean;
|
|
13
|
+
/** 总页数,未就绪时为 0 */
|
|
14
|
+
total: number;
|
|
15
|
+
/** 当前页(1 基) */
|
|
16
|
+
page: number;
|
|
17
|
+
/** 当前缩放倍率 */
|
|
18
|
+
zoom: number;
|
|
19
|
+
/** 已解析尺寸的页数(渐进式度量进度) */
|
|
20
|
+
measured: number;
|
|
21
|
+
/** 位图缓存估算占用(字节) */
|
|
22
|
+
cacheBytes: number;
|
|
23
|
+
/** 已挂载的页面 DOM 数(虚拟化效果的直接体现) */
|
|
24
|
+
mountedPages: number;
|
|
25
|
+
/** 最近一次错误信息 */
|
|
26
|
+
error: string | null;
|
|
27
|
+
/** 手势缩放是否启用 */
|
|
28
|
+
zoomEnabled: boolean;
|
|
29
|
+
/** 滚动是否启用 */
|
|
30
|
+
scrollEnabled: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface ZoomEventPayload {
|
|
33
|
+
zoom: number;
|
|
34
|
+
/** 相对缩放开始时的倍率变化 */
|
|
35
|
+
scaleChange: number;
|
|
36
|
+
/** 手势 / 动画开始时的倍率 */
|
|
37
|
+
startZoom: number;
|
|
38
|
+
/** 本次缩放耗时(ms),动画结束或手势结束时给出 */
|
|
39
|
+
duration: number;
|
|
40
|
+
/** 触发来源,便于区分埋点 */
|
|
41
|
+
source: 'gesture' | 'doubleTap' | 'button' | 'wheel' | 'api' | 'reset';
|
|
42
|
+
}
|
|
43
|
+
export interface ScrollEventPayload {
|
|
44
|
+
scrollTop: number;
|
|
45
|
+
scrollLeft: number;
|
|
46
|
+
currentPage: number;
|
|
47
|
+
/** 卷动进度 0-1 */
|
|
48
|
+
progress: number;
|
|
49
|
+
}
|
|
50
|
+
export interface ReaderEvents {
|
|
51
|
+
/** 开始初始化(文档尚未加载) */
|
|
52
|
+
init: {
|
|
53
|
+
src: unknown;
|
|
54
|
+
};
|
|
55
|
+
/** 文档已加载,可以拿到总页数 */
|
|
56
|
+
ready: {
|
|
57
|
+
doc: PDFDocumentProxy;
|
|
58
|
+
total: number;
|
|
59
|
+
};
|
|
60
|
+
/** 加载失败 */
|
|
61
|
+
error: {
|
|
62
|
+
error: Error;
|
|
63
|
+
message: string;
|
|
64
|
+
time: number;
|
|
65
|
+
};
|
|
66
|
+
/** 某一页渲染完成 */
|
|
67
|
+
render: RenderTiming & {
|
|
68
|
+
totalTime: number;
|
|
69
|
+
};
|
|
70
|
+
/** 渲染成功(首屏可用) */
|
|
71
|
+
success: {
|
|
72
|
+
message: string;
|
|
73
|
+
time: number;
|
|
74
|
+
};
|
|
75
|
+
/** 加载流程结束(无论成功失败都会触发,与 pdfh5 的 complete 语义一致) */
|
|
76
|
+
complete: {
|
|
77
|
+
status: 'success' | 'error';
|
|
78
|
+
message: string;
|
|
79
|
+
time: number;
|
|
80
|
+
};
|
|
81
|
+
/** 滚动(已节流) */
|
|
82
|
+
scroll: ScrollEventPayload;
|
|
83
|
+
/** 当前页变化 */
|
|
84
|
+
pageChange: {
|
|
85
|
+
page: number;
|
|
86
|
+
total: number;
|
|
87
|
+
};
|
|
88
|
+
/** 缩放值变化(手势过程中也会触发,已节流) */
|
|
89
|
+
zoom: {
|
|
90
|
+
zoom: number;
|
|
91
|
+
source: ZoomEventPayload['source'];
|
|
92
|
+
};
|
|
93
|
+
/** 缩放开始 */
|
|
94
|
+
zoomStart: {
|
|
95
|
+
zoom: number;
|
|
96
|
+
source: ZoomEventPayload['source'];
|
|
97
|
+
};
|
|
98
|
+
/** 缩放结束(含动画) */
|
|
99
|
+
zoomEnd: ZoomEventPayload;
|
|
100
|
+
/** 缩放开关变化 */
|
|
101
|
+
zoomEnabled: {
|
|
102
|
+
enabled: boolean;
|
|
103
|
+
};
|
|
104
|
+
/** 滚动开关变化 */
|
|
105
|
+
scrollEnabled: {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
};
|
|
108
|
+
/** 用户点击回到顶部 */
|
|
109
|
+
backTop: {
|
|
110
|
+
from: number;
|
|
111
|
+
};
|
|
112
|
+
/** 组件销毁 */
|
|
113
|
+
destroy: Record<string, never>;
|
|
114
|
+
}
|
|
115
|
+
export type ReaderEventName = keyof ReaderEvents;
|
|
116
|
+
export type ReaderEventPayload<K extends ReaderEventName> = ReaderEvents[K];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type RenderPriority = 'visible' | 'prefetch';
|
|
2
|
+
export interface RenderQueueOptions {
|
|
3
|
+
visibleConcurrency?: number;
|
|
4
|
+
prefetchConcurrency?: number;
|
|
5
|
+
/** 任务之间让出主线程的延迟(ms),默认 0 */
|
|
6
|
+
yieldDelay?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class RenderQueue {
|
|
9
|
+
private jobs;
|
|
10
|
+
private readonly running;
|
|
11
|
+
private visibleRunning;
|
|
12
|
+
private prefetchRunning;
|
|
13
|
+
private readonly visibleConcurrency;
|
|
14
|
+
private readonly prefetchConcurrency;
|
|
15
|
+
private readonly yieldDelay;
|
|
16
|
+
private pumping;
|
|
17
|
+
private stats;
|
|
18
|
+
constructor(options?: RenderQueueOptions);
|
|
19
|
+
/** 提交任务;同 key 已在排队或执行中则复用其 Promise(引用计数 +1) */
|
|
20
|
+
enqueue<T>(key: string, priority: RenderPriority, run: (signal: AbortSignal) => Promise<T>): Promise<T>;
|
|
21
|
+
/**
|
|
22
|
+
* 归还一次使用权(引用计数 -1),归零时才真正取消。
|
|
23
|
+
*
|
|
24
|
+
* 为什么不能直接 cancel:任务在多个调用方之间共享(同一 page@scale 可能被
|
|
25
|
+
* 可见区与预取区同时需要;React 严格模式下 effect 也会挂载两次)。
|
|
26
|
+
* 「谁先卸载谁就 cancel」会把别人仍需的任务杀掉 —— 表现为页面一直空白:
|
|
27
|
+
* 任务被 abort → Promise reject → 没有重试者。
|
|
28
|
+
*/
|
|
29
|
+
release(key: string, reason?: unknown): void;
|
|
30
|
+
/** 取消某个 key(排队中直接丢弃,执行中触发 abort) */
|
|
31
|
+
cancel(key: string, reason?: unknown): void;
|
|
32
|
+
/** 丢弃所有未开始的预取任务,返回丢弃数量 */
|
|
33
|
+
dropPendingPrefetch(keep?: (key: string) => boolean): number;
|
|
34
|
+
get pending(): number;
|
|
35
|
+
get active(): number;
|
|
36
|
+
getStats(): {
|
|
37
|
+
started: number;
|
|
38
|
+
completed: number;
|
|
39
|
+
cancelled: number;
|
|
40
|
+
};
|
|
41
|
+
cancelAll(reason?: unknown): void;
|
|
42
|
+
private canStart;
|
|
43
|
+
private pump;
|
|
44
|
+
private start;
|
|
45
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 高频事件节流工具。
|
|
3
|
+
*
|
|
4
|
+
* H5 阅读器里滚动、捏合、尺寸变化、进度、搜索输入都是高频源,
|
|
5
|
+
* 一律先经过这里的三个工具再进入 React 状态,避免「一帧多次 setState」。
|
|
6
|
+
*/
|
|
7
|
+
export type AnyFn = (...args: any[]) => any;
|
|
8
|
+
export interface Cancelable {
|
|
9
|
+
cancel(): void;
|
|
10
|
+
/** 立即执行挂起的调用(用于离开页面 / 提交前冲刷) */
|
|
11
|
+
flush(): void;
|
|
12
|
+
/** 是否有挂起调用 */
|
|
13
|
+
pending(): boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 每帧最多执行一次。滚动、缩放等「跟手」操作首选。
|
|
17
|
+
*/
|
|
18
|
+
export declare function rafThrottle<T extends AnyFn>(fn: T): T & Cancelable;
|
|
19
|
+
export interface ThrottleOptions {
|
|
20
|
+
/** 首次调用是否立即执行,默认 true */
|
|
21
|
+
leading?: boolean;
|
|
22
|
+
/** 尾随调用是否补一次,默认 true */
|
|
23
|
+
trailing?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 固定时间窗节流(滚动进度、加载进度、日志上报)。
|
|
27
|
+
*/
|
|
28
|
+
export declare function throttle<T extends AnyFn>(fn: T, wait?: number, options?: ThrottleOptions): T & Cancelable;
|
|
29
|
+
/**
|
|
30
|
+
* 防抖(搜索输入、缩放落定后的重渲染)。
|
|
31
|
+
*/
|
|
32
|
+
export declare function debounce<T extends AnyFn>(fn: T, wait?: number): T & Cancelable;
|
|
33
|
+
/**
|
|
34
|
+
* 批量合并:把一帧内多次 push 的条目合成一次回调。
|
|
35
|
+
* 用于「500 页尺寸陆续到达」这类必须批量更新的场景。
|
|
36
|
+
*/
|
|
37
|
+
export declare function rafBatch<T>(onFlush: (items: T[]) => void, maxBatch?: number): {
|
|
38
|
+
push(item: T): void;
|
|
39
|
+
cancel(): void;
|
|
40
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 缩放动画。
|
|
3
|
+
*
|
|
4
|
+
* pdfh5 有 `animationDuration`(默认 300ms),双击 / 按钮缩放走缓动动画而不是瞬变。
|
|
5
|
+
* 那个手感差异很明显:瞬变会让人「晕」,动画则保留了空间连续性。
|
|
6
|
+
*
|
|
7
|
+
* 实现要点:
|
|
8
|
+
* 1. 用 rAF 推进,缓动用 easeOutCubic(快进慢出,符合手指离开后的惯性直觉);
|
|
9
|
+
* 2. 每帧回调的是「插值后的 zoom + 锚点滚位」,调用方只负责应用,不关心动画细节;
|
|
10
|
+
* 3. 可中途取消(用户再次触摸时立刻停下),避免和手势抢控制权;
|
|
11
|
+
* 4. 尊重 `prefers-reduced-motion`:系统要求减少动效时直接跳到终值。
|
|
12
|
+
*/
|
|
13
|
+
export interface ZoomAnimationOptions {
|
|
14
|
+
from: number;
|
|
15
|
+
to: number;
|
|
16
|
+
duration: number;
|
|
17
|
+
/** 每帧回调:progress 为 0-1 */
|
|
18
|
+
onUpdate: (zoom: number, progress: number) => void;
|
|
19
|
+
onDone?: () => void;
|
|
20
|
+
/** 缓动函数,默认 easeOutCubic */
|
|
21
|
+
easing?: (t: number) => number;
|
|
22
|
+
}
|
|
23
|
+
export interface AnimationHandle {
|
|
24
|
+
cancel(): void;
|
|
25
|
+
readonly finished: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** 是否应当禁用动画(系统偏好 / 不可见页面) */
|
|
28
|
+
export declare function shouldReduceMotion(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 启动一次缩放动画。
|
|
31
|
+
* duration <= 0 或系统要求减少动效时,同步跳到终值并立即结束。
|
|
32
|
+
*/
|
|
33
|
+
export declare function animateZoom(options: ZoomAnimationOptions): AnimationHandle;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ElementSize {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* 观察容器尺寸。
|
|
7
|
+
*
|
|
8
|
+
* 关键点:必须用 callback ref 而不是 useRef + 挂载时 effect。
|
|
9
|
+
* 因为调用方常常「先渲染 loading 占位、加载完才渲染容器」,
|
|
10
|
+
* 用 useRef 的话首帧 ref 还是 null,effect 不会再跑,尺寸就永远停在 0。
|
|
11
|
+
*
|
|
12
|
+
* ResizeObserver 在拖动窗口 / 旋转屏幕时会连发多次,这里每帧合并一次再写 state。
|
|
13
|
+
*/
|
|
14
|
+
export declare function useElementSize<T extends HTMLElement>(): {
|
|
15
|
+
readonly ref: (node: T | null) => void;
|
|
16
|
+
readonly width: number;
|
|
17
|
+
readonly height: number;
|
|
18
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';
|
|
2
|
+
import { PageMetric } from '../types';
|
|
3
|
+
export interface UsePageMetricsResult {
|
|
4
|
+
metrics: ReadonlyArray<PageMetric | undefined>;
|
|
5
|
+
/** 已解析尺寸的页数(用于进度显示) */
|
|
6
|
+
resolved: number;
|
|
7
|
+
/** 取页面代理(带 LRU + 并发合并) */
|
|
8
|
+
getPage(pageNumber: number): Promise<PDFPageProxy>;
|
|
9
|
+
peekPage(pageNumber: number): PDFPageProxy | undefined;
|
|
10
|
+
/** 请求解析某一页的尺寸(幂等,滚动接近时调用) */
|
|
11
|
+
ensurePage(pageNumber: number): void;
|
|
12
|
+
}
|
|
13
|
+
export interface UsePageMetricsOptions {
|
|
14
|
+
/** 首屏并发解析的页数,默认 4 */
|
|
15
|
+
initialPages?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 渐进式页面度量。
|
|
19
|
+
*
|
|
20
|
+
* 大文档不可能一次性 getPage() 全部页面(等于把整份文件解析一遍)。
|
|
21
|
+
* 这里分三层:
|
|
22
|
+
* 1. 首屏并发解析前 N 页,拿到真实尺寸;
|
|
23
|
+
* 2. 其余页先用「已解析页的平均尺寸」占位(layout 里传 fallback),滚动时不至于跳动;
|
|
24
|
+
* 3. 滚动接近某页时 ensurePage() 解析它 —— 尺寸校正走 rafBatch,一帧合并多页,
|
|
25
|
+
* 避免「多页尺寸同时到达 → 每页一次 setState → 布局抖动」。
|
|
26
|
+
*/
|
|
27
|
+
export declare function usePageMetrics(doc: PDFDocumentProxy | null, options?: UsePageMetricsOptions): UsePageMetricsResult;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PDFDocumentProxy } from 'pdfjs-dist';
|
|
2
|
+
import { PdfSource } from '../types';
|
|
3
|
+
export interface PdfDocumentState {
|
|
4
|
+
doc: PDFDocumentProxy | null;
|
|
5
|
+
numPages: number;
|
|
6
|
+
loading: boolean;
|
|
7
|
+
progress: {
|
|
8
|
+
loaded: number;
|
|
9
|
+
total: number;
|
|
10
|
+
} | null;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
/** 需要密码时为 true */
|
|
13
|
+
needPassword: boolean;
|
|
14
|
+
/** pdf.js PasswordResponses:1 = NEED_PASSWORD,2 = INCORRECT_PASSWORD */
|
|
15
|
+
passwordReason: number;
|
|
16
|
+
submitPassword(password: string): void;
|
|
17
|
+
cancelPassword(): void;
|
|
18
|
+
}
|
|
19
|
+
export declare function usePdfDocument(source: PdfSource | null | undefined, enabled?: boolean): PdfDocumentState;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { PinchGeometry } from '../core/gestures';
|
|
2
|
+
export interface PinchGestureOptions {
|
|
3
|
+
/** 滚动容器 */
|
|
4
|
+
scrollRef: React.RefObject<HTMLElement | null>;
|
|
5
|
+
/** 承载内容的元素(transform 作用在它身上) */
|
|
6
|
+
contentRef: React.RefObject<HTMLElement | null>;
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
zoom: number;
|
|
9
|
+
minZoom: number;
|
|
10
|
+
maxZoom: number;
|
|
11
|
+
/** 双击目标倍率 */
|
|
12
|
+
doubleTapZoom: number;
|
|
13
|
+
/** 内容的最大滚动范围计算器 */
|
|
14
|
+
maxScroll: () => {
|
|
15
|
+
left: number;
|
|
16
|
+
top: number;
|
|
17
|
+
};
|
|
18
|
+
onCommit(zoom: number, scrollLeft: number, scrollTop: number): void;
|
|
19
|
+
/** 双击缩放(可选)。不提供时退化为 onCommit */
|
|
20
|
+
onDoubleTap?(zoom: number, scrollLeft: number, scrollTop: number): void;
|
|
21
|
+
onGestureStart?(): void;
|
|
22
|
+
onGestureEnd?(): void;
|
|
23
|
+
}
|
|
24
|
+
export interface PinchGestureState {
|
|
25
|
+
/** 捏合中(此时内容走 transform 预演) */
|
|
26
|
+
active: boolean;
|
|
27
|
+
/** 预演 transform;null 表示不预演 */
|
|
28
|
+
preview: PinchGeometry | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 双指捏合 + 双击缩放。
|
|
32
|
+
*
|
|
33
|
+
* 实现要点(移动端性能关键):
|
|
34
|
+
* 1. 捏合过程中**不**改变真实 zoom,只设置一个 CSS transform 做预演 ——
|
|
35
|
+
* transform 只触发合成,不触发布局 / 重绘,因此可以跟手到 60fps;
|
|
36
|
+
* 2. 松手时才提交 zoom + scroll,并清除 transform;
|
|
37
|
+
* 3. 用 pointerdown/move/up 统一处理(iOS Safari 13+ / Android Chrome 均支持),
|
|
38
|
+
* 配合 touch-action: none 阻止浏览器默认的整页缩放;
|
|
39
|
+
* 4. 双击使用本地时间戳判定,不依赖 300ms click 延迟。
|
|
40
|
+
*/
|
|
41
|
+
export declare function usePinchGesture(options: PinchGestureOptions): PinchGestureState;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface VirtualWindow {
|
|
2
|
+
/** 需要真正挂载 DOM 的页(1 基,含首尾) */
|
|
3
|
+
mounted: number[];
|
|
4
|
+
/** 需要渲染位图的页 */
|
|
5
|
+
visible: number[];
|
|
6
|
+
/** 需要预渲染的页(可见区上下各 buffer 屏) */
|
|
7
|
+
prefetch: number[];
|
|
8
|
+
/** 当前阅读页 */
|
|
9
|
+
current: number;
|
|
10
|
+
}
|
|
11
|
+
export interface UseVirtualPagesOptions {
|
|
12
|
+
/** 页面盒子(来自 computeLayout),左右滚动时用 left/width */
|
|
13
|
+
boxes: ReadonlyArray<{
|
|
14
|
+
pageNumber: number;
|
|
15
|
+
top: number;
|
|
16
|
+
left: number;
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}>;
|
|
20
|
+
mode: 'scroll' | 'page';
|
|
21
|
+
/** 距离可见区多少屏开始预渲染,默认 1.2 */
|
|
22
|
+
prefetchScreens?: number;
|
|
23
|
+
/** 距离可见区多少屏开始挂载 DOM(比预渲染更远,保证快速滚动时不留白) */
|
|
24
|
+
mountScreens?: number;
|
|
25
|
+
/** 容器尺寸 */
|
|
26
|
+
viewportWidth: number;
|
|
27
|
+
viewportHeight: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 虚拟化:只挂载「看得见 + 缓冲」的页面 DOM。
|
|
31
|
+
*
|
|
32
|
+
* 为什么不直接渲染全部:500 页文档每页 2 个 canvas + 数百个 span,
|
|
33
|
+
* DOM 节点数和内存都会直接打爆移动端。
|
|
34
|
+
*
|
|
35
|
+
* 滚动位置由滚动容器自身维护(不用 transform 虚拟滚动),
|
|
36
|
+
* 因为原生滚动的惯性 / 回弹在 iOS 上无法用 JS 复刻。
|
|
37
|
+
*/
|
|
38
|
+
export declare function useVirtualPages(scrollRef: React.RefObject<HTMLElement | null>, options: UseVirtualPagesOptions): VirtualWindow;
|
|
39
|
+
export interface ScrollProgress {
|
|
40
|
+
current: number;
|
|
41
|
+
total: number;
|
|
42
|
+
ratio: number;
|
|
43
|
+
}
|
|
44
|
+
/** 缩略图用的懒加载观察器:进入视口才渲染 */
|
|
45
|
+
export declare function useInView<T extends Element>(rootMargin?: string): {
|
|
46
|
+
ref: React.RefObject<T | null>;
|
|
47
|
+
inView: boolean;
|
|
48
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { PdfH5Reader, PdfH5ReaderProps as ReaderProps } from './components/PdfH5Reader';
|
|
2
|
+
import { PdfH5ReaderHandle as ReaderHandle } from './types';
|
|
3
|
+
export { PdfH5Reader };
|
|
4
|
+
export type PdfH5ReaderProps = ReaderProps;
|
|
5
|
+
export type PdfH5ReaderHandle = ReaderHandle;
|
|
6
|
+
export { configurePdfjs, getPdfjsRuntimeOptions, loadPdf, loadPdfDocument, pdfjsLib } from './core/pdfjs';
|
|
7
|
+
export type { PdfjsRuntimeOptions } from './core/pdfjs';
|
|
8
|
+
export { LruCache } from './core/lru';
|
|
9
|
+
export type { LruCacheOptions, LruCacheStats } from './core/lru';
|
|
10
|
+
export { EventEmitter } from './core/eventEmitter';
|
|
11
|
+
export type { Listener } from './core/eventEmitter';
|
|
12
|
+
export type { ReaderEvents, ReaderEventName, ReaderEventPayload, ReaderStatus, RenderTiming, ScrollEventPayload, ZoomEventPayload, } from './core/readerEvents';
|
|
13
|
+
export { animateZoom, shouldReduceMotion } from './core/zoomAnimation';
|
|
14
|
+
export type { AnimationHandle, ZoomAnimationOptions } from './core/zoomAnimation';
|
|
15
|
+
export { DEFAULT_ANNOTATION_STYLE, createAnnotationId, groupByPage, isAnnotationValid, isPointInPage, rectFromPoints, rectToPixel, toNormalized, toPixel, } from './core/annotations';
|
|
16
|
+
export type { Annotation, AnnotationKind, AnnotationMode, AnnotationStyle, FreetextAnnotation, HighlightAnnotation, InkAnnotation, NormPoint, NormRect, } from './core/annotations';
|
|
17
|
+
export { AnnotationLayer } from './components/AnnotationLayer';
|
|
18
|
+
export type { AnnotationLayerProps } from './components/AnnotationLayer';
|
|
19
|
+
export { rafThrottle, throttle, debounce, rafBatch } from './core/throttle';
|
|
20
|
+
export type { Cancelable } from './core/throttle';
|
|
21
|
+
export { BitmapCache, TextLayerCache, PageProxyCache, ThumbnailCache } from './core/cache';
|
|
22
|
+
export { RenderQueue } from './core/renderQueue';
|
|
23
|
+
export { computeLayout, pageAtOffset, offsetForPage, quantizeScale, quantizePixelRatio, viewportScaleFor, clampCanvasSize, bitmapBytes } from './core/layout';
|
|
24
|
+
export type { PageBox, ViewerLayout } from './core/layout';
|
|
25
|
+
export { pinchTransform, pinchCommit, doubleTapTarget, zoomAtPoint } from './core/gestures';
|
|
26
|
+
export { usePdfDocument } from './hooks/usePdfDocument';
|
|
27
|
+
export type { PdfDocumentState } from './hooks/usePdfDocument';
|
|
28
|
+
export { usePageMetrics } from './hooks/usePageMetrics';
|
|
29
|
+
export { usePinchGesture } from './hooks/usePinchGesture';
|
|
30
|
+
export { useVirtualPages } from './hooks/useVirtualPages';
|
|
31
|
+
export { useElementSize } from './hooks/useElementSize';
|
|
32
|
+
export { searchDocument, extractPageText, clearSearchCache } from './lib/search';
|
|
33
|
+
export { flattenOutline } from './lib/outline';
|
|
34
|
+
export type { OutlineEntry } from './lib/outline';
|
|
35
|
+
export { makeSnippet, splitSnippet, findInPage } from './lib/text';
|
|
36
|
+
export { highlightTextNodes } from './lib/highlight';
|
|
37
|
+
export { createThumbnailCanvas } from './lib/thumbnail';
|
|
38
|
+
export type { CacheStatsSnapshot, FitMode, LoadProgress, PageMetric, PdfSource, SearchHit, ThemeMode, ViewerMode, } from './types';
|
|
39
|
+
export declare function usePdfH5ReaderActions(ref: React.RefObject<PdfH5ReaderHandle | null>): {
|
|
40
|
+
next: () => void | undefined;
|
|
41
|
+
prev: () => void | undefined;
|
|
42
|
+
goTo: (page: number) => void | undefined;
|
|
43
|
+
zoomIn: () => void | undefined;
|
|
44
|
+
zoomOut: () => void | undefined;
|
|
45
|
+
resetZoom: () => void | undefined;
|
|
46
|
+
};
|