@hamster-note/reader 0.2.0-beta.1
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 +267 -0
- package/dist/components/IntermediateDocumentViewer/IntermediateDocumentPageContent.d.ts +40 -0
- package/dist/components/IntermediateDocumentViewer/IntermediateDocumentPageContent.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/IntermediateDocumentViewer.d.ts +356 -0
- package/dist/components/IntermediateDocumentViewer/IntermediateDocumentViewer.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/index.d.ts +7 -0
- package/dist/components/IntermediateDocumentViewer/index.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/pageContentGeometry.d.ts +84 -0
- package/dist/components/IntermediateDocumentViewer/pageContentGeometry.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/rangeJumpHelpers.d.ts +131 -0
- package/dist/components/IntermediateDocumentViewer/rangeJumpHelpers.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/renderTiming.d.ts +44 -0
- package/dist/components/IntermediateDocumentViewer/renderTiming.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/selectionAdapter.d.ts +25 -0
- package/dist/components/IntermediateDocumentViewer/selectionAdapter.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/textSpanStyle.d.ts +4 -0
- package/dist/components/IntermediateDocumentViewer/textSpanStyle.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer/useLazyPageQueue.d.ts +73 -0
- package/dist/components/IntermediateDocumentViewer/useLazyPageQueue.d.ts.map +1 -0
- package/dist/components/IntermediateDocumentViewer.d.ts +2 -0
- package/dist/components/IntermediateDocumentViewer.d.ts.map +1 -0
- package/dist/components/PopoverPortal.d.ts +21 -0
- package/dist/components/PopoverPortal.d.ts.map +1 -0
- package/dist/components/Reader.d.ts +122 -0
- package/dist/components/Reader.d.ts.map +1 -0
- package/dist/components/gestureRouting.d.ts +73 -0
- package/dist/components/gestureRouting.d.ts.map +1 -0
- package/dist/components/selection/caretResolver.d.ts +33 -0
- package/dist/components/selection/caretResolver.d.ts.map +1 -0
- package/dist/components/selection/index.d.ts +2 -0
- package/dist/components/selection/index.d.ts.map +1 -0
- package/dist/components/selection/savedSelection.d.ts +71 -0
- package/dist/components/selection/savedSelection.d.ts.map +1 -0
- package/dist/components/selection/selectionComposer.d.ts +3 -0
- package/dist/components/selection/selectionComposer.d.ts.map +1 -0
- package/dist/components/selection/selectionPayloadSerializer.d.ts +21 -0
- package/dist/components/selection/selectionPayloadSerializer.d.ts.map +1 -0
- package/dist/components/selection/wordRange.d.ts +17 -0
- package/dist/components/selection/wordRange.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2933 -0
- package/dist/style.css +323 -0
- package/dist/types/selection.d.ts +42 -0
- package/dist/types/selection.d.ts.map +1 -0
- package/dist/vendor/clipper-lib.d.ts +3 -0
- package/dist/vendor/clipper-lib.d.ts.map +1 -0
- package/package.json +99 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 仓鼠笔记
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# @hamster-note/reader
|
|
2
|
+
|
|
3
|
+
React reader component package for Hamster Note.
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
Install the package and its peer dependencies:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
yarn add @hamster-note/reader react react-dom
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 使用
|
|
14
|
+
|
|
15
|
+
Styles are not injected automatically. Import `@hamster-note/reader/style.css` explicitly before rendering `Reader`.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Reader } from '@hamster-note/reader'
|
|
19
|
+
import type { ReaderProps } from '@hamster-note/reader'
|
|
20
|
+
import '@hamster-note/reader/style.css'
|
|
21
|
+
|
|
22
|
+
const document: NonNullable<ReaderProps['document']> = {
|
|
23
|
+
id: 'demo-document',
|
|
24
|
+
title: 'Hello Hamster',
|
|
25
|
+
pages: []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function App() {
|
|
29
|
+
return <Reader document={document} emptyText='No document' />
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### How It Works
|
|
34
|
+
|
|
35
|
+
`Reader` is parser-agnostic. It accepts an intermediate document (produced by parser packages such as `@hamster-note/pdf-parser`, `@hamster-note/docx-parser`, etc.) and renders it through the intermediate-document renderer. Pages are rendered in `contain` fit mode by default (hardcoded inside `IntermediateDocumentViewer`).
|
|
36
|
+
|
|
37
|
+
The renderer lazily loads page content on demand via a visibility-debounced queue with concurrency control and offscreen-release, designed for long documents without blocking the main thread.
|
|
38
|
+
|
|
39
|
+
#### Lazy Page Loading Props
|
|
40
|
+
|
|
41
|
+
The following optional props control the lazy loading queue:
|
|
42
|
+
|
|
43
|
+
| Prop | Type | Default | Description |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| `initialLoadedPages` | `number` | `1` | Number of pages to load immediately on mount (before visibility-based queue kicks in). |
|
|
46
|
+
| `pageLoadConcurrency` | `number` | `3` | Maximum number of pages loaded concurrently. |
|
|
47
|
+
| `pageLoadEnterDelayMs` | `number` | `500` | A non-initial page must remain continuously visible for this duration (ms) before its content load is enqueued. Prevents fast-scroll from triggering loads. |
|
|
48
|
+
| `pageUnloadDelayMs` | `number` | `5000` | After a loaded page leaves the visible window, wait this duration (ms) before unloading its content back to an empty shell. Re-entering before the delay cancels the unload. |
|
|
49
|
+
|
|
50
|
+
#### Render Timing
|
|
51
|
+
|
|
52
|
+
To diagnose bottlenecks in the render pipeline, you can opt in to stage-by-stage timing logs. Production builds emit **no timing output by default**.
|
|
53
|
+
|
|
54
|
+
**Activation paths:**
|
|
55
|
+
|
|
56
|
+
1. **Callback prop** — receive every timing entry in code:
|
|
57
|
+
```tsx
|
|
58
|
+
<Reader
|
|
59
|
+
document={document}
|
|
60
|
+
onIntermediateDocumentRenderTiming={(entry) => {
|
|
61
|
+
console.table(entry)
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
2. **Environment flag** — print `console.debug` logs when no callback is provided:
|
|
67
|
+
```bash
|
|
68
|
+
VITE_HAMSTER_READER_INTERMEDIATE_TIMING=true
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Each entry has the following shape:
|
|
72
|
+
|
|
73
|
+
| Field | Type | Description |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `stage` | `string` | One of `document-resolution`, `shell-rendering`, `initial-page-loading`, `content-extraction`, `page-content-rendering`, `visibility-lazy-loading`, `offscreen-unload`, `ocr-processing`. |
|
|
76
|
+
| `startedAt` | `number` | Start timestamp (ms). |
|
|
77
|
+
| `endedAt` | `number` | End timestamp (ms). |
|
|
78
|
+
| `durationMs` | `number` | `endedAt - startedAt`. |
|
|
79
|
+
| `pageNumber` | `number` *(optional)* | Present for page-scoped stages. |
|
|
80
|
+
| `detail` | `object` *(optional)* | Stage-specific context such as `pageCount`, `textCount`, `imageCount`, or `status`. |
|
|
81
|
+
|
|
82
|
+
#### Demo Upload Formats
|
|
83
|
+
|
|
84
|
+
The browser Demo supports uploading and previewing the following formats:
|
|
85
|
+
|
|
86
|
+
- **PDF** (`.pdf`)
|
|
87
|
+
- **TXT** (`.txt`)
|
|
88
|
+
- **DOCX** (`.docx`)
|
|
89
|
+
- **Markdown** (`.md`, `.markdown`)
|
|
90
|
+
|
|
91
|
+
EPUB (`.epub`) is **not supported** in this browser Demo because `@hamster-note/epub-parser` is Node.js-only and requires a separate server-side design.
|
|
92
|
+
|
|
93
|
+
## API Notes
|
|
94
|
+
|
|
95
|
+
Enable OCR for visible pages with the `ocr` prop, and listen for text selection updates with `onTextSelectionChange` and `onTextSelectionEnd`.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
<Reader
|
|
99
|
+
document={document}
|
|
100
|
+
ocr
|
|
101
|
+
onTextSelectionChange={(text, detail) => {
|
|
102
|
+
// handle selection change
|
|
103
|
+
}}
|
|
104
|
+
onTextSelectionEnd={(text, detail) => {
|
|
105
|
+
// handle selection end
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Text Selection (@hamster-note/selection)
|
|
111
|
+
|
|
112
|
+
`Reader` integrates [`@hamster-note/selection`](https://www.npmjs.com/package/@hamster-note/selection) to provide rich text-selection features, highlighted ranges, popovers, and programmatic control on top of the native browser `Selection` API.
|
|
113
|
+
|
|
114
|
+
The `<Selection>` component wraps page content inside `<VirtualPaper>` and is active by default. The legacy native callbacks (`onTextSelectionChange`, `onTextSelectionEnd`, `onSelectText`) continue to fire alongside the linked-range Selection component.
|
|
115
|
+
|
|
116
|
+
### Linked range shape
|
|
117
|
+
|
|
118
|
+
`Reader` uses a linked range shape. Each endpoint carries a public page `selectionId`, and overlay rectangles are grouped by that page id in `rectsBySelectionId`.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
{
|
|
122
|
+
id: 'highlight-1',
|
|
123
|
+
text: 'Selected text',
|
|
124
|
+
start: { selectionId: 'page-1', offset: 12 },
|
|
125
|
+
end: { selectionId: 'page-2', offset: 34 },
|
|
126
|
+
createdAt: Date.now(),
|
|
127
|
+
overlayRectType: 'percent',
|
|
128
|
+
rectsBySelectionId: {
|
|
129
|
+
'page-1': [{ x: 0.1, y: 0.2, width: 0.5, height: 0.05 }],
|
|
130
|
+
'page-2': [{ x: 0.05, y: 0.1, width: 0.4, height: 0.05 }]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Public page ids are always `page-${pageNumber}` (for example, `page-1`, `page-2`). Internally, each `Reader` instance scopes runtime Selection ids so two Readers on the same page cannot collide, but public callbacks and stored data stay unscoped. You should only read and write the public `page-${pageNumber}` ids.
|
|
136
|
+
|
|
137
|
+
### Quick Start (linked selection)
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { Reader } from '@hamster-note/reader'
|
|
141
|
+
import type { ReaderSelectionRange } from '@hamster-note/reader'
|
|
142
|
+
import '@hamster-note/reader/style.css' // includes Selection CSS
|
|
143
|
+
import { useState } from 'react'
|
|
144
|
+
|
|
145
|
+
const initialRanges: ReaderSelectionRange[] = [
|
|
146
|
+
{
|
|
147
|
+
id: 'highlight-1',
|
|
148
|
+
text: 'Selected text on page 1',
|
|
149
|
+
start: { selectionId: 'page-1', offset: 12 },
|
|
150
|
+
end: { selectionId: 'page-1', offset: 34 },
|
|
151
|
+
createdAt: Date.now(),
|
|
152
|
+
overlayRectType: 'percent',
|
|
153
|
+
rectsBySelectionId: {
|
|
154
|
+
'page-1': [{ x: 0.1, y: 0.2, width: 0.5, height: 0.05 }]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
export function App() {
|
|
160
|
+
// 受控模式:Reader 不内部修改 ranges,由 onSelect 回调外部追加
|
|
161
|
+
const [ranges, setRanges] = useState<ReaderSelectionRange[]>(initialRanges)
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Reader
|
|
165
|
+
document={document}
|
|
166
|
+
ranges={ranges}
|
|
167
|
+
overlayRectType='percent'
|
|
168
|
+
onSelect={(range) => setRanges((prev) => [...prev, range])}
|
|
169
|
+
onUpdateRange={(range) =>
|
|
170
|
+
setRanges((prev) => prev.map((r) => (r.id === range.id ? range : r)))
|
|
171
|
+
}
|
|
172
|
+
/>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Props
|
|
178
|
+
|
|
179
|
+
| Prop | Type | Description |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| `ranges` | `ReaderSelectionRange[]` | Controlled highlight ranges in the linked shape. Reader does not mutate this array. |
|
|
182
|
+
| `defaultRanges` | `ReaderSelectionRange[]` | Initial ranges for uncontrolled mode (when `ranges` is omitted). |
|
|
183
|
+
| `selectedRangeId` | `string \| null` | Controlled currently-selected range ID. |
|
|
184
|
+
| `defaultSelectedRangeId` | `string \| null` | Initial selected range ID for uncontrolled mode. |
|
|
185
|
+
| `onSelect` | `(range: ReaderSelectionRange) => void` | Fired when the user finishes a new selection. In uncontrolled mode, Reader appends the range internally before calling this. |
|
|
186
|
+
| `onSelectRange` | `(id: string \| null) => void` | Fired when the user clicks an existing highlight. |
|
|
187
|
+
| `onUpdateRange` | `(range: ReaderSelectionRange) => void` | Fired when the user drags a selected highlight range handle. In uncontrolled mode, Reader replaces the matching range internally before calling this; controlled callers must update their `ranges` array. |
|
|
188
|
+
| `onHighlight` | `(range: ReaderSelectionRange) => void` | Fired when a range is highlighted via the ref API or via Reader's internal auto-highlight (when `autoHighlight` is enabled). |
|
|
189
|
+
| `onSelectionStart` | `(mousePos: ReaderMousePosition, selection: Selection) => void` | Fired when a selection gesture begins. |
|
|
190
|
+
| `onSelectionEnd` | `(mousePos: ReaderMousePosition, selection: Selection) => void` | Fired when a selection gesture ends (mouseup-based; touch selection may not trigger this). |
|
|
191
|
+
| `autoHighlight` | `boolean` | When true, completing a text selection automatically creates a highlight. Reader fires `onHighlight` but does not append to ranges array. Defaults to `false`. |
|
|
192
|
+
| `highlightColor` | `string` | CSS color for highlight overlays. In Phase 1, this applies globally to all highlights. |
|
|
193
|
+
| `selectionColor` | `string` | CSS color for active selection overlay. |
|
|
194
|
+
| `selectionPopover` | `React.ReactNode` | Custom popover content shown during active selection (before it becomes a highlight). |
|
|
195
|
+
| `highlightPopover` | `React.ReactNode` | Custom popover content shown when an existing highlight is clicked. |
|
|
196
|
+
| `selectionRef` | `React.Ref<ReaderSelectionRef>` | Reader-owned command ref, distinct from the upstream Selection component ref. Exposes `highlight()`, `clear()`, and additive `scrollToRange(id)` for jumping to an existing range. |
|
|
197
|
+
| `overlayRectType` | `ReaderSelectionOverlayRectType` | Controls whether selection overlay rectangles are stored/rendered as pixel (`'px'`) or percentage (`'percent'`) coordinates relative to the selection container. Defaults to `'percent'`. |
|
|
198
|
+
|
|
199
|
+
### Exported Types
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import type {
|
|
203
|
+
ReaderSelectionRange, // linked: { id, text, start, end, rectsBySelectionId, overlayRectType? }
|
|
204
|
+
ReaderSelectionOverlayRectType, // 'px' | 'percent'
|
|
205
|
+
ReaderSelectionRef, // { highlight(): void; clear(): void; scrollToRange(id: string): void }
|
|
206
|
+
ReaderMousePosition // { x, y }, viewport coordinates (clientX/clientY)
|
|
207
|
+
} from '@hamster-note/reader'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### CSS
|
|
211
|
+
|
|
212
|
+
`@hamster-note/reader/style.css` already bundles the Selection library CSS (`.hsn-selection-*` classes). No additional import is needed.
|
|
213
|
+
|
|
214
|
+
### Legacy Selection Callbacks
|
|
215
|
+
|
|
216
|
+
The existing `onTextSelectionChange`, `onTextSelectionEnd`, and `onSelectText` callbacks are preserved for backward compatibility. They continue to fire through the native `mouseup`/`touchend`/`selectionchange` listeners on the viewer root element, independent of the `<Selection>` component. They are not affected by the linked range shape.
|
|
217
|
+
|
|
218
|
+
> **Note**: `onSelectionEnd` is **mouseup-based**. On touch devices, the selection-end signal relies on the legacy `touchend` listener (which fires `onTextSelectionEnd` / `onSelectText`), not `onSelectionEnd`.
|
|
219
|
+
|
|
220
|
+
### Demo localStorage Migration
|
|
221
|
+
|
|
222
|
+
The browser Demo persists highlights to localStorage keyed by filename. The stored shape is now `{ version: 2, ranges: ReaderSelectionRange[] }`. Older unversioned bare arrays, or legacy objects with flat numeric `start`/`end` and `rects`, are ignored and return `[]`. Their page ownership cannot be proven, so the demo does not attempt to migrate them. If you have old data, recreate the highlights instead.
|
|
223
|
+
|
|
224
|
+
### Programmatic Control
|
|
225
|
+
|
|
226
|
+
`selectionRef` exposes Reader-level commands. `highlight()` and `clear()` are forwarded to the active page Selection instances; `scrollToRange(id)` is implemented by Reader to translate the VirtualPaper viewport to an existing range while preserving the current scale.
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
import { useRef } from 'react'
|
|
230
|
+
import type { ReaderSelectionRef } from '@hamster-note/reader'
|
|
231
|
+
|
|
232
|
+
const selectionRef = useRef<ReaderSelectionRef>(null)
|
|
233
|
+
|
|
234
|
+
// Highlight the current native selection as a range
|
|
235
|
+
selectionRef.current?.highlight()
|
|
236
|
+
|
|
237
|
+
// Clear all highlights
|
|
238
|
+
selectionRef.current?.clear()
|
|
239
|
+
|
|
240
|
+
// Scroll the viewer to a specific range by id
|
|
241
|
+
selectionRef.current?.scrollToRange('highlight-1')
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Peer Dependencies
|
|
245
|
+
|
|
246
|
+
- `react@^19.0.0`
|
|
247
|
+
- `react-dom@^19.0.0`
|
|
248
|
+
|
|
249
|
+
## 开发脚本
|
|
250
|
+
|
|
251
|
+
- `yarn dev`: start the local Vite dev server.
|
|
252
|
+
- `yarn build:lib`: build the library output in `dist/`.
|
|
253
|
+
- `yarn build:demo`: build the local demo output in `demo-dist/`.
|
|
254
|
+
- `yarn build:all`: build the library and demo.
|
|
255
|
+
- `yarn build`: run `yarn build:all`.
|
|
256
|
+
- `yarn typecheck`: run TypeScript type checking.
|
|
257
|
+
- `yarn lint`: run ESLint.
|
|
258
|
+
- `yarn test`: start Vitest in watch mode.
|
|
259
|
+
- `yarn test:run`: run Vitest once.
|
|
260
|
+
- `yarn preview`: preview the demo build.
|
|
261
|
+
- `yarn prepublishOnly`: build the library before publish.
|
|
262
|
+
|
|
263
|
+
## 发版规则
|
|
264
|
+
|
|
265
|
+
- Push `version/x.y.z` branches for stable releases.
|
|
266
|
+
- Push `version/x.y.z-*` branches for pre-releases.
|
|
267
|
+
- Publish tag selection follows the package version suffix: no suffix -> `latest`, `-dev` -> `dev`, `-beta` -> `beta`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { IntermediateImage, IntermediateText } from '@hamster-note/types';
|
|
2
|
+
/**
|
|
3
|
+
* `intermediate-document` 默认模式已加载页面的内容渲染器。
|
|
4
|
+
*
|
|
5
|
+
* 该组件渲染在外壳 `.hamster-reader__intermediate-page` 内部,负责把已加载
|
|
6
|
+
* 的页面内容 bundle(基础底图、文本 span、OCR 文本 span、IntermediateImage
|
|
7
|
+
* 内容项)绘制到 DOM。它复用统一的几何辅助函数,
|
|
8
|
+
* 以保证选择、OCR 与测试行为一致。
|
|
9
|
+
*
|
|
10
|
+
* 关键约束:
|
|
11
|
+
* - 绝不使用 `dangerouslySetInnerHTML`;所有内容均由 React 元素渲染。
|
|
12
|
+
* - 保留 thumbnail / base-image duck typing。
|
|
13
|
+
* - 文本 span 沿用 `.hamster-reader__intermediate-text` + `data-text-id` +
|
|
14
|
+
* `data-page-number`,以便选择载荷序列化器 / OCR / 测试正常工作。
|
|
15
|
+
* - IntermediateImage 内容项以绝对定位 `<img>` 绘制,几何由 polygon 决定。
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* 文本 ref 注册回调类型 —— 与 viewer 内 `SetTextRef` 结构兼容,
|
|
19
|
+
* 使文本 span 能被选择载荷追踪。
|
|
20
|
+
*/
|
|
21
|
+
export type IntermediateDocumentSetTextRef = (text: IntermediateText, pageNumber: number) => (element: HTMLSpanElement | null) => void;
|
|
22
|
+
export type IntermediateDocumentPageContentProps = {
|
|
23
|
+
/** 当前页码(用于 data-page-number 与文本 ref 注册) */
|
|
24
|
+
pageNumber: number;
|
|
25
|
+
/** getContent() 返回的文本内容(已过滤掉图片项) */
|
|
26
|
+
texts: IntermediateText[];
|
|
27
|
+
/** OCR 识别产生的文本 span(id 已带 ocr- 前缀) */
|
|
28
|
+
ocrTexts: IntermediateText[];
|
|
29
|
+
/** 基础底图 URL(来自 thumbnail / image / getThumbnail() 的 duck typing 解析) */
|
|
30
|
+
baseImageSource: string | undefined;
|
|
31
|
+
/** getContent() 返回的 IntermediateImage 内容项 */
|
|
32
|
+
images: IntermediateImage[];
|
|
33
|
+
/** 文本 span ref 注册回调 */
|
|
34
|
+
setTextRef: IntermediateDocumentSetTextRef;
|
|
35
|
+
onRenderTiming?: (pageNumber: number, startTime: number, commitTime: number, actualDuration: number) => void;
|
|
36
|
+
};
|
|
37
|
+
declare function IntermediateDocumentPageContentComponent({ pageNumber, texts, ocrTexts, baseImageSource, images, setTextRef, onRenderTiming }: IntermediateDocumentPageContentProps): import("react/jsx-runtime").JSX.Element;
|
|
38
|
+
export declare const IntermediateDocumentPageContent: import("react").MemoExoticComponent<typeof IntermediateDocumentPageContentComponent>;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=IntermediateDocumentPageContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntermediateDocumentPageContent.d.ts","sourceRoot":"","sources":["../../../src/components/IntermediateDocumentViewer/IntermediateDocumentPageContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAW9E;;;;;;;;;;;;;;GAcG;AAEH;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,CAC3C,IAAI,EAAE,gBAAgB,EACtB,UAAU,EAAE,MAAM,KACf,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,CAAA;AAE9C,MAAM,MAAM,oCAAoC,GAAG;IACjD,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,uEAAuE;IACvE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,6CAA6C;IAC7C,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,uBAAuB;IACvB,UAAU,EAAE,8BAA8B,CAAA;IAC1C,cAAc,CAAC,EAAE,CACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,KACnB,IAAI,CAAA;CACV,CAAA;AA0DD,iBAAS,wCAAwC,CAAC,EAChD,UAAU,EACV,KAAK,EACL,QAAQ,EACR,eAAe,EACf,MAAM,EACN,UAAU,EACV,cAAc,EACf,EAAE,oCAAoC,2CAmDtC;AAED,eAAO,MAAM,+BAA+B,sFAE3C,CAAA"}
|