From dc77a1d42382970f0cf826f96a96ec1caf2505df Mon Sep 17 00:00:00 2001 From: Matt Herbst Date: Sun, 18 Aug 2024 22:39:20 -0700 Subject: [PATCH] onBeforePrint improvements prep for v3-beta2 --- CHANGELOG.md | 10 +++--- package.json | 2 +- src/hooks/useReactToPrint.ts | 49 ++++++++++++++++------------ src/types/UseReactToPrintOptions.ts | 3 +- src/utils/appendPrintWindow.ts | 19 +++++++++++ src/utils/handleOnBeforePrint.ts | 28 ---------------- src/utils/handlePrintWindowOnLoad.ts | 2 +- 7 files changed, 58 insertions(+), 55 deletions(-) create mode 100644 src/utils/appendPrintWindow.ts delete mode 100644 src/utils/handleOnBeforePrint.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a566be..c0fbfac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,21 @@ ## (BETA) 3.0.0 (15 Jul 2024) -React 19 support + API modernization [717](https://github.com/MatthewHerbst/react-to-print/pull/717) +- FEATURE [717](https://github.com/MatthewHerbst/react-to-print/pull/717): React 19 support + API modernization +- CHORE: package size reduced by 18.7kb (34%) ### BREAKING CHANGES - `content` renamed to `contentRef` and type changed from `() => React.ReactInstance` to `RefObject`. The core impact here is that Class components now need to have the ref forwarded via props internally to a DOM node -- React ^16.8.0 required (dropped support for React versions that don't support hooks) -- `onBeforeGetContent` removed. Use `onBeforePrint` +- React >= 16.8.0 required (dropped support for React versions that don't support hooks) +- `onBeforeGetContent` removed. Use `onBeforePrint`, which similar to `onBeforeGetContent`, now runs before the print iframe is loaded - `removeAfterPrint` renamed to `preserveAfterPrint` which defaults to `false` - `ReactToPrint` removed. Use `useReactToPrint` - `PrintContextConsumer` removed. Use `useReactToPrint` -- `trigger`removed, call the function returned by `useReactToPrint` +- `trigger` removed, use the function returned by `useReactToPrint` - `IReactToPrintProps` renamed to `UseReactToPrintOptions` - Default package export removed, use named `useReactToPrint` export +- Removed `event?: unknown` type from `useReactToPrint` callback. `optionalContent` is now the only (optional) argument - Build is now ES6 code. Previously it was ES5 - No longer officially support IE11 (will still try but no promises) diff --git a/package.json b/package.json index 8535efb..bd2f848 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ ], "scripts": { "build": "NODE_ENV=production webpack --progress", - "lint": "eslint src/**/*.{ts,tsx}", + "lint": "eslint ./src", "prepare": "npm run build && husky install", "start": "NODE_ENV=development webpack serve" }, diff --git a/src/hooks/useReactToPrint.ts b/src/hooks/useReactToPrint.ts index 3b28a40..c386deb 100644 --- a/src/hooks/useReactToPrint.ts +++ b/src/hooks/useReactToPrint.ts @@ -5,17 +5,20 @@ import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions"; import { getContentNode } from "../utils/getContentNode"; import { generatePrintWindow } from "../utils/generatePrintWindow"; import { logMessages } from "../utils/logMessage"; -import { handleOnBeforePrint } from "../utils/handleOnBeforePrint"; import { UseReactToPrintHookContent } from "../types/UseReactToPrintHookContent"; -import { handlePrintWindowOnLoad } from "../utils/handlePrintWindowOnLoad"; +import { HandlePrintWindowOnLoadData } from "../utils/handlePrintWindowOnLoad"; import { removePrintIframe } from "../utils/removePrintIframe"; import { UseReactToPrintFn } from "../types/UseReactToPrintFn"; +import { appendPrintWindow } from "../utils/appendPrintWindow"; +import { startPrint } from "../utils/startPrint"; export function useReactToPrint(options: UseReactToPrintOptions): UseReactToPrintFn { const { contentRef, fonts, ignoreGlobalStyles, + onBeforePrint, + onPrintError, preserveAfterPrint, suppressErrors, } = options; @@ -65,6 +68,10 @@ export function useReactToPrint(options: UseReactToPrintOptions): UseReactToPrin const printWindow = generatePrintWindow(); + /** + * Keeps track of loaded resources, kicking off the actual print function once all + * resources have been marked (loaded or failed) + */ const markLoaded = (resource: Element | Font | FontFace, errorMessages?: unknown[]) => { if (resourcesLoaded.includes(resource)) { logMessages({ @@ -93,27 +100,29 @@ export function useReactToPrint(options: UseReactToPrintOptions): UseReactToPrin const numResourcesManaged = resourcesLoaded.length + resourcesErrored.length; if (numResourcesManaged === numResourcesToLoad) { - handleOnBeforePrint( - printWindow, - options, - ); + startPrint(printWindow, options); } }; - printWindow.onload = () => handlePrintWindowOnLoad( - printWindow, - markLoaded, - { - clonedContentNode, - contentNode, - numResourcesToLoad, - renderComponentImgNodes, - renderComponentVideoNodes, - }, - options - ); - - document.body.appendChild(printWindow); + const data: HandlePrintWindowOnLoadData = { + clonedContentNode, + contentNode, + numResourcesToLoad, + renderComponentImgNodes, + renderComponentVideoNodes, + } + + // Ensure we run `onBeforePrint` before appending the print window, which kicks off loading + // needed resources once mounted + if (onBeforePrint) { + onBeforePrint() + .then(() => appendPrintWindow(printWindow, markLoaded, data, options)) + .catch((error: Error) => { + onPrintError?.("onBeforePrint", error); + }); + } else { + appendPrintWindow(printWindow, markLoaded, data, options); + } }, [options]); return handlePrint; diff --git a/src/types/UseReactToPrintOptions.ts b/src/types/UseReactToPrintOptions.ts index aa8efa6..36db382 100644 --- a/src/types/UseReactToPrintOptions.ts +++ b/src/types/UseReactToPrintOptions.ts @@ -28,7 +28,8 @@ export interface UseReactToPrintOptions { onAfterPrint?: () => void; /** * Callback function that triggers before print. This can be used to change the content on the - * page before printing as an alternative to, or in conjunction with `@media print` queries + * page before printing as an alternative to, or in conjunction with `@media print` queries. Is + * run prior to the print iframe being mounted. */ onBeforePrint?: () => Promise; /** diff --git a/src/utils/appendPrintWindow.ts b/src/utils/appendPrintWindow.ts new file mode 100644 index 0000000..d1deb17 --- /dev/null +++ b/src/utils/appendPrintWindow.ts @@ -0,0 +1,19 @@ +import { Font } from "../types/Font"; +import { UseReactToPrintOptions } from "../types/UseReactToPrintOptions"; +import { handlePrintWindowOnLoad, HandlePrintWindowOnLoadData } from "./handlePrintWindowOnLoad"; + +export function appendPrintWindow( + printWindow: HTMLIFrameElement, + markLoaded: (resource: Element | Font | FontFace, errorMessages?: unknown[]) => void, + data: HandlePrintWindowOnLoadData, + options: UseReactToPrintOptions, +) { + printWindow.onload = () => handlePrintWindowOnLoad( + printWindow, + markLoaded, + data, + options + ); + + document.body.appendChild(printWindow); +} \ No newline at end of file diff --git a/src/utils/handleOnBeforePrint.ts b/src/utils/handleOnBeforePrint.ts deleted file mode 100644 index cc883fd..0000000 --- a/src/utils/handleOnBeforePrint.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { startPrint } from "./startPrint"; -import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions"; - -/** - * Begins the printing process. Ensures proper calling of `onBeforePrint` when specified before - * handing off to the main printing function. - */ -export function handleOnBeforePrint( - printWindow: HTMLIFrameElement, - options: UseReactToPrintOptions, -) { - const { - onBeforePrint, - onPrintError, - } = options; - - if (onBeforePrint) { - onBeforePrint() - .then(() => { - startPrint(printWindow, options); - }) - .catch((error: Error) => { - onPrintError?.("onBeforePrint", error); - }); - } else { - startPrint(printWindow, options); - } -} \ No newline at end of file diff --git a/src/utils/handlePrintWindowOnLoad.ts b/src/utils/handlePrintWindowOnLoad.ts index 45ba8af..afac135 100644 --- a/src/utils/handlePrintWindowOnLoad.ts +++ b/src/utils/handlePrintWindowOnLoad.ts @@ -3,7 +3,7 @@ import { startPrint } from "./startPrint"; import { Font } from "../types/Font"; import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions"; -type HandlePrintWindowOnLoadData = { +export type HandlePrintWindowOnLoadData = { clonedContentNode: Node; contentNode: Node; numResourcesToLoad: number;