diff --git a/packages/react-pdf/README.md b/packages/react-pdf/README.md index 72438e205..9b8d6bdac 100644 --- a/packages/react-pdf/README.md +++ b/packages/react-pdf/README.md @@ -489,6 +489,7 @@ Displays a page. Should be placed inside ``. Alternatively, it can h | Prop name | Description | Default value | Example values | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| annotationMode | Annotation mode. | `AnnotationMode.ENABLE` | `AnnotationMode.ENABLE_FORMS` | | canvasBackground | Canvas background color. Any valid `canvas.fillStyle` can be used. | n/a | `"transparent"` | | canvasRef | A prop that behaves like [ref](https://reactjs.org/docs/refs-and-the-dom.html), but it's passed to `` rendered by `` component. | n/a |
  • Function:
    `(ref) => { this.myCanvas = ref; }`
  • Ref created using `createRef`:
    `this.ref = createRef();`

    `inputRef={this.ref}`
  • Ref created using `useRef`:
    `const ref = useRef();`

    `inputRef={ref}`
| | className | Class name(s) that will be added to rendered element along with the default `react-pdf__Page`. | n/a |
  • String:
    `"custom-class-name-1 custom-class-name-2"`
  • Array of strings:
    `["custom-class-name-1", "custom-class-name-2"]`
| @@ -548,6 +549,7 @@ Displays a thumbnail of a page. Does not render the annotation layer or the text Props are the same as in `` component, but certain annotation layer and text layer-related props are not available: +- annotationMode - customTextRenderer - onGetAnnotationsError - onGetAnnotationsSuccess diff --git a/packages/react-pdf/src/AnnotationMode.ts b/packages/react-pdf/src/AnnotationMode.ts new file mode 100644 index 000000000..5d80c8506 --- /dev/null +++ b/packages/react-pdf/src/AnnotationMode.ts @@ -0,0 +1,5 @@ +import * as pdfjs from 'pdfjs-dist'; + +const AnnotationMode: typeof pdfjs.AnnotationMode = pdfjs.AnnotationMode; + +export default AnnotationMode; diff --git a/packages/react-pdf/src/Page.spec.tsx b/packages/react-pdf/src/Page.spec.tsx index 88aafac29..95a185060 100644 --- a/packages/react-pdf/src/Page.spec.tsx +++ b/packages/react-pdf/src/Page.spec.tsx @@ -5,6 +5,7 @@ import { fireEvent, render } from '@testing-library/react'; import { pdfjs } from './index.test.js'; import Page from './Page.js'; +import AnnotationMode from './AnnotationMode.js'; import LinkService from './LinkService.js'; import failingPdf from '../../../__mocks__/_failing_pdf.js'; @@ -760,6 +761,32 @@ describe('Page', () => { expect(textWidgetAnnotation).toBeFalsy(); }); + it('requests page to be rendered with forms when given annotationMode = AnnotationMode.ENABLE_FORMS', async () => { + const { func: onRenderAnnotationLayerSuccess, promise: onRenderAnnotationLayerSuccessPromise } = + makeAsyncCallback(); + + const { container } = renderWithContext( + , + { + linkService, + pdf: pdf4, + }, + ); + + expect.assertions(1); + + await onRenderAnnotationLayerSuccessPromise; + + const textWidgetAnnotation = container.querySelector('.textWidgetAnnotation'); + + expect(textWidgetAnnotation).toBeTruthy(); + }); + it('requests page to be rendered with forms given renderForms = true', async () => { const { func: onRenderAnnotationLayerSuccess, promise: onRenderAnnotationLayerSuccessPromise } = makeAsyncCallback(); diff --git a/packages/react-pdf/src/Page.tsx b/packages/react-pdf/src/Page.tsx index bb7497536..d5fa8c766 100644 --- a/packages/react-pdf/src/Page.tsx +++ b/packages/react-pdf/src/Page.tsx @@ -8,6 +8,7 @@ import mergeRefs from 'merge-refs'; import invariant from 'tiny-invariant'; import warning from 'warning'; +import AnnotationMode from './AnnotationMode.js'; import PageContext from './PageContext.js'; import Message from './Message.js'; @@ -50,6 +51,13 @@ const defaultScale = 1; export type PageProps = { _className?: string; _enableRegisterUnregisterPage?: boolean; + /** + * Annotation mode. + * + * @default AnnotationMode.ENABLE + * @example AnnotationMode.ENABLE_FORMS + */ + annotationMode?: (typeof AnnotationMode)[keyof typeof AnnotationMode]; /** * Canvas background color. Any valid `canvas.fillStyle` can be used. * @@ -307,6 +315,7 @@ export default function Page(props: PageProps): React.ReactElement { const { _className = 'react-pdf__Page', _enableRegisterUnregisterPage = true, + annotationMode = AnnotationMode.ENABLE, canvasBackground, canvasRef, children, @@ -493,6 +502,7 @@ export default function Page(props: PageProps): React.ReactElement { page && isProvided(pageIndex) && pageNumber && isProvided(rotate) && isProvided(scale) ? { _className, + annotationMode, canvasBackground, customTextRenderer, devicePixelRatio, @@ -519,6 +529,7 @@ export default function Page(props: PageProps): React.ReactElement { : null, [ _className, + annotationMode, canvasBackground, customTextRenderer, devicePixelRatio, diff --git a/packages/react-pdf/src/Page/AnnotationLayer.tsx b/packages/react-pdf/src/Page/AnnotationLayer.tsx index f1dc37a64..2e54d79a5 100644 --- a/packages/react-pdf/src/Page/AnnotationLayer.tsx +++ b/packages/react-pdf/src/Page/AnnotationLayer.tsx @@ -7,6 +7,8 @@ import invariant from 'tiny-invariant'; import warning from 'warning'; import * as pdfjs from 'pdfjs-dist'; +import AnnotationMode from '../AnnotationMode.js'; + import useDocumentContext from '../shared/hooks/useDocumentContext.js'; import usePageContext from '../shared/hooks/usePageContext.js'; import useResolver from '../shared/hooks/useResolver.js'; @@ -22,6 +24,7 @@ export default function AnnotationLayer(): React.ReactElement { const mergedProps = { ...documentContext, ...pageContext }; const { + annotationMode, imageResourcesPath, linkService, onGetAnnotationsError: onGetAnnotationsErrorProps, @@ -176,7 +179,7 @@ export default function AnnotationLayer(): React.ReactElement { imageResourcesPath, linkService, page, - renderForms, + renderForms: annotationMode === AnnotationMode.ENABLE_FORMS ? renderForms : false, viewport: clonedViewport, }; @@ -195,7 +198,16 @@ export default function AnnotationLayer(): React.ReactElement { // TODO: Cancel running task? }; }, - [annotations, imageResourcesPath, linkService, page, pdf, renderForms, viewport], + [ + annotationMode, + annotations, + imageResourcesPath, + linkService, + page, + pdf, + renderForms, + viewport, + ], ); return ( diff --git a/packages/react-pdf/src/Page/Canvas.tsx b/packages/react-pdf/src/Page/Canvas.tsx index 3f7f61d58..792b99eca 100644 --- a/packages/react-pdf/src/Page/Canvas.tsx +++ b/packages/react-pdf/src/Page/Canvas.tsx @@ -4,8 +4,8 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'; import mergeRefs from 'merge-refs'; import invariant from 'tiny-invariant'; import warning from 'warning'; -import * as pdfjs from 'pdfjs-dist'; +import AnnotationMode from '../AnnotationMode.js'; import StructTree from '../StructTree.js'; import usePageContext from '../shared/hooks/usePageContext.js'; @@ -18,8 +18,6 @@ import { import type { RenderParameters } from 'pdfjs-dist/types/src/display/api.js'; -const ANNOTATION_MODE = pdfjs.AnnotationMode; - type CanvasProps = { canvasRef?: React.Ref; }; @@ -32,6 +30,7 @@ export default function Canvas(props: CanvasProps): React.ReactElement { const mergedProps = { ...pageContext, ...props }; const { _className, + annotationMode, canvasBackground, devicePixelRatio = getDevicePixelRatio(), onRenderError: onRenderErrorProps, @@ -111,7 +110,8 @@ export default function Canvas(props: CanvasProps): React.ReactElement { canvas.style.visibility = 'hidden'; const renderContext: RenderParameters = { - annotationMode: renderForms ? ANNOTATION_MODE.ENABLE_FORMS : ANNOTATION_MODE.ENABLE, + annotationMode: + annotationMode ?? (renderForms ? AnnotationMode.ENABLE_FORMS : AnnotationMode.ENABLE), canvasContext: canvas.getContext('2d', { alpha: false }) as CanvasRenderingContext2D, viewport: renderViewport, }; @@ -132,7 +132,7 @@ export default function Canvas(props: CanvasProps): React.ReactElement { return () => cancelRunningTask(runningTask); }, - [canvasBackground, page, renderForms, renderViewport, viewport], + [annotationMode, canvasBackground, page, renderForms, renderViewport, viewport], ); const cleanup = useCallback(() => { diff --git a/packages/react-pdf/src/Thumbnail.tsx b/packages/react-pdf/src/Thumbnail.tsx index 6db3b4e97..e80f8c664 100644 --- a/packages/react-pdf/src/Thumbnail.tsx +++ b/packages/react-pdf/src/Thumbnail.tsx @@ -14,6 +14,7 @@ import type { ClassName, OnItemClickArgs } from './shared/types.js'; export type ThumbnailProps = Omit< PageProps, + | 'annotationMode' | 'className' | 'customTextRenderer' | 'onGetAnnotationsError' diff --git a/packages/react-pdf/src/index.ts b/packages/react-pdf/src/index.ts index 1d5a79371..846e269bf 100644 --- a/packages/react-pdf/src/index.ts +++ b/packages/react-pdf/src/index.ts @@ -9,6 +9,7 @@ import useDocumentContext from './shared/hooks/useDocumentContext.js'; import useOutlineContext from './shared/hooks/useOutlineContext.js'; import usePageContext from './shared/hooks/usePageContext.js'; +import AnnotationMode from './AnnotationMode.js'; import PasswordResponses from './PasswordResponses.js'; export type { DocumentProps } from './Document.js'; @@ -31,5 +32,6 @@ export { useDocumentContext, useOutlineContext, usePageContext, + AnnotationMode, PasswordResponses, }; diff --git a/packages/react-pdf/src/shared/types.ts b/packages/react-pdf/src/shared/types.ts index cc5258405..df62bf343 100644 --- a/packages/react-pdf/src/shared/types.ts +++ b/packages/react-pdf/src/shared/types.ts @@ -14,6 +14,7 @@ import type { TextMarkedContent, } from 'pdfjs-dist/types/src/display/api.js'; import type { AnnotationLayerParameters } from 'pdfjs-dist/types/src/display/annotation_layer.js'; +import type AnnotationMode from '../AnnotationMode.js'; import type LinkService from '../LinkService.js'; export type { PasswordResponses, StructTreeNode, TextContent, TextItem, TextMarkedContent }; @@ -143,6 +144,7 @@ export type DocumentContextType = { export type PageContextType = { _className?: string; + annotationMode?: (typeof AnnotationMode)[keyof typeof AnnotationMode]; canvasBackground?: string; customTextRenderer?: CustomTextRenderer; devicePixelRatio?: number; diff --git a/test/AnnotationOptions.tsx b/test/AnnotationOptions.tsx index 77454df9f..8534ac49c 100644 --- a/test/AnnotationOptions.tsx +++ b/test/AnnotationOptions.tsx @@ -29,7 +29,7 @@ export default function AnnotationOptions({
Annotation options - +
void; setRenderAnnotationLayer: (value: boolean) => void; setRenderForms: (value: boolean) => void; setRenderTextLayer: (value: boolean) => void; @@ -12,20 +16,29 @@ type LayerOptionsProps = { }; export default function LayerOptions({ + annotationMode, renderAnnotationLayer, renderForms, renderTextLayer, useCustomTextRenderer, + setAnnotationMode, setRenderAnnotationLayer, setRenderForms, setRenderTextLayer, setUseCustomTextRenderer, }: LayerOptionsProps) { + const annotationModeId = useId(); const renderTextLayerId = useId(); const useCustomTextRendererId = useId(); const renderAnnotationLayerId = useId(); const renderFormsId = useId(); + function onAnnotationModeChange(event: React.ChangeEvent) { + const { value } = event.target; + + setAnnotationMode(value as keyof typeof AnnotationMode); + } + function onRenderAnnotationLayerChange(event: React.ChangeEvent) { setRenderAnnotationLayer(event.target.checked); } @@ -46,6 +59,48 @@ export default function LayerOptions({
Layer options + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
{ } export default function Test() { + const [annotationMode, setAnnotationMode] = useState(); const [canvasBackground, setCanvasBackground] = useState(); const [devicePixelRatio, setDevicePixelRatio] = useState(); const [displayAll, setDisplayAll] = useState(false); @@ -83,7 +85,6 @@ export default function Test() { const [passMethod, setPassMethod] = useState(); const [render, setRender] = useState(true); const [renderAnnotationLayer, setRenderAnnotationLayer] = useState(true); - const [renderForms, setRenderForms] = useState(true); const [renderMode, setRenderMode] = useState('canvas'); const [renderTextLayer, setRenderTextLayer] = useState(true); const [useCustomTextRenderer, setUseCustomTextRenderer] = useState(true); @@ -214,6 +215,7 @@ export default function Test() { }; const pageProps = { + annotationMode, canvasBackground, className: 'custom-classname-page', customRenderer: CustomRenderer, @@ -223,7 +225,6 @@ export default function Test() { onClick: onPageClick, onRenderSuccess: onPageRenderSuccess, renderAnnotationLayer, - renderForms, renderMode, renderTextLayer, scale: pageScale, @@ -240,12 +241,12 @@ export default function Test() {