Spaces:
Sleeping
Sleeping
| import * as primitives from '@react-pdf/primitives'; | |
| export * from '@react-pdf/primitives'; | |
| import queue from 'queue'; | |
| import { useRef, useState, useEffect, useCallback, forwardRef } 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 && <Text>{name}</Text>}</> | |
| if (isOrphanTextInstance) { | |
| console.warn(`Invalid '${child.value}' string child outside <Text> 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.5.1"; | |
| 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, | |
| keywords, | |
| creator = 'react-pdf', | |
| producer = 'react-pdf', | |
| creationDate = new Date(), | |
| modificationDate, | |
| ownerPassword, | |
| userPassword, | |
| permissions | |
| } = props; | |
| const ctx = new PDFDocument({ | |
| compress, | |
| pdfVersion, | |
| lang: language, | |
| displayTitle: true, | |
| autoFirstPage: false, | |
| ownerPassword, | |
| userPassword, | |
| permissions, | |
| pageLayout, | |
| info: omitNils({ | |
| Title: title, | |
| Author: author, | |
| Subject: subject, | |
| Keywords: keywords, | |
| Creator: creator, | |
| Producer: producer, | |
| CreationDate: creationDate, | |
| ModificationDate: modificationDate | |
| }) | |
| }); | |
| 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 PDFDownloadLinkBase = (_ref, 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, | |
| ref: ref, | |
| ...rest, | |
| children: typeof children === 'function' ? children(instance) : children | |
| }); | |
| }; | |
| const PDFDownloadLink = /*#__PURE__*/forwardRef(PDFDownloadLinkBase); | |
| 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 | |