import * as primitives from '@react-pdf/primitives'; export * from '@react-pdf/primitives'; import queue from 'queue'; import { useRef, useState, useEffect, useCallback } from 'react'; import FontStore from '@react-pdf/font'; import renderPDF from '@react-pdf/render'; import PDFDocument from '@react-pdf/pdfkit'; import layoutDocument from '@react-pdf/layout'; import { upperFirst } from '@react-pdf/fns'; import Reconciler from '@react-pdf/reconciler'; import { jsx } from 'react/jsx-runtime'; const omitNils = object => Object.fromEntries(Object.entries(object).filter(_ref => { let [, value] = _ref; return value !== undefined; })); const createInstance = (type, _ref) => { let { style, children, ...props } = _ref; return { type, box: {}, style: style || {}, props: props || {}, children: [] }; }; const createTextInstance = text => ({ type: 'TEXT_INSTANCE', value: text }); const appendChild = (parent, child) => { const isParentText = parent.type === 'TEXT' || parent.type === 'LINK' || parent.type === 'TSPAN' || parent.type === 'NOTE'; const isChildTextInstance = child.type === 'TEXT_INSTANCE'; const isOrphanTextInstance = isChildTextInstance && !isParentText; // Ignore orphan text instances. // Caused by cases such as <>{name && {name}} if (isOrphanTextInstance) { console.warn(`Invalid '${child.value}' string child outside component`); return; } parent.children.push(child); }; const appendChildToContainer = (parentInstance, child) => { if (parentInstance.type === 'ROOT') { parentInstance.document = child; } else { appendChild(parentInstance, child); } }; const insertBefore = (parentInstance, child, beforeChild) => { var _parentInstance$child; const index = (_parentInstance$child = parentInstance.children) === null || _parentInstance$child === void 0 ? void 0 : _parentInstance$child.indexOf(beforeChild); if (index === undefined) return; if (index !== -1 && child) parentInstance.children.splice(index, 0, child); }; const removeChild = (parentInstance, child) => { var _parentInstance$child2; const index = (_parentInstance$child2 = parentInstance.children) === null || _parentInstance$child2 === void 0 ? void 0 : _parentInstance$child2.indexOf(child); if (index === undefined) return; if (index !== -1) parentInstance.children.splice(index, 1); }; const removeChildFromContainer = (parentInstance, child) => { var _parentInstance$child3; const index = (_parentInstance$child3 = parentInstance.children) === null || _parentInstance$child3 === void 0 ? void 0 : _parentInstance$child3.indexOf(child); if (index === undefined) return; if (index !== -1) parentInstance.children.splice(index, 1); }; const commitTextUpdate = (textInstance, oldText, newText) => { textInstance.value = newText; }; const commitUpdate = (instance, updatePayload, type, oldProps, newProps) => { const { style, ...props } = newProps; instance.props = props; instance.style = style; }; const createRenderer = _ref2 => { let { onChange = () => {} } = _ref2; return Reconciler({ appendChild, appendChildToContainer, commitTextUpdate, commitUpdate, createInstance, createTextInstance, insertBefore, removeChild, removeChildFromContainer, resetAfterCommit: onChange }); }; var version$1 = "4.3.0"; var packageJson = { version: version$1}; const { version } = packageJson; const fontStore = new FontStore(); // We must keep a single renderer instance, otherwise React will complain let renderer; // The pdf instance acts as an event emitter for DOM usage. // We only want to trigger an update when PDF content changes const events = {}; const pdf = initialValue => { const onChange = () => { var _events$change; const listeners = ((_events$change = events.change) === null || _events$change === void 0 ? void 0 : _events$change.slice()) || []; for (let i = 0; i < listeners.length; i += 1) listeners[i](); }; const container = { type: 'ROOT', document: null }; renderer = renderer || createRenderer({ onChange }); const mountNode = renderer.createContainer(container); const updateContainer = (doc, callback) => { renderer.updateContainer(doc, mountNode, null, callback); }; if (initialValue) updateContainer(initialValue); const render = async function (compress) { if (compress === void 0) { compress = true; } const props = container.document.props || {}; const { pdfVersion, language, pageLayout, pageMode, title, author, subject, keyboards, creator = 'react-pdf', producer = 'react-pdf', creationDate = new Date(), modificationDate } = props; const ctx = new PDFDocument({ compress, pdfVersion, lang: language, displayTitle: true, autoFirstPage: false, info: omitNils({ Title: title, Author: author, Subject: subject, Keywords: keyboards, Creator: creator, Producer: producer, CreationDate: creationDate, ModificationDate: modificationDate }) }); if (pageLayout) { ctx._root.data.PageLayout = upperFirst(pageLayout); } if (pageMode) { ctx._root.data.PageMode = upperFirst(pageMode); } const layout = await layoutDocument(container.document, fontStore); const fileStream = renderPDF(ctx, layout); return { layout, fileStream }; }; const callOnRender = function (params) { if (params === void 0) { params = {}; } if (container.document.props.onRender) { container.document.props.onRender(params); } }; const toBlob = async () => { const chunks = []; const { layout: _INTERNAL__LAYOUT__DATA_, fileStream: instance } = await render(); return new Promise((resolve, reject) => { instance.on('data', chunk => { chunks.push(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk)); }); instance.on('end', () => { try { const blob = new Blob(chunks, { type: 'application/pdf' }); callOnRender({ blob, _INTERNAL__LAYOUT__DATA_ }); resolve(blob); } catch (error) { reject(error); } }); }); }; // TODO: rename this method to `toStream` in next major release, because it return stream not a buffer const toBuffer = async () => { const { layout: _INTERNAL__LAYOUT__DATA_, fileStream } = await render(); callOnRender({ _INTERNAL__LAYOUT__DATA_ }); return fileStream; }; /* * TODO: remove this method in next major release. it is buggy * see * - https://github.com/diegomura/react-pdf/issues/2112 * - https://github.com/diegomura/react-pdf/issues/2095 */ const toString = async () => { if (process.env.NODE_ENV === 'development') { console.warn('`toString` is deprecated and will be removed in next major release'); } let result = ''; const { fileStream: instance } = await render(false); // For some reason, when rendering to string if compress=true the document is blank return new Promise((resolve, reject) => { try { instance.on('data', buffer => { result += buffer; }); instance.on('end', () => { callOnRender(); resolve(result); }); } catch (error) { reject(error); } }); }; const on = (event, listener) => { if (!events[event]) events[event] = []; events[event].push(listener); }; const removeListener = (event, listener) => { if (!events[event]) return; const idx = events[event].indexOf(listener); if (idx > -1) events[event].splice(idx, 1); }; return { on, container, toBlob, toBuffer, toString, removeListener, updateContainer }; }; const Font = fontStore; const StyleSheet = { create: s => s }; /** * PDF hook * * @param {Object} [options] hook options * @returns {[Object, Function]} pdf state and update function */ const usePDF = function (_temp) { let { document } = _temp === void 0 ? {} : _temp; const pdfInstance = useRef(null); const [state, setState] = useState({ url: null, blob: null, error: null, loading: !!document }); // Setup rendering queue useEffect(() => { const renderQueue = queue({ autostart: true, concurrency: 1 }); const queueDocumentRender = () => { setState(prev => ({ ...prev, loading: true })); renderQueue.splice(0, renderQueue.length, () => state.error ? Promise.resolve() : pdfInstance.current.toBlob()); }; const onRenderFailed = error => { console.error(error); setState(prev => ({ ...prev, loading: false, error })); }; const onRenderSuccessful = blob => { setState({ blob, error: null, loading: false, url: URL.createObjectURL(blob) }); }; pdfInstance.current = pdf(); pdfInstance.current.on('change', queueDocumentRender); if (document) { pdfInstance.current.updateContainer(document); } renderQueue.on('error', onRenderFailed); renderQueue.on('success', onRenderSuccessful); return () => { renderQueue.end(); pdfInstance.current.removeListener('change', queueDocumentRender); }; }, []); // Revoke old unused url instances useEffect(() => { return () => { if (state.url) { URL.revokeObjectURL(state.url); } }; }, [state.url]); const update = useCallback(newDoc => { pdfInstance.current.updateContainer(newDoc); }, []); return [state, update]; }; const PDFViewer = _ref => { let { title, style, className, children, innerRef, showToolbar = true, ...props } = _ref; const [instance, updateInstance] = usePDF(); useEffect(() => updateInstance(children), [children]); const src = instance.url ? `${instance.url}#toolbar=${showToolbar ? 1 : 0}` : null; return /*#__PURE__*/jsx("iframe", { src: src, title: title, ref: innerRef, style: style, className: className, ...props }); }; const BlobProvider = _ref => { let { document: doc, children } = _ref; const [instance, updateInstance] = usePDF(); useEffect(() => updateInstance(doc), [doc]); if (!doc) { console.warn('You should pass a valid document to BlobProvider'); return null; } return children(instance); }; const PDFDownloadLink = _ref => { let { fileName = 'document.pdf', document: doc, children, onClick, href, ...rest } = _ref; const [instance, updateInstance] = usePDF(); useEffect(() => updateInstance(doc), [doc]); if (!doc) { console.warn('You should pass a valid document to PDFDownloadLink'); return null; } const handleDownloadIE = () => { if (instance && window.navigator.msSaveBlob) { // IE window.navigator.msSaveBlob(instance.blob, fileName); } }; const handleClick = event => { handleDownloadIE(); if (typeof onClick === 'function') onClick(event, instance); }; return /*#__PURE__*/jsx("a", { href: instance.url, download: fileName, onClick: handleClick, ...rest, children: typeof children === 'function' ? children(instance) : children }); }; const throwEnvironmentError = name => { throw new Error(`${name} is a Node specific API. You're either using this method in a browser, or your bundler is not loading react-pdf from the appropriate web build.`); }; const renderToStream = () => { throwEnvironmentError('renderToStream'); }; const renderToBuffer = () => { throwEnvironmentError('renderToBuffer'); }; const renderToString = () => { throwEnvironmentError('renderToString'); }; const renderToFile = () => { throwEnvironmentError('renderToFile'); }; const render = () => { throwEnvironmentError('render'); }; // TODO: remove this default export in next major release because it breaks tree-shacking var index = { pdf, usePDF, Font, version, StyleSheet, PDFViewer, BlobProvider, PDFDownloadLink, renderToStream, renderToString, renderToFile, render, ...primitives }; export { BlobProvider, Font, PDFDownloadLink, PDFViewer, StyleSheet, createRenderer, index as default, pdf, render, renderToBuffer, renderToFile, renderToStream, renderToString, usePDF, version }; //# sourceMappingURL=react-pdf.browser.js.map