react-to-print
Advanced tools
Comparing version 3.0.2 to 3.0.3-beta-1
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("lib",["react"],t):"object"==typeof exports?exports.lib=t(require("react")):e.lib=t(e.react)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={155:function(t){t.exports=e}},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var s=o[e]={exports:{}};return t[e](s,s.exports,n),s.exports}n.d=function(e,t){for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};n.r(r),n.d(r,{useReactToPrint:function(){return f}});var s=n(155);function i({level:e="error",messages:t,suppressErrors:o=!1}){o||("error"===e?console.error(t):"warning"===e?console.warn(t):"debug"===e&&console.debug(t))}function l(e,t){if(t||!e){const e=document.getElementById("printWindow");e&&document.body.removeChild(e)}}function a(e,t){const{documentTitle:o,onAfterPrint:n,onPrintError:r,preserveAfterPrint:s,print:a,suppressErrors:c}=t;setTimeout((()=>{var t,d;if(e.contentWindow)if(e.contentWindow.focus(),a)a(e).then((()=>null==n?void 0:n())).then((()=>l(s))).catch((e=>{r?r("print",e):i({messages:["An error was thrown by the specified `print` function"],suppressErrors:c})}));else{if(e.contentWindow.print){const n=null!==(d=null===(t=e.contentDocument)||void 0===t?void 0:t.title)&&void 0!==d?d:"",r=e.ownerDocument.title;o&&(e.ownerDocument.title=o,e.contentDocument&&(e.contentDocument.title=o)),e.contentWindow.print(),o&&(e.ownerDocument.title=r,e.contentDocument&&(e.contentDocument.title=n))}else i({messages:["Printing for this browser is not currently possible: the browser does not have a `print` method available for iframes."],suppressErrors:c});null==n||n(),l(s)}else i({messages:["Printing failed because the `contentWindow` of the print iframe did not load. This is possibly an error with `react-to-print`. Please file an issue: https://github.com/MatthewHerbst/react-to-print/issues/"],suppressErrors:c})}),500)}function c(e){const t=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,null);let n=o.nextNode();for(;n;)t.push(n),n=o.nextNode();return t}function d(e,t,o){const n=c(e),r=c(t);if(n.length===r.length)for(let e=0;e<n.length;e++){const t=n[e],s=r[e],i=t.shadowRoot;if(null!==i){const e=s.attachShadow({mode:i.mode});e.innerHTML=i.innerHTML,d(i,e,o)}}else i({messages:["When cloning shadow root content, source and target elements have different size. `onBeforePrint` likely resolved too early.",e,t],suppressErrors:o})}const u='\n @page {\n /* Remove browser default header (title) and footer (url) */\n margin: 0;\n }\n @media print {\n body {\n /* Tell browsers to print background colors */\n color-adjust: exact; /* Firefox. This is an older version of "print-color-adjust" */\n print-color-adjust: exact; /* Firefox/Safari */\n -webkit-print-color-adjust: exact; /* Chrome/Safari/Edge/Opera */\n }\n }\n';function p(e,t,o,n){var r,s,l;const{contentNode:c,clonedContentNode:p,clonedImgNodes:h,clonedVideoNodes:f,numResourcesToLoad:g,originalCanvasNodes:m}=o,{bodyClass:b,fonts:y,ignoreGlobalStyles:v,pageStyle:w,nonce:E,suppressErrors:A,copyShadowRoots:T}=n;e.onload=null;const x=e.contentDocument||(null===(r=e.contentWindow)||void 0===r?void 0:r.document);if(x){const o=x.body.appendChild(p);T&&d(c,o,!!A),y&&((null===(s=e.contentDocument)||void 0===s?void 0:s.fonts)&&(null===(l=e.contentWindow)||void 0===l?void 0:l.FontFace)?y.forEach((o=>{const n=new FontFace(o.family,o.source,{weight:o.weight,style:o.style});e.contentDocument.fonts.add(n),n.loaded.then((()=>{t(n)})).catch((e=>{t(n,["Failed loading the font:",n,"Load error:",e])}))})):(y.forEach((e=>t(e))),i({messages:['"react-to-print" is not able to load custom fonts because the browser does not support the FontFace API but will continue attempting to print the page'],suppressErrors:A})));const n=null!=w?w:u,r=x.createElement("style");E&&(r.setAttribute("nonce",E),x.head.setAttribute("nonce",E)),r.appendChild(x.createTextNode(n)),x.head.appendChild(r),b&&x.body.classList.add(...b.split(" "));const a=x.querySelectorAll("canvas");for(let e=0;e<m.length;++e){const t=m[e],o=a[e];if(void 0===o){i({messages:["A canvas element could not be copied for printing, has it loaded? `onBeforePrint` likely resolved too early.",t],suppressErrors:A});continue}const n=o.getContext("2d");n&&n.drawImage(t,0,0)}for(let e=0;e<h.length;e++){const o=h[e],n=o.getAttribute("src");if(n){const e=new Image;e.onload=()=>t(o),e.onerror=(e,n,r,s,i)=>t(o,["Error loading <img>",o,"Error",i]),e.src=n}else t(o,['Found an <img> tag with an empty "src" attribute. This prevents pre-loading it.',o])}for(let e=0;e<f.length;e++){const o=f[e];o.preload="auto";const n=o.getAttribute("poster");if(n){const e=new Image;e.onload=()=>t(o),e.onerror=(e,r,s,i,l)=>t(o,["Error loading video poster",n,"for video",o,"Error:",l]),e.src=n}else o.readyState>=2?t(o):(o.onloadeddata=()=>t(o),o.onerror=(e,n,r,s,i)=>t(o,["Error loading video",o,"Error",i]),o.onstalled=()=>t(o,["Loading video stalled, skipping",o]))}const g="select",S=c.querySelectorAll(g),k=x.querySelectorAll(g);for(let e=0;e<S.length;e++)k[e].value=S[e].value;if(!v){const e=document.querySelectorAll("style, link[rel~='stylesheet'], link[as='style']");for(let o=0,n=e.length;o<n;++o){const n=e[o];if("style"===n.tagName.toLowerCase()){const e=x.createElement(n.tagName),t=n.sheet;if(t){let r="";try{const e=t.cssRules.length;for(let o=0;o<e;++o)"string"==typeof t.cssRules[o].cssText&&(r+=`${t.cssRules[o].cssText}\r\n`)}catch(e){i({messages:["A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/MatthewHerbst/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross `crossorigin` attribute, and setting the `Access-Control-Allow-Origin` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.",n,`Original error: ${null==e?void 0:e.message}`],level:"warning"})}e.setAttribute("id",`react-to-print-${o}`),E&&e.setAttribute("nonce",E),e.appendChild(x.createTextNode(r)),x.head.appendChild(e)}}else if(n.getAttribute("href"))if(n.hasAttribute("disabled"))i({messages:["`react-to-print` encountered a <link> tag with a `disabled` attribute and will ignore it. Note that the `disabled` attribute is deprecated, and some browsers ignore it. You should stop using it. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled. The <link> is:",n],level:"warning"}),t(n);else{const e=x.createElement(n.tagName);for(let t=0,o=n.attributes.length;t<o;++t){const o=n.attributes[t];o&&e.setAttribute(o.nodeName,o.nodeValue||"")}e.onload=()=>t(e),e.onerror=(o,n,r,s,i)=>t(e,["Failed to load",e,"Error:",i]),E&&e.setAttribute("nonce",E),x.head.appendChild(e)}else i({messages:["`react-to-print` encountered a <link> tag with an empty `href` attribute. In addition to being invalid HTML, this can cause problems in many browsers, and so the <link> was not loaded. The <link> is:",n],level:"warning"}),t(n)}}}0===g&&a(e,n)}function h(e,t,o,n){e.onload=()=>p(e,t,o,n),document.body.appendChild(e)}function f(e){const{contentRef:t,fonts:o,ignoreGlobalStyles:n,onBeforePrint:r,onPrintError:c,preserveAfterPrint:d,suppressErrors:u}=e,p=(0,s.useCallback)((s=>{l(d,!0);const p=function({contentRef:e,optionalContent:t,suppressErrors:o}){return t&&(e&&i({level:"warning",messages:['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.']}),"function"==typeof t)?t():e?e.current:void i({messages:['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'],suppressErrors:o})}({contentRef:t,optionalContent:s,suppressErrors:u});if(!p)return void i({messages:["There is nothing to print"],suppressErrors:u});const f=p.cloneNode(!0),g=document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"),m=f.querySelectorAll("img"),b=f.querySelectorAll("video"),y=o?o.length:0,v=(n?0:g.length)+m.length+b.length+y,w=[],E=[],A=function(){const e=document.createElement("iframe");return e.width=`${document.documentElement.clientWidth}px`,e.height=`${document.documentElement.clientHeight}px`,e.style.position="absolute",e.style.top=`-${document.documentElement.clientHeight+100}px`,e.style.left=`-${document.documentElement.clientWidth+100}px`,e.id="printWindow",e.srcdoc="<!DOCTYPE html>",e}(),T=(t,o)=>{w.includes(t)?i({level:"debug",messages:["Tried to mark a resource that has already been handled",t],suppressErrors:u}):(o?(i({messages:['"react-to-print" was unable to load a resource but will continue attempting to print the page',...o],suppressErrors:u}),E.push(t)):w.push(t),w.length+E.length===v&&a(A,e))},x={contentNode:p,clonedContentNode:f,clonedImgNodes:m,clonedVideoNodes:b,numResourcesToLoad:v,originalCanvasNodes:p.querySelectorAll("canvas")};r?r().then((()=>h(A,T,x,e))).catch((e=>{null==c||c("onBeforePrint",e)})):h(A,T,x,e)}),[e]);return p}return r}()})); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("lib",["react"],t):"object"==typeof exports?exports.lib=t(require("react")):e.lib=t(e.react)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={155:function(t){t.exports=e}},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var s=o[e]={exports:{}};return t[e](s,s.exports,n),s.exports}n.d=function(e,t){for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};n.r(r),n.d(r,{useReactToPrint:function(){return g}});var s=n(155);function i({level:e="error",messages:t,suppressErrors:o=!1}){o||("error"===e?console.error(t):"warning"===e?console.warn(t):console.debug(t))}function l(e,t){if(t||!e){const e=document.getElementById("printWindow");e&&document.body.removeChild(e)}}function a(e){return e instanceof Error?e:new Error("Unknown Error")}function c(e,t){const{documentTitle:o,onAfterPrint:n,onPrintError:r,preserveAfterPrint:s,print:c,suppressErrors:d}=t;setTimeout((()=>{var t,u;if(e.contentWindow)if(e.contentWindow.focus(),c)c(e).then((()=>{null==n||n()})).then((()=>{l(s)})).catch((e=>{r?r("print",a(e)):i({messages:["An error was thrown by the specified `print` function"],suppressErrors:d})}));else{if(e.contentWindow.print){const n=null!==(u=null===(t=e.contentDocument)||void 0===t?void 0:t.title)&&void 0!==u?u:"",r=e.ownerDocument.title;o&&(e.ownerDocument.title=o,e.contentDocument&&(e.contentDocument.title=o)),e.contentWindow.print(),o&&(e.ownerDocument.title=r,e.contentDocument&&(e.contentDocument.title=n))}else i({messages:["Printing for this browser is not currently possible: the browser does not have a `print` method available for iframes."],suppressErrors:d});window.addEventListener("focus",(()=>{null==n||n(),l(s)}),{once:!0})}else i({messages:["Printing failed because the `contentWindow` of the print iframe did not load. This is possibly an error with `react-to-print`. Please file an issue: https://github.com/MatthewHerbst/react-to-print/issues/"],suppressErrors:d})}),500)}function d(e){const t=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,null);let n=o.nextNode();for(;n;)t.push(n),n=o.nextNode();return t}function u(e,t,o){const n=d(e),r=d(t);if(n.length===r.length)for(let e=0;e<n.length;e++){const t=n[e],s=r[e],i=t.shadowRoot;if(null!==i){const e=s.attachShadow({mode:i.mode});e.innerHTML=i.innerHTML,u(i,e,o)}}else i({messages:["When cloning shadow root content, source and target elements have different size. `onBeforePrint` likely resolved too early.",e,t],suppressErrors:o})}const p='\n @page {\n /* Remove browser default header (title) and footer (url) */\n margin: 0;\n }\n @media print {\n body {\n /* Tell browsers to print background colors */\n color-adjust: exact; /* Firefox. This is an older version of "print-color-adjust" */\n print-color-adjust: exact; /* Firefox/Safari */\n -webkit-print-color-adjust: exact; /* Chrome/Safari/Edge/Opera */\n }\n }\n';function h(e,t,o,n){var r,s,l,d,h;const{contentNode:f,clonedContentNode:g,clonedImgNodes:m,clonedVideoNodes:b,numResourcesToLoad:y,originalCanvasNodes:v}=o,{bodyClass:w,fonts:E,ignoreGlobalStyles:A,pageStyle:T,nonce:x,suppressErrors:k,copyShadowRoots:S}=n;e.onload=null;const N=null!==(r=e.contentDocument)&&void 0!==r?r:null===(s=e.contentWindow)||void 0===s?void 0:s.document;if(N){const o=N.body.appendChild(g);S&&u(f,o,!!k),E&&((null===(l=e.contentDocument)||void 0===l?void 0:l.fonts)&&(null===(d=e.contentWindow)||void 0===d?void 0:d.FontFace)?E.forEach((o=>{const n=new FontFace(o.family,o.source,{weight:o.weight,style:o.style});e.contentDocument.fonts.add(n),n.loaded.then((()=>{t(n)})).catch((e=>{t(n,["Failed loading the font:",n,"Load error:",a(e)])}))})):(E.forEach((e=>{t(e)})),i({messages:['"react-to-print" is not able to load custom fonts because the browser does not support the FontFace API but will continue attempting to print the page'],suppressErrors:k})));const n=null!=T?T:p,r=N.createElement("style");x&&(r.setAttribute("nonce",x),N.head.setAttribute("nonce",x)),r.appendChild(N.createTextNode(n)),N.head.appendChild(r),w&&N.body.classList.add(...w.split(" "));const s=N.querySelectorAll("canvas");for(let e=0;e<v.length;++e){const t=v[e],o=s[e];if(void 0===o){i({messages:["A canvas element could not be copied for printing, has it loaded? `onBeforePrint` likely resolved too early.",t],suppressErrors:k});continue}const n=o.getContext("2d");n&&n.drawImage(t,0,0)}for(let e=0;e<m.length;e++){const o=m[e],n=o.getAttribute("src");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,n,r,s,i)=>{t(o,["Error loading <img>",o,"Error",i])},e.src=n}else t(o,['Found an <img> tag with an empty "src" attribute. This prevents pre-loading it.',o])}for(let e=0;e<b.length;e++){const o=b[e];o.preload="auto";const n=o.getAttribute("poster");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,r,s,i,l)=>{t(o,["Error loading video poster",n,"for video",o,"Error:",l])},e.src=n}else o.readyState>=2?t(o):(o.onloadeddata=()=>{t(o)},o.onerror=(e,n,r,s,i)=>{t(o,["Error loading video",o,"Error",i])},o.onstalled=()=>{t(o,["Loading video stalled, skipping",o])})}const c="select",y=f.querySelectorAll(c),C=N.querySelectorAll(c);for(let e=0;e<y.length;e++)C[e].value=y[e].value;if(!A){const e=document.querySelectorAll("style, link[rel~='stylesheet'], link[as='style']");for(let o=0,n=e.length;o<n;++o){const n=e[o];if("style"===n.tagName.toLowerCase()){const e=N.createElement(n.tagName),t=n.sheet;if(t){let r="";try{const e=t.cssRules.length;for(let o=0;o<e;++o)"string"==typeof t.cssRules[o].cssText&&(r+=`${t.cssRules[o].cssText}\r\n`)}catch(e){i({messages:["A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/MatthewHerbst/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross `crossorigin` attribute, and setting the `Access-Control-Allow-Origin` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.",n,`Original error: ${a(e).message}`],level:"warning"})}e.setAttribute("id",`react-to-print-${o}`),x&&e.setAttribute("nonce",x),e.appendChild(N.createTextNode(r)),N.head.appendChild(e)}}else if(n.getAttribute("href"))if(n.hasAttribute("disabled"))i({messages:["`react-to-print` encountered a <link> tag with a `disabled` attribute and will ignore it. Note that the `disabled` attribute is deprecated, and some browsers ignore it. You should stop using it. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled. The <link> is:",n],level:"warning"}),t(n);else{const e=N.createElement(n.tagName);for(let t=0,o=n.attributes.length;t<o;++t){const o=n.attributes[t];o&&e.setAttribute(o.nodeName,null!==(h=o.nodeValue)&&void 0!==h?h:"")}e.onload=()=>{t(e)},e.onerror=(o,n,r,s,i)=>{t(e,["Failed to load",e,"Error:",i])},x&&e.setAttribute("nonce",x),N.head.appendChild(e)}else i({messages:["`react-to-print` encountered a <link> tag with an empty `href` attribute. In addition to being invalid HTML, this can cause problems in many browsers, and so the <link> was not loaded. The <link> is:",n],level:"warning"}),t(n)}}}0===y&&c(e,n)}function f(e,t,o,n){e.onload=()=>{h(e,t,o,n)},document.body.appendChild(e)}function g(e){const{contentRef:t,fonts:o,ignoreGlobalStyles:n,onBeforePrint:r,onPrintError:d,preserveAfterPrint:u,suppressErrors:p}=e,h=(0,s.useCallback)((s=>{l(u,!0);const h=function({contentRef:e,optionalContent:t,suppressErrors:o}){return t&&(e&&i({level:"warning",messages:['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.']}),"function"==typeof t)?t():e?e.current:void i({messages:['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'],suppressErrors:o})}({contentRef:t,optionalContent:s,suppressErrors:p});if(!h)return void i({messages:["There is nothing to print"],suppressErrors:p});const g=h.cloneNode(!0),m=document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"),b=g.querySelectorAll("img"),y=g.querySelectorAll("video"),v=o?o.length:0,w=(n?0:m.length)+b.length+y.length+v,E=[],A=[],T=function(){const e=document.createElement("iframe");return e.width=`${document.documentElement.clientWidth}px`,e.height=`${document.documentElement.clientHeight}px`,e.style.position="absolute",e.style.top=`-${document.documentElement.clientHeight+100}px`,e.style.left=`-${document.documentElement.clientWidth+100}px`,e.id="printWindow",e.srcdoc="<!DOCTYPE html>",e}(),x=(t,o)=>{E.includes(t)?i({level:"debug",messages:["Tried to mark a resource that has already been handled",t],suppressErrors:p}):(o?(i({messages:['"react-to-print" was unable to load a resource but will continue attempting to print the page',...o],suppressErrors:p}),A.push(t)):E.push(t),E.length+A.length===w&&c(T,e))},k={contentNode:h,clonedContentNode:g,clonedImgNodes:b,clonedVideoNodes:y,numResourcesToLoad:w,originalCanvasNodes:h.querySelectorAll("canvas")};r?r().then((()=>{f(T,x,k,e)})).catch((e=>{null==d||d("onBeforePrint",a(e))})):f(T,x,k,e)}),[e]);return h}return r}()})); |
@@ -1,2 +0,2 @@ | ||
export type Font = { | ||
export interface Font { | ||
family: string; | ||
@@ -6,2 +6,2 @@ source: string; | ||
style?: string; | ||
}; | ||
} |
import { ContentNode } from "../types/ContentNode"; | ||
import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions"; | ||
import { UseReactToPrintHookContent } from "../types/UseReactToPrintHookContent"; | ||
type GetContentNodesArgs = { | ||
interface GetContentNodesArgs { | ||
contentRef?: UseReactToPrintOptions["contentRef"]; | ||
optionalContent?: UseReactToPrintHookContent; | ||
suppressErrors?: boolean; | ||
}; | ||
} | ||
export declare function getContentNode({ contentRef, optionalContent, suppressErrors }: GetContentNodesArgs): ContentNode; | ||
export {}; |
import { Font } from "../types/font"; | ||
import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions"; | ||
export type HandlePrintWindowOnLoadData = { | ||
export interface HandlePrintWindowOnLoadData { | ||
contentNode: Node; | ||
@@ -10,5 +10,5 @@ clonedContentNode: Node; | ||
originalCanvasNodes: never[] | NodeListOf<HTMLCanvasElement>; | ||
}; | ||
} | ||
type MarkLoaded = (resource: Element | Font | FontFace, errorMessages?: unknown[]) => void; | ||
export declare function handlePrintWindowOnLoad(printWindow: HTMLIFrameElement, markLoaded: MarkLoaded, data: HandlePrintWindowOnLoadData, options: UseReactToPrintOptions): void; | ||
export {}; |
@@ -1,7 +0,7 @@ | ||
type LogMessagesArgs = { | ||
interface LogMessagesArgs { | ||
level?: 'error' | 'warning' | 'debug'; | ||
messages: unknown[]; | ||
suppressErrors?: boolean; | ||
}; | ||
} | ||
export declare function logMessages({ level, messages, suppressErrors }: LogMessagesArgs): void; | ||
export {}; |
{ | ||
"name": "react-to-print", | ||
"version": "3.0.2", | ||
"version": "3.0.3-beta-1", | ||
"description": "Print React components in the browser", | ||
@@ -13,3 +13,3 @@ "main": "lib/index.js", | ||
"lint": "eslint ./src", | ||
"prepare": "npm run build && husky install", | ||
"prepare": "npm run lint && npm run build && husky install", | ||
"start": "NODE_ENV=development webpack serve" | ||
@@ -40,13 +40,13 @@ }, | ||
"devDependencies": { | ||
"@types/react": "^18.3.10", | ||
"@types/react-dom": "^18.3.0", | ||
"@typescript-eslint/eslint-plugin": "^8.7.0", | ||
"@typescript-eslint/parser": "^8.7.0", | ||
"acorn": "^8.12.1", | ||
"@eslint/js": "^9.16.0", | ||
"@types/react": "^18.3.12", | ||
"@types/react-dom": "^18.3.1", | ||
"acorn": "^8.14.0", | ||
"clean-webpack-plugin": "^4.0.0", | ||
"copy-webpack-plugin": "^12.0.2", | ||
"css-loader": "^7.1.2", | ||
"eslint": "^8.56.0", | ||
"html-webpack-plugin": "^5.6.0", | ||
"husky": "^9.1.6", | ||
"eslint": "^9.16.0", | ||
"eslint-plugin-react": "^7.37.2", | ||
"html-webpack-plugin": "^5.6.3", | ||
"husky": "^9.1.7", | ||
"lint-staged": "^15.2.10", | ||
@@ -58,6 +58,7 @@ "react": "^18.3.1", | ||
"ts-loader": "^9.5.1", | ||
"tslib": "^2.7.0", | ||
"typescript": "^5.6.2", | ||
"tslib": "^2.8.1", | ||
"typescript": "^5.7.2", | ||
"typescript-eslint": "^8.16.0", | ||
"url-loader": "^4.1.1", | ||
"webpack": "^5.95.0", | ||
"webpack": "^5.96.1", | ||
"webpack-cli": "^5.1.4", | ||
@@ -64,0 +65,0 @@ "webpack-dev-server": "^5.1.0" |
@@ -12,2 +12,4 @@ <p align="center"> | ||
`npm install --save react-to-print` | ||
## Demo | ||
@@ -17,11 +19,8 @@ | ||
## Install | ||
## Usage | ||
`npm install --save react-to-print` | ||
```tsx | ||
import { useReactToPrint } from "react-to-print"; | ||
import { useRef } from "react"; | ||
## API | ||
### Usage | ||
```tsx | ||
const contentRef = useRef<HTMLDivElement>(null); | ||
@@ -32,3 +31,3 @@ const reactToPrintFn = useReactToPrint({ contentRef }); | ||
<div> | ||
<button onClick={reactToPrintFn}>Print</button> | ||
<button onClick={() => reactToPrintFn()}>Print</button> | ||
<div ref={contentRef}>Content to print</div> | ||
@@ -39,23 +38,23 @@ </div> | ||
### Options | ||
It is also possible to lazy set the ref if your content being printed is dynamic. See the [`LazyContent`](https://github.com/MatthewHerbst/react-to-print/blob/master/examples/LazyContent/index.tsx) example for more. This can also be useful for setting the ref in non-React code, such as util functions. | ||
## API | ||
| Option | Type | Description | | ||
| :-------------------: | :------- | :---------------------------------------------------------------------------------------------------------------------------------- | | ||
| **`bodyClass?`** | `string` | One or more class names to pass to the print window, separated by spaces | | ||
| **`contentRef?`** | `React.RefObject<Element \| Text>` | The ref pointing to the content to be printed. Alternatively, pass the ref directly to the callback returned by `useReactToPrint` | | ||
| **`documentTitle?`** | `string` | Set the title for printing when saving as a file. Ignored when passing a custom `print` option | | ||
| **`fonts?`** | `{ family: string, source: string; weight?: string; style?: string; }[]` | A list of fonts to load into the printing iframe. This is useful if you are using custom fonts | | ||
| **`ignoreGlobalStyles?`** | `boolean` | Ignore all `<style>` and `<link type="stylesheet" />` tags from `<head>` | | ||
| **`nonce?`** | `string` | Set the [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) attribute for allow-listing script and style elements for Content Security Policy (CSP) | | ||
| **`onAfterPrint?`** | `() => void` | Callback function that triggers after the print dialog is closed _regardless of if the user selected to print or cancel_ | | ||
| **`onBeforePrint?`** | `() => Promise<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 | | ||
| **`onPrintError?`** | `(errorLocation: 'onBeforePrint' \| 'print', error: Error) => void` | Called if there is a printing error serious enough that printing cannot continue. Currently limited to Promise rejections in `onBeforePrint`, and `print`. Use this to attempt to print again. `errorLocation` will tell you where the Promise was rejected | | ||
| **`pageStyle?`** | `string` | `react-to-print` sets some basic styles to help improve page printing, notably, removing the header and footer that most browsers add. Use this to override these styles and provide your own | | ||
| **`preserveAfterPrint?`** | `boolean` | Preserve the print iframe after printing. This can be useful for debugging by inspecting the print iframe | | ||
| **`print?`** | `(iframe: HTMLIFrameElement) => Promise<void>` | If passed, this function will be used instead of `window.print` to print the content. Use this to print in non-browser environments such as Electron | | ||
| **`suppressErrors?`** | `boolean` | When passed, prevents `console` logging of errors | | ||
| **`copyShadowRoots?`** | `boolean` | When passed, shadow root content will be copied to print window. WARNING: Use with care if you print large documents. TreeWalker's are used to traverse source and target documents. | | ||
| **`bodyClass`** | `string` | One or more class names to pass to the print window, separated by spaces | | ||
| **`contentRef`** | `React.RefObject<Element \| Text>` | The ref pointing to the content to be printed. Alternatively, pass the ref directly to the callback returned by `useReactToPrint` | | ||
| **`copyShadowRoots`** | `boolean` | Copy shadow root content into the print window. Warning: Use with care if you print large documents as traversing these can be slow. | | ||
| **`documentTitle`** | `string` | Set the title for printing when saving as a file | | ||
| **`fonts`** | `{ family: string, source: string; weight?: string; style?: string; }[]` | A list of fonts to load into the printing iframe. This is useful if you are using custom fonts | | ||
| **`ignoreGlobalStyles`** | `boolean` | Ignore all `<style>` and `<link type="stylesheet" />` tags | | ||
| **`nonce`** | `string` | Set the [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) attribute for allow-listing script and style elements for Content Security Policy (CSP) | | ||
| **`onAfterPrint`** | `() => void` | Callback function that triggers after the print dialog is closed _regardless of if the user selected to print or cancel_ | | ||
| **`onBeforePrint`** | `() => Promise<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 | | ||
| **`onPrintError`** | `(errorLocation: 'onBeforePrint' \| 'print', error: Error) => void` | Called if there is a printing error serious enough that printing cannot continue. Currently limited to Promise rejections in `onBeforePrint`, and `print`. | | ||
| **`pageStyle`** | `string` | `react-to-print` sets some basic styles to help improve page printing, notably, removing the header and footer that most browsers add. Use this to override these styles and provide your own | | ||
| **`preserveAfterPrint`** | `boolean` | Preserve the print iframe after printing. This can be useful for debugging by inspecting the print iframe | | ||
| **`print`** | `(iframe: HTMLIFrameElement) => Promise<void>` | If passed, this function will be used instead of `window.print` to print the content. Use this to print in non-browser environments such as Electron | | ||
| **`suppressErrors`** | `boolean` | When passed, prevents `console` logging of errors | | ||
The hook returns a function that will initiate the print process when called. This function can also be optionally passed the `content` when called, allowing for its use in conditional rendering logic (where hooks are not allowed) and/or in non-React code such as a util function. See the repo examples for more. | ||
## Compatibility | ||
@@ -103,5 +102,31 @@ | ||
### How can content be hidden/shown during printing? | ||
The simplest way to hide or show content during printing is to use a [CSS Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries). | ||
```css | ||
.printContent { | ||
display: none; | ||
@media print { | ||
display: block; | ||
} | ||
} | ||
``` | ||
```tsx | ||
const contentRef = useRef<HTMLDivElement>(null); | ||
const reactToPrintFn = useReactToPrint({ contentRef }); | ||
return ( | ||
<div> | ||
<button onClick={reactToPrintFn}>Print</button> | ||
<div className="printContent" ref={contentRef}>Content to print</div> | ||
</div> | ||
); | ||
``` | ||
### Can `react-to-print` be used to download a PDF without using the Print Preview window? | ||
No. We aren't able to print a PDF as we lose control once the print preview window opens. However, it should be very easy to use `react-to-print` to take the information you need and pass it to a library that can generate a PDF. | ||
Not directly. We aren't able to print a PDF as we lose control once the print preview window opens. However, it is possible to use `react-to-print` to gather the content you want to print and pass it to a library that can generate a PDF. | ||
@@ -178,3 +203,3 @@ ```tsx | ||
const [isPrinting, setIsPrinting] = useState(false); | ||
const printRef = useRef(null); | ||
const contentRef = useRef(null); | ||
@@ -193,3 +218,3 @@ // We store the resolve Promise being used in `onBeforePrint` here | ||
const handlePrint = useReactToPrint({ | ||
content: () => printRef.current, | ||
contentRef, | ||
onBeforePrint: () => { | ||
@@ -209,3 +234,3 @@ return new Promise((resolve) => { | ||
Note: for Class components, just pass the `resolve` to the callback for `this.setState`: `this.setState({ isPrinting: false }, resolve)` | ||
Note: for Class components, pass the Promise `resolve` to the callback for `this.setState`: `this.setState({ isPrinting: false }, resolve)` | ||
@@ -436,6 +461,10 @@ ### Changing print settings in the print dialog | ||
*NOTE*: The library is tested and built locally using Node >= 20. | ||
*NOTE*: The library is built and tested locally using Node ^20. | ||
## Related | ||
- Clone the repo | ||
- `npm ci` | ||
- `npm start` | ||
* [vue-to-print](https://github.com/siaikin/vue-to-print): vue3 version of react-to-print | ||
## Related Packages | ||
- [vue-to-print](https://github.com/siaikin/vue-to-print): vue3 version of react-to-print |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38817
20
76
462
24
2