diff --git a/src/component/elements/print/PrintContent.tsx b/src/component/elements/print/PrintContent.tsx index 1ff8670ef..2d6082e20 100644 --- a/src/component/elements/print/PrintContent.tsx +++ b/src/component/elements/print/PrintContent.tsx @@ -3,7 +3,7 @@ import { revalidateLogic } from '@tanstack/react-form'; import { useSelector } from '@tanstack/react-store'; import type { PrintPageOptions } from '@zakodium/nmrium-core'; import type { CSSProperties, ReactNode } from 'react'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { createPortal } from 'react-dom'; import { AppForm, Button, coerceNumberInput, useForm } from 'react-science/ui'; import { z } from 'zod'; @@ -14,8 +14,6 @@ import { StyledDialogBody } from '../StyledDialogBody.js'; import { PrintProvider } from './PrintProvider.js'; import { getSizesList, pageSizes } from './pageSize.js'; -const isFirefox = navigator.userAgent.toLowerCase().includes('firefox'); - interface BasePrintProps { onPrint: (options: PrintPageOptions) => void; defaultPrintPageOptions: Partial; @@ -24,6 +22,7 @@ interface InnerPrintFrameProps { children: ReactNode; onAfterPrint?: () => void; onBeforePrint?: () => void; + onError?: (error: Error) => void; printPageOptions?: Partial; } interface PrintFrameProps @@ -42,6 +41,7 @@ export function PrintContent(props: PrintFrameProps) { printPageOptions, defaultPrintPageOptions, onPrint, + onError, } = props; useEffect(() => { @@ -102,6 +102,10 @@ export function PrintContent(props: PrintFrameProps) { onBeforePrint={() => { onBeforePrint?.(); }} + onError={(error) => { + setPageOptions(null); + onError?.(error); + }} > {children} @@ -114,6 +118,7 @@ function InnerPrintFrame(props: InnerPrintFrameProps) { children, onAfterPrint, onBeforePrint, + onError, printPageOptions = {}, } = props; @@ -122,80 +127,69 @@ function InnerPrintFrame(props: InnerPrintFrameProps) { margin = 0, layout = 'landscape', } = printPageOptions || {}; - - const frameRef = useRef(null); - const [content, setContent] = useState(); + const [iframeDocument, setIframeDocument] = useState(); const { width = 0, height = 0 } = pageSizes.find((pageItem) => pageItem.name === size)?.[layout] || {}; const handleAfterPrint = useCallback(() => { onAfterPrint?.(); }, [onAfterPrint]); + const handleBeforePrint = useCallback(() => { onBeforePrint?.(); }, [onBeforePrint]); - const load = useCallback(() => { - const contentWindow = frameRef.current?.contentWindow; - if (!contentWindow) return; - const document = contentWindow.document; + function refHandler(frame: HTMLIFrameElement | null) { + if (!frame) return; - setContent(document.body); + const document = frame.contentWindow?.document; + + if (!document) { + onError?.(new Error('Print document is not available')); + return; + } transferStyles(document); appendPrintPageStyle(document, { size, layout, margin }); - - contentWindow.addEventListener('afterprint', handleAfterPrint); - contentWindow.addEventListener('beforeprint', handleBeforePrint); - - return contentWindow; - }, [handleAfterPrint, handleBeforePrint, layout, margin, size]); + setIframeDocument(document); + } useEffect(() => { - const contentWindow = frameRef.current?.contentWindow; + const contentWindow = iframeDocument?.defaultView; + if (!contentWindow) return; - if (!isFirefox) { - load(); - } + contentWindow.addEventListener('afterprint', handleAfterPrint); + contentWindow.addEventListener('beforeprint', handleBeforePrint); return () => { - if (!contentWindow) return; - contentWindow.removeEventListener('afterprint', handleAfterPrint); contentWindow.removeEventListener('beforeprint', handleBeforePrint); }; - }, [ - onBeforePrint, - onAfterPrint, - handleBeforePrint, - handleAfterPrint, - size, - layout, - margin, - load, - ]); + }, [iframeDocument, handleAfterPrint, handleBeforePrint]); return (