@octanejs/pdf 0.0.27 → 0.0.29
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/package.json +3 -3
- package/src/components.tsrx +339 -295
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/pdf",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.29",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"pdfjs-dist": "5.4.296"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"octane": "^0.
|
|
49
|
+
"octane": "^0.11.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/react": "19.2.7",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"dequal": "^2.0.3",
|
|
58
58
|
"make-cancellable-promise": "^2.0.0",
|
|
59
59
|
"merge-refs": "^2.0.0",
|
|
60
|
-
"octane": "0.
|
|
60
|
+
"octane": "0.11.0",
|
|
61
61
|
"playwright": "^1.61.1",
|
|
62
62
|
"react": "19.2.3",
|
|
63
63
|
"react-dom": "19.2.3",
|
package/src/components.tsrx
CHANGED
|
@@ -41,10 +41,12 @@ const BLOCKED_CUSTOM_TEXT_TAGS = new Set([
|
|
|
41
41
|
const URL_ATTRIBUTES = new Set(['action', 'formaction', 'href', 'poster', 'src', 'xlink:href']);
|
|
42
42
|
|
|
43
43
|
function isDangerousUrl(value: string): boolean {
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
return (
|
|
45
|
+
value
|
|
46
|
+
.replace(/[\u0000-\u0020\u007f]/g, '')
|
|
47
|
+
.toLowerCase()
|
|
48
|
+
.match(/^(?:javascript|vbscript):/) !== null
|
|
49
|
+
);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
function sanitizeCustomTextNode(node: ChildNode): Node {
|
|
@@ -174,18 +176,19 @@ export function Document(props: DocumentProps = {}) {
|
|
|
174
176
|
let active = true;
|
|
175
177
|
setSource(undefined);
|
|
176
178
|
setSourceError(null);
|
|
177
|
-
void resolveSource(file)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
179
|
+
void resolveSource(file)
|
|
180
|
+
.then((nextSource) => {
|
|
181
|
+
if (!active) return;
|
|
182
|
+
setSource(nextSource);
|
|
183
|
+
onSourceSuccess?.();
|
|
184
|
+
})
|
|
185
|
+
.catch((caught: unknown) => {
|
|
186
|
+
if (!active) return;
|
|
187
|
+
const nextError = caught instanceof Error ? caught : new Error(String(caught));
|
|
188
|
+
setSource(false);
|
|
189
|
+
setSourceError(nextError);
|
|
190
|
+
onSourceError?.(nextError);
|
|
191
|
+
});
|
|
189
192
|
return () => {
|
|
190
193
|
active = false;
|
|
191
194
|
};
|
|
@@ -198,26 +201,28 @@ export function Document(props: DocumentProps = {}) {
|
|
|
198
201
|
setPdfError(null);
|
|
199
202
|
if (!source) return;
|
|
200
203
|
|
|
201
|
-
void import('pdfjs-dist')
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
204
|
+
void import('pdfjs-dist')
|
|
205
|
+
.then((pdfjs) => {
|
|
206
|
+
if (!active) return;
|
|
207
|
+
loadingTask = pdfjs.getDocument({ ...source, ...options } as never);
|
|
208
|
+
if (onLoadProgress) loadingTask.onProgress = onLoadProgress;
|
|
209
|
+
loadingTask.onPassword = onPassword;
|
|
210
|
+
return loadingTask.promise;
|
|
211
|
+
})
|
|
212
|
+
.then((nextPdf) => {
|
|
213
|
+
if (!active || !nextPdf) return;
|
|
214
|
+
setPdf(nextPdf);
|
|
215
|
+
pagesRef.current = new Array(nextPdf.numPages);
|
|
216
|
+
linkService.setDocument(nextPdf);
|
|
217
|
+
onLoadSuccess?.(nextPdf);
|
|
218
|
+
})
|
|
219
|
+
.catch((caught: unknown) => {
|
|
220
|
+
if (!active) return;
|
|
221
|
+
const nextError = caught instanceof Error ? caught : new Error(String(caught));
|
|
222
|
+
setPdf(false);
|
|
223
|
+
setPdfError(nextError);
|
|
224
|
+
onLoadError?.(nextError);
|
|
225
|
+
});
|
|
221
226
|
|
|
222
227
|
return () => {
|
|
223
228
|
active = false;
|
|
@@ -260,30 +265,33 @@ export function Document(props: DocumentProps = {}) {
|
|
|
260
265
|
|
|
261
266
|
let content: unknown;
|
|
262
267
|
if (!file) {
|
|
263
|
-
content =
|
|
264
|
-
noData
|
|
265
|
-
)
|
|
268
|
+
content = (
|
|
269
|
+
<div class="react-pdf__message react-pdf__message--no-data">{renderMessage(noData)}</div>
|
|
270
|
+
);
|
|
266
271
|
} else if (sourceError || pdfError || source === false || pdf === false) {
|
|
267
|
-
content =
|
|
268
|
-
error
|
|
269
|
-
)
|
|
272
|
+
content = (
|
|
273
|
+
<div class="react-pdf__message react-pdf__message--error">{renderMessage(error)}</div>
|
|
274
|
+
);
|
|
270
275
|
} else if (!pdf) {
|
|
271
|
-
content =
|
|
272
|
-
loading
|
|
273
|
-
)
|
|
276
|
+
content = (
|
|
277
|
+
<div class="react-pdf__message react-pdf__message--loading">{renderMessage(loading)}</div>
|
|
278
|
+
);
|
|
274
279
|
} else {
|
|
275
|
-
content =
|
|
276
|
-
|
|
277
|
-
|
|
280
|
+
content =
|
|
281
|
+
typeof children === 'function' && !isChildrenBlock(children)
|
|
282
|
+
? children(contextValue as DocumentRenderProps)
|
|
283
|
+
: children;
|
|
278
284
|
}
|
|
279
285
|
|
|
280
|
-
return
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
286
|
+
return (
|
|
287
|
+
<div
|
|
288
|
+
{...withEventData(hostProps, pdf)}
|
|
289
|
+
ref={documentElement}
|
|
290
|
+
class={['react-pdf__Document', classProp, className]}
|
|
291
|
+
>
|
|
292
|
+
<DocumentContext value={contextValue}>{content}</DocumentContext>
|
|
293
|
+
</div>
|
|
294
|
+
);
|
|
287
295
|
}
|
|
288
296
|
|
|
289
297
|
function makePageCallback(page: PDFPageProxy, viewport: PageViewport): PageCallback {
|
|
@@ -341,16 +349,19 @@ function StructTreeItem({ node, className }: { node: unknown; className?: string
|
|
|
341
349
|
}
|
|
342
350
|
}
|
|
343
351
|
const onlyContentChild =
|
|
344
|
-
value.children?.length === 1 &&
|
|
345
|
-
|
|
346
|
-
|
|
352
|
+
value.children?.length === 1 &&
|
|
353
|
+
value.children[0] != null &&
|
|
354
|
+
typeof value.children[0] === 'object' &&
|
|
355
|
+
'id' in value.children[0];
|
|
347
356
|
if (onlyContentChild) {
|
|
348
357
|
const child = value.children?.[0] as { id?: string };
|
|
349
358
|
if (child.id !== undefined) attributes['aria-owns'] = child.id;
|
|
350
359
|
}
|
|
351
|
-
return
|
|
352
|
-
|
|
353
|
-
|
|
360
|
+
return (
|
|
361
|
+
<span class={className} {...attributes}>
|
|
362
|
+
{onlyContentChild ? null : value.children?.map((child) => <StructTreeItem node={child} />)}
|
|
363
|
+
</span>
|
|
364
|
+
);
|
|
354
365
|
}
|
|
355
366
|
|
|
356
367
|
export function Page(props: PageProps = {}) {
|
|
@@ -412,8 +423,7 @@ export function Page(props: PageProps = {}) {
|
|
|
412
423
|
const [page, setPage] = useState<PDFPageProxy | false | undefined>(undefined);
|
|
413
424
|
const [pageError, setPageError] = useState<Error | null>(null);
|
|
414
425
|
const [structTree, setStructTree] = useState<StructTreeNode | null | undefined>(undefined);
|
|
415
|
-
const pageIndex =
|
|
416
|
-
pageNumberProp != null ? pageNumberProp - 1 : pageIndexProp;
|
|
426
|
+
const pageIndex = pageNumberProp != null ? pageNumberProp - 1 : pageIndexProp;
|
|
417
427
|
const pageNumber = pageNumberProp ?? (pageIndexProp != null ? pageIndexProp + 1 : undefined);
|
|
418
428
|
|
|
419
429
|
if (pdf === undefined && documentContext === null) {
|
|
@@ -424,12 +434,7 @@ export function Page(props: PageProps = {}) {
|
|
|
424
434
|
if (!page || !pageNumber) return null;
|
|
425
435
|
const rotation = rotateProp ?? page.rotate;
|
|
426
436
|
const base = page.getViewport({ scale: 1, rotation });
|
|
427
|
-
const sizeScale =
|
|
428
|
-
width
|
|
429
|
-
? width / base.width
|
|
430
|
-
: height
|
|
431
|
-
? height / base.height
|
|
432
|
-
: 1;
|
|
437
|
+
const sizeScale = width ? width / base.width : height ? height / base.height : 1;
|
|
433
438
|
return page.getViewport({ scale: scaleProp * sizeScale, rotation });
|
|
434
439
|
}, [height, page, pageNumber, rotateProp, scaleProp, width]);
|
|
435
440
|
|
|
@@ -438,17 +443,19 @@ export function Page(props: PageProps = {}) {
|
|
|
438
443
|
setPage(undefined);
|
|
439
444
|
setPageError(null);
|
|
440
445
|
if (!pdf || !pageNumber) return;
|
|
441
|
-
void pdf
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
446
|
+
void pdf
|
|
447
|
+
.getPage(pageNumber)
|
|
448
|
+
.then((nextPage) => {
|
|
449
|
+
if (!active) return;
|
|
450
|
+
setPage(nextPage);
|
|
451
|
+
})
|
|
452
|
+
.catch((caught: unknown) => {
|
|
453
|
+
if (!active) return;
|
|
454
|
+
const nextError = caught instanceof Error ? caught : new Error(String(caught));
|
|
455
|
+
setPage(false);
|
|
456
|
+
setPageError(nextError);
|
|
457
|
+
onLoadError?.(nextError);
|
|
458
|
+
});
|
|
452
459
|
return () => {
|
|
453
460
|
active = false;
|
|
454
461
|
};
|
|
@@ -492,27 +499,30 @@ export function Page(props: PageProps = {}) {
|
|
|
492
499
|
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
493
500
|
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
494
501
|
canvas.style.visibility = 'hidden';
|
|
495
|
-
void import('pdfjs-dist')
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
502
|
+
void import('pdfjs-dist')
|
|
503
|
+
.then((pdfjs) => {
|
|
504
|
+
if (!active) return;
|
|
505
|
+
renderTask = page.render({
|
|
506
|
+
annotationMode: renderForms
|
|
507
|
+
? pdfjs.AnnotationMode.ENABLE_FORMS
|
|
508
|
+
: pdfjs.AnnotationMode.ENABLE,
|
|
509
|
+
canvas,
|
|
510
|
+
canvasContext: canvas.getContext('2d', { alpha: false })!,
|
|
511
|
+
background: canvasBackground,
|
|
512
|
+
pageColors,
|
|
513
|
+
viewport: renderViewport,
|
|
514
|
+
});
|
|
515
|
+
return renderTask.promise;
|
|
516
|
+
})
|
|
517
|
+
.then(() => {
|
|
518
|
+
if (!active || !renderTask) return;
|
|
519
|
+
canvas.style.visibility = '';
|
|
520
|
+
onRenderSuccess?.(makePageCallback(page, viewport));
|
|
521
|
+
})
|
|
522
|
+
.catch((caught: unknown) => {
|
|
523
|
+
if (!active || (caught instanceof Error && caught.name === 'AbortException')) return;
|
|
524
|
+
onRenderError?.(caught instanceof Error ? caught : new Error(String(caught)));
|
|
506
525
|
});
|
|
507
|
-
return renderTask.promise;
|
|
508
|
-
}).then(() => {
|
|
509
|
-
if (!active || !renderTask) return;
|
|
510
|
-
canvas.style.visibility = '';
|
|
511
|
-
onRenderSuccess?.(makePageCallback(page, viewport));
|
|
512
|
-
}).catch((caught: unknown) => {
|
|
513
|
-
if (!active || caught instanceof Error && caught.name === 'AbortException') return;
|
|
514
|
-
onRenderError?.(caught instanceof Error ? caught : new Error(String(caught)));
|
|
515
|
-
});
|
|
516
526
|
return () => {
|
|
517
527
|
active = false;
|
|
518
528
|
renderTask?.cancel();
|
|
@@ -529,50 +539,52 @@ export function Page(props: PageProps = {}) {
|
|
|
529
539
|
const element = textElement.current;
|
|
530
540
|
if (!element) return;
|
|
531
541
|
element.replaceChildren();
|
|
532
|
-
void page
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
542
|
+
void page
|
|
543
|
+
.getTextContent()
|
|
544
|
+
.then(async (content) => {
|
|
545
|
+
if (!active) return;
|
|
546
|
+
contentLoaded = true;
|
|
547
|
+
onGetTextSuccess?.(content);
|
|
548
|
+
const pdfjs = await import('pdfjs-dist');
|
|
549
|
+
if (!active) return;
|
|
550
|
+
textLayer = new pdfjs.TextLayer({
|
|
551
|
+
container: element,
|
|
552
|
+
textContentSource: page.streamTextContent({ includeMarkedContent: true }),
|
|
553
|
+
viewport,
|
|
554
|
+
}) as { cancel: () => void; render: () => Promise<void> };
|
|
555
|
+
await textLayer.render();
|
|
556
|
+
if (!active) return;
|
|
557
|
+
const end = document.createElement('div');
|
|
558
|
+
end.className = 'endOfContent';
|
|
559
|
+
element.append(end);
|
|
560
|
+
if (customTextRenderer) {
|
|
561
|
+
const children = element.querySelectorAll('[role="presentation"]');
|
|
562
|
+
let childIndex = 0;
|
|
563
|
+
content.items.forEach((item, itemIndex) => {
|
|
564
|
+
if (!('str' in item)) return;
|
|
565
|
+
const child = children[childIndex];
|
|
566
|
+
if (child) {
|
|
567
|
+
renderSafeCustomText(
|
|
568
|
+
child,
|
|
569
|
+
customTextRenderer({
|
|
570
|
+
...item,
|
|
571
|
+
itemIndex,
|
|
572
|
+
pageIndex,
|
|
573
|
+
pageNumber,
|
|
574
|
+
}),
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
childIndex += item.str && item.hasEOL ? 2 : 1;
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
onRenderTextLayerSuccess?.();
|
|
581
|
+
})
|
|
582
|
+
.catch((caught: unknown) => {
|
|
583
|
+
if (!active || (caught instanceof Error && caught.name === 'AbortException')) return;
|
|
584
|
+
const error = caught instanceof Error ? caught : new Error(String(caught));
|
|
585
|
+
if (contentLoaded) onRenderTextLayerError?.(error);
|
|
586
|
+
else onGetTextError?.(error);
|
|
587
|
+
});
|
|
576
588
|
return () => {
|
|
577
589
|
active = false;
|
|
578
590
|
textLayer?.cancel();
|
|
@@ -587,32 +599,32 @@ export function Page(props: PageProps = {}) {
|
|
|
587
599
|
const element = annotationElement.current;
|
|
588
600
|
if (!element) return;
|
|
589
601
|
element.replaceChildren();
|
|
590
|
-
void page
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
602
|
+
void page
|
|
603
|
+
.getAnnotations()
|
|
604
|
+
.then(async (loadedAnnotations) => {
|
|
605
|
+
if (!active) return;
|
|
606
|
+
annotationsLoaded = true;
|
|
607
|
+
onGetAnnotationsSuccess?.(loadedAnnotations);
|
|
608
|
+
const annotations = filterAnnotations
|
|
596
609
|
? filterAnnotations({ annotations: loadedAnnotations })
|
|
597
610
|
: loadedAnnotations;
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
{
|
|
611
|
+
const pdfjs = await import('pdfjs-dist');
|
|
612
|
+
if (!active) return;
|
|
613
|
+
const annotationViewport = viewport.clone({ dontFlip: true });
|
|
614
|
+
const parameters = {
|
|
615
|
+
accessibilityManager: null,
|
|
616
|
+
annotationCanvasMap: null,
|
|
617
|
+
annotationEditorUIManager: null,
|
|
618
|
+
annotationStorage: pdf.annotationStorage,
|
|
619
|
+
commentManager: null,
|
|
620
|
+
div: element,
|
|
621
|
+
l10n: null,
|
|
622
|
+
linkService: documentContext?.linkService,
|
|
623
|
+
page,
|
|
624
|
+
structTreeLayer: null,
|
|
625
|
+
viewport: annotationViewport,
|
|
626
|
+
};
|
|
627
|
+
new pdfjs.AnnotationLayer(parameters as never).render({
|
|
616
628
|
annotations,
|
|
617
629
|
annotationStorage: pdf.annotationStorage,
|
|
618
630
|
div: element,
|
|
@@ -621,37 +633,46 @@ export function Page(props: PageProps = {}) {
|
|
|
621
633
|
page,
|
|
622
634
|
renderForms,
|
|
623
635
|
viewport: annotationViewport,
|
|
624
|
-
} as never
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
});
|
|
636
|
+
} as never);
|
|
637
|
+
onRenderAnnotationLayerSuccess?.();
|
|
638
|
+
})
|
|
639
|
+
.catch((caught: unknown) => {
|
|
640
|
+
if (!active) return;
|
|
641
|
+
const error = caught instanceof Error ? caught : new Error(String(caught));
|
|
642
|
+
if (annotationsLoaded) onRenderAnnotationLayerError?.(error);
|
|
643
|
+
else onGetAnnotationsError?.(error);
|
|
644
|
+
});
|
|
634
645
|
return () => {
|
|
635
646
|
active = false;
|
|
636
647
|
element.replaceChildren();
|
|
637
648
|
};
|
|
638
|
-
}, [
|
|
649
|
+
}, [
|
|
650
|
+
filterAnnotations,
|
|
651
|
+
imageResourcesPath,
|
|
652
|
+
page,
|
|
653
|
+
pdf,
|
|
654
|
+
renderAnnotationLayer,
|
|
655
|
+
renderForms,
|
|
656
|
+
viewport,
|
|
657
|
+
]);
|
|
639
658
|
|
|
640
659
|
useEffect(() => {
|
|
641
660
|
let active = true;
|
|
642
661
|
setStructTree(undefined);
|
|
643
662
|
if (!page || customTextRenderer || !renderTextLayer) return;
|
|
644
|
-
void page
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
663
|
+
void page
|
|
664
|
+
.getStructTree()
|
|
665
|
+
.then((tree) => {
|
|
666
|
+
if (!active) return;
|
|
667
|
+
setStructTree(tree);
|
|
668
|
+
if (tree) onGetStructTreeSuccess?.(tree);
|
|
669
|
+
})
|
|
670
|
+
.catch((caught: unknown) => {
|
|
671
|
+
if (!active) return;
|
|
672
|
+
const error = caught instanceof Error ? caught : new Error(String(caught));
|
|
673
|
+
setStructTree(null);
|
|
674
|
+
onGetStructTreeError?.(error);
|
|
675
|
+
});
|
|
655
676
|
return () => {
|
|
656
677
|
active = false;
|
|
657
678
|
};
|
|
@@ -670,68 +691,76 @@ export function Page(props: PageProps = {}) {
|
|
|
670
691
|
|
|
671
692
|
let content: unknown;
|
|
672
693
|
if (!pageNumber) {
|
|
673
|
-
content =
|
|
674
|
-
noData
|
|
675
|
-
)
|
|
694
|
+
content = (
|
|
695
|
+
<div class="react-pdf__message react-pdf__message--no-data">{renderMessage(noData)}</div>
|
|
696
|
+
);
|
|
676
697
|
} else if (pdf === false || page === false || pageError) {
|
|
677
|
-
content =
|
|
678
|
-
error
|
|
679
|
-
)
|
|
698
|
+
content = (
|
|
699
|
+
<div class="react-pdf__message react-pdf__message--error">{renderMessage(error)}</div>
|
|
700
|
+
);
|
|
680
701
|
} else if (!page || !viewport || !contextValue) {
|
|
681
|
-
content =
|
|
682
|
-
loading
|
|
683
|
-
)
|
|
702
|
+
content = (
|
|
703
|
+
<div class="react-pdf__message react-pdf__message--loading">{renderMessage(loading)}</div>
|
|
704
|
+
);
|
|
684
705
|
} else {
|
|
685
706
|
if (renderMode === 'custom' && !customRenderer) {
|
|
686
707
|
throw new Error('renderMode was set to "custom", but no customRenderer was passed.');
|
|
687
708
|
}
|
|
688
709
|
const renderProps = contextValue as PageRenderProps;
|
|
689
|
-
content =
|
|
690
|
-
{
|
|
691
|
-
?
|
|
710
|
+
content = (
|
|
711
|
+
<PageContext value={contextValue}>
|
|
712
|
+
{renderMode === 'canvas' ? (
|
|
713
|
+
<canvas
|
|
692
714
|
ref={canvasElement}
|
|
693
715
|
class="react-pdf__Page__canvas"
|
|
694
716
|
dir="ltr"
|
|
695
717
|
style={{ display: 'block', userSelect: 'none' }}
|
|
696
718
|
>
|
|
697
|
-
{renderTextLayer && structTree
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
719
|
+
{renderTextLayer && structTree ? (
|
|
720
|
+
<StructTreeItem
|
|
721
|
+
className="react-pdf__Page__structTree structTree"
|
|
722
|
+
node={structTree}
|
|
723
|
+
/>
|
|
724
|
+
) : null}
|
|
703
725
|
</canvas>
|
|
704
|
-
: null}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
: null}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
: null}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
726
|
+
) : null}
|
|
727
|
+
{renderMode === 'custom' && customRenderer ? createElement(customRenderer, {}) : null}
|
|
728
|
+
{renderTextLayer ? (
|
|
729
|
+
<div ref={textElement} class="react-pdf__Page__textContent textLayer" />
|
|
730
|
+
) : null}
|
|
731
|
+
{renderAnnotationLayer ? (
|
|
732
|
+
<div ref={annotationElement} class="react-pdf__Page__annotations annotationLayer" />
|
|
733
|
+
) : null}
|
|
734
|
+
{typeof children === 'function' && !isChildrenBlock(children)
|
|
735
|
+
? children(renderProps)
|
|
736
|
+
: children}
|
|
737
|
+
</PageContext>
|
|
738
|
+
);
|
|
716
739
|
}
|
|
717
740
|
|
|
718
|
-
return
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
741
|
+
return (
|
|
742
|
+
<div
|
|
743
|
+
{...withEventData(hostProps, page && viewport ? makePageCallback(page, viewport) : page)}
|
|
744
|
+
ref={pageElement}
|
|
745
|
+
class={[_className, classProp, className]}
|
|
746
|
+
data-page-number={pageNumber}
|
|
747
|
+
style={
|
|
748
|
+
{
|
|
749
|
+
'--scale-round-x': '1px',
|
|
750
|
+
'--scale-round-y': '1px',
|
|
751
|
+
'--scale-factor': '1',
|
|
752
|
+
'--user-unit': `${viewport?.scale ?? scaleProp}`,
|
|
753
|
+
'--total-scale-factor': 'calc(var(--scale-factor) * var(--user-unit))',
|
|
754
|
+
backgroundColor: canvasBackground || 'white',
|
|
755
|
+
minHeight: 'min-content',
|
|
756
|
+
minWidth: 'min-content',
|
|
757
|
+
position: 'relative',
|
|
758
|
+
} as never
|
|
759
|
+
}
|
|
760
|
+
>
|
|
761
|
+
{content}
|
|
762
|
+
</div>
|
|
763
|
+
);
|
|
735
764
|
}
|
|
736
765
|
|
|
737
766
|
export function Thumbnail(props: ThumbnailProps = {}) {
|
|
@@ -742,8 +771,7 @@ export function Thumbnail(props: ThumbnailProps = {}) {
|
|
|
742
771
|
throw new Error('Attempted to load a thumbnail, but no document was specified.');
|
|
743
772
|
}
|
|
744
773
|
const resolvedPageNumber = pageNumber ?? (pageIndex != null ? pageIndex + 1 : undefined);
|
|
745
|
-
const resolvedPageIndex =
|
|
746
|
-
resolvedPageNumber != null ? resolvedPageNumber - 1 : 0;
|
|
774
|
+
const resolvedPageIndex = resolvedPageNumber != null ? resolvedPageNumber - 1 : 0;
|
|
747
775
|
|
|
748
776
|
function handleClick(event: MouseEvent) {
|
|
749
777
|
event.preventDefault();
|
|
@@ -751,25 +779,30 @@ export function Thumbnail(props: ThumbnailProps = {}) {
|
|
|
751
779
|
const args = { pageIndex: resolvedPageIndex, pageNumber: resolvedPageNumber };
|
|
752
780
|
if (onItemClick) onItemClick(args);
|
|
753
781
|
else if (documentContext?.linkService) documentContext.linkService.goToPage(resolvedPageNumber);
|
|
754
|
-
else
|
|
782
|
+
else
|
|
783
|
+
throw new Error(
|
|
784
|
+
'Either onItemClick callback or linkService must be defined in order to navigate to an outline item.',
|
|
785
|
+
);
|
|
755
786
|
}
|
|
756
787
|
|
|
757
788
|
const { class: _class, className: _className, onItemClick: _onItemClick, ...pageProps } = props;
|
|
758
|
-
return
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
789
|
+
return (
|
|
790
|
+
<a
|
|
791
|
+
class={['react-pdf__Thumbnail', classProp, className]}
|
|
792
|
+
href={resolvedPageNumber ? '#' : undefined}
|
|
793
|
+
onClick={handleClick}
|
|
794
|
+
>
|
|
795
|
+
<Page
|
|
796
|
+
{...pageProps}
|
|
797
|
+
_className="react-pdf__Thumbnail__page"
|
|
798
|
+
_enableRegisterUnregisterPage={false}
|
|
799
|
+
pageIndex={pageIndex}
|
|
800
|
+
pageNumber={pageNumber}
|
|
801
|
+
renderAnnotationLayer={false}
|
|
802
|
+
renderTextLayer={false}
|
|
803
|
+
/>
|
|
804
|
+
</a>
|
|
805
|
+
);
|
|
773
806
|
}
|
|
774
807
|
|
|
775
808
|
type OutlineEntry = NonNullable<Awaited<ReturnType<PDFDocumentProxy['getOutline']>>>[number];
|
|
@@ -788,14 +821,15 @@ function OutlineItem({
|
|
|
788
821
|
async function activate(event: Event) {
|
|
789
822
|
event.preventDefault();
|
|
790
823
|
if (!onItemClick && !linkService) {
|
|
791
|
-
throw new Error(
|
|
824
|
+
throw new Error(
|
|
825
|
+
'Either onItemClick callback or linkService must be defined in order to navigate to an outline item.',
|
|
826
|
+
);
|
|
792
827
|
}
|
|
793
828
|
if (!onItemClick) {
|
|
794
829
|
void linkService?.goToDestination(item.dest);
|
|
795
830
|
return;
|
|
796
831
|
}
|
|
797
|
-
const dest =
|
|
798
|
-
typeof item.dest === 'string' ? await pdf.getDestination(item.dest) : item.dest;
|
|
832
|
+
const dest = typeof item.dest === 'string' ? await pdf.getDestination(item.dest) : item.dest;
|
|
799
833
|
if (!dest) throw new Error('Destination not found.');
|
|
800
834
|
const reference = dest[0];
|
|
801
835
|
const pageIndex =
|
|
@@ -804,20 +838,25 @@ function OutlineItem({
|
|
|
804
838
|
onItemClick(args);
|
|
805
839
|
}
|
|
806
840
|
|
|
807
|
-
return
|
|
808
|
-
<
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
841
|
+
return (
|
|
842
|
+
<li>
|
|
843
|
+
<a href="#" onClick={activate}>
|
|
844
|
+
{item.title}
|
|
845
|
+
</a>
|
|
846
|
+
{item.items?.length ? (
|
|
847
|
+
<ul>
|
|
848
|
+
{item.items.map((child) => (
|
|
812
849
|
<OutlineItem
|
|
813
850
|
item={child}
|
|
814
851
|
linkService={linkService}
|
|
815
852
|
pdf={pdf}
|
|
816
853
|
onItemClick={onItemClick}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
854
|
+
/>
|
|
855
|
+
))}
|
|
856
|
+
</ul>
|
|
857
|
+
) : null}
|
|
858
|
+
</li>
|
|
859
|
+
);
|
|
821
860
|
}
|
|
822
861
|
|
|
823
862
|
export function Outline(props: OutlineProps = {}) {
|
|
@@ -850,17 +889,19 @@ export function Outline(props: OutlineProps = {}) {
|
|
|
850
889
|
let active = true;
|
|
851
890
|
setOutline(undefined);
|
|
852
891
|
setFailed(false);
|
|
853
|
-
void pdf
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
892
|
+
void pdf
|
|
893
|
+
.getOutline()
|
|
894
|
+
.then((nextOutline) => {
|
|
895
|
+
if (!active) return;
|
|
896
|
+
setOutline(nextOutline);
|
|
897
|
+
onLoadSuccess?.(nextOutline);
|
|
898
|
+
})
|
|
899
|
+
.catch((caught: unknown) => {
|
|
900
|
+
if (!active) return;
|
|
901
|
+
const error = caught instanceof Error ? caught : new Error(String(caught));
|
|
902
|
+
setFailed(true);
|
|
903
|
+
onLoadError?.(error);
|
|
904
|
+
});
|
|
864
905
|
return () => {
|
|
865
906
|
active = false;
|
|
866
907
|
};
|
|
@@ -868,21 +909,24 @@ export function Outline(props: OutlineProps = {}) {
|
|
|
868
909
|
|
|
869
910
|
if (failed || !outline) return null;
|
|
870
911
|
const clickHandler = onItemClick ?? documentContext?.onItemClick;
|
|
871
|
-
return
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
<
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
912
|
+
return (
|
|
913
|
+
<div
|
|
914
|
+
{...withEventData(hostProps, outline)}
|
|
915
|
+
ref={outlineElement}
|
|
916
|
+
class={['react-pdf__Outline', classProp, className]}
|
|
917
|
+
>
|
|
918
|
+
<OutlineContext value={{ onItemClick: clickHandler }}>
|
|
919
|
+
<ul>
|
|
920
|
+
{outline.map((item) => (
|
|
921
|
+
<OutlineItem
|
|
922
|
+
item={item}
|
|
923
|
+
linkService={documentContext?.linkService}
|
|
924
|
+
pdf={pdf}
|
|
925
|
+
onItemClick={clickHandler}
|
|
926
|
+
/>
|
|
927
|
+
))}
|
|
928
|
+
</ul>
|
|
929
|
+
</OutlineContext>
|
|
930
|
+
</div>
|
|
931
|
+
);
|
|
888
932
|
}
|