├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.js ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── config ├── tsup.config.ts ├── tsup.frameworks.config.ts └── turbowatch.config.ts ├── eslint.config.js ├── examples └── react-mui │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── application.tsx │ ├── main.tsx │ └── webworker.ts │ ├── tsconfig.json │ └── vite.config.ts ├── package.json ├── packages ├── core │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── base │ │ │ │ └── base-plugin.ts │ │ │ ├── index.ts │ │ │ ├── registry │ │ │ │ └── plugin-registry.ts │ │ │ ├── store │ │ │ │ ├── actions.ts │ │ │ │ ├── index.ts │ │ │ │ ├── initial-state.ts │ │ │ │ ├── plugin-store.ts │ │ │ │ ├── reducer.ts │ │ │ │ ├── selectors.ts │ │ │ │ ├── store.ts │ │ │ │ └── types.ts │ │ │ ├── types │ │ │ │ ├── errors.ts │ │ │ │ └── plugin.ts │ │ │ └── utils │ │ │ │ ├── dependency-resolver.ts │ │ │ │ ├── event-control.ts │ │ │ │ ├── eventing.ts │ │ │ │ ├── math.ts │ │ │ │ └── plugin-helpers.ts │ │ ├── preact │ │ │ ├── README.md │ │ │ ├── components │ │ │ │ ├── embed-pdf.tsx │ │ │ │ └── index.ts │ │ │ ├── context.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-capability.ts │ │ │ │ ├── use-plugin.ts │ │ │ │ ├── use-registry.ts │ │ │ │ └── use-store-state.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── README.md │ │ │ ├── components │ │ │ ├── embed-pdf.tsx │ │ │ └── index.ts │ │ │ ├── context.ts │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-capability.ts │ │ │ ├── use-plugin.ts │ │ │ ├── use-registry.ts │ │ │ └── use-store-state.ts │ │ │ └── index.ts │ └── tsconfig.json ├── engines │ ├── LICENSE │ ├── README.md │ ├── demo │ │ ├── index.html │ │ ├── main.ts │ │ ├── styles.css │ │ ├── url.d.ts │ │ └── webworker.ts │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── mock │ │ │ └── index.ts │ │ ├── pdfium-engine.ts │ │ ├── pdfium │ │ │ ├── cache.ts │ │ │ ├── engine.test.ts │ │ │ ├── engine.ts │ │ │ ├── helper.test.ts │ │ │ ├── helper.ts │ │ │ ├── index.ts │ │ │ └── runner.ts │ │ ├── webworker-engine.ts │ │ └── webworker │ │ │ ├── engine.ts │ │ │ ├── index.ts │ │ │ └── runner.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── models │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── geometry.test.ts │ │ ├── geometry.ts │ │ ├── index.ts │ │ ├── logger.test.ts │ │ ├── logger.ts │ │ ├── pdf.ts │ │ ├── task.test.ts │ │ └── task.ts │ └── tsconfig.json ├── pdfium │ ├── .gitignore │ ├── Dockerfile │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── build │ │ ├── code │ │ │ └── cpp │ │ │ │ ├── filewriter.cpp │ │ │ │ ├── filewriter.h │ │ │ │ └── main.cpp │ │ ├── compile.sh │ │ └── patch │ │ │ ├── BUILD.gn │ │ │ ├── build │ │ │ ├── config │ │ │ │ └── BUILDCONFIG.gn │ │ │ └── toolchain │ │ │ │ └── wasm │ │ │ │ └── BUILD.gn │ │ │ └── core │ │ │ └── fxge │ │ │ └── BUILD.gn │ ├── package.json │ ├── scripts │ │ ├── exported-functions.js │ │ ├── exported-runtime-methods.js │ │ ├── generate-exported-functions.js │ │ └── generate-exported-runtime-methods.js │ ├── src │ │ ├── functions.ts │ │ ├── index.ts │ │ ├── pdfium.d.ts │ │ ├── pdfium.js │ │ ├── pdfium.wasm │ │ └── runtime.ts │ └── tsconfig.json ├── plugin-annotation │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── annotation-plugin.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── selectors.ts │ │ │ └── types.ts │ │ └── preact │ │ │ ├── components │ │ │ ├── annotation-layer.tsx │ │ │ ├── annotations │ │ │ │ └── highlight.tsx │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-annotation.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── plugin-attachment │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── attachment-plugin.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ └── types.ts │ │ └── preact │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-attachment.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── plugin-bookmark │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── bookmark-plugin.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ └── types.ts │ │ └── preact │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-bookmark.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── plugin-download │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── download-plugin.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── download.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-download.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── component │ │ │ ├── download.tsx │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-download.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-fullscreen │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── fullscreen-plugin.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── fullscreen.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-fullscreen.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── fullscreen.tsx │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-fullscreen.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-interaction-manager │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── helper.ts │ │ │ ├── index.ts │ │ │ ├── interaction-manager-plugin.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── global-pointer-provider.tsx │ │ │ │ ├── index.ts │ │ │ │ └── page-pointer-provider.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-interaction-manager.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ ├── react │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-interaction-manager.ts │ │ │ └── index.ts │ │ └── shared │ │ │ └── utils.ts │ └── tsconfig.json ├── plugin-loader │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── loader-plugin.ts │ │ │ ├── loader │ │ │ │ ├── document-loader.ts │ │ │ │ ├── index.ts │ │ │ │ └── strategies │ │ │ │ │ ├── buffer-strategy.ts │ │ │ │ │ ├── loading-strategy.ts │ │ │ │ │ └── url-strategy.ts │ │ │ ├── manifest.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── file-picker.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-loader.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── file-picker.tsx │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-loader.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-pan │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── pan-plugin.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ └── pan-mode.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-pan.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-pan.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-print │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── print-plugin.ts │ │ │ └── types.ts │ │ └── preact │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── print.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-print-action.ts │ │ │ └── use-print.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── plugin-render │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── render-plugin.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ └── render-layer.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-render.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── render-layer.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-render.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-rotate │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── rotate-plugin.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ └── rotate.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-rotate.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── rotate.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-rotate.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-scroll │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── scroll-plugin.ts │ │ │ ├── selectors.ts │ │ │ ├── strategies │ │ │ │ ├── base-strategy.ts │ │ │ │ ├── horizontal-strategy.ts │ │ │ │ └── vertical-strategy.ts │ │ │ ├── types.ts │ │ │ └── types │ │ │ │ └── virtual-item.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ └── scroller.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-scroll.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── scroller.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-scroll.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-search │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── search-plugin.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ └── search-layer.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-search.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── search-layer.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-search.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-selection │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── selection-plugin.ts │ │ │ ├── selectors.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ └── preact │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── selection-layer.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-selection.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── plugin-spread │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── spread-plugin.ts │ │ │ └── types.ts │ │ ├── preact │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-spread.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-spread.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-thumbnail │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── thumbnail-plugin.ts │ │ │ └── types.ts │ │ └── preact │ │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── thumbnail-img.tsx │ │ │ └── thumbnails-pane.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-thumbnail.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── plugin-tiling │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── tiling-plugin.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ ├── tile-img.tsx │ │ │ │ └── tiling-layer.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-tiling.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── tile-img.tsx │ │ │ └── tiling-layer.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-tiling.ts │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-ui │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── icons │ │ │ │ ├── icon-manager.ts │ │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── menu │ │ │ │ ├── menu-manager.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── reducer.ts │ │ │ ├── types.ts │ │ │ ├── ui-component.ts │ │ │ ├── ui-plugin.ts │ │ │ └── utils.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── component-wrapper.tsx │ │ │ │ ├── index.ts │ │ │ │ └── plugin-ui-provider.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-icon.ts │ │ │ │ └── use-ui.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ └── index.ts │ └── tsconfig.json ├── plugin-viewport │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── reducer.ts │ │ │ ├── types.ts │ │ │ └── viewport-plugin.ts │ │ ├── preact │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ └── viewport.tsx │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-viewport-ref.ts │ │ │ │ └── use-viewport.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.preact.json │ │ └── react │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── viewport.tsx │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-viewport-ref.ts │ │ │ └── use-viewport.ts │ │ │ └── index.ts │ └── tsconfig.json └── plugin-zoom │ ├── package.json │ ├── src │ ├── index.ts │ ├── lib │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── manifest.ts │ │ ├── reducer.ts │ │ ├── types.ts │ │ └── zoom-plugin.ts │ └── preact │ │ ├── components │ │ ├── index.ts │ │ └── pinch-wrapper.tsx │ │ ├── hooks │ │ ├── index.ts │ │ ├── use-pinch-zoom.ts │ │ └── use-zoom.ts │ │ ├── index.ts │ │ └── tsconfig.preact.json │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── snippet ├── .babelrc ├── .gitignore ├── README.md ├── demo-pdf │ ├── demo.pdf │ └── ebook.pdf ├── package.json ├── postcss.config.cjs ├── rollup.config.js ├── src │ ├── components │ │ ├── app.tsx │ │ ├── loader-local.ts │ │ ├── loader-worker.ts │ │ ├── renderers.tsx │ │ ├── toolbar.tsx │ │ ├── ui │ │ │ ├── button.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── dialog.tsx │ │ │ ├── dropdown.tsx │ │ │ ├── icon.tsx │ │ │ ├── loading-indicator.tsx │ │ │ └── tooltip.tsx │ │ ├── utils.ts │ │ └── webworker.ts │ ├── embedpdf.ts │ ├── global.d.ts │ ├── hooks │ │ ├── use-debounce.ts │ │ └── use-swipe-gesture.ts │ ├── index.html │ ├── styles │ │ └── index.css │ └── web-components │ │ └── container.tsx ├── tools │ └── build-worker.js └── tsconfig.json ├── turbo.json ├── types └── assets.d.ts └── website ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── mdx-components.tsx ├── next.config.ts ├── package.json ├── postcss.config.js ├── prettier.config.js ├── public ├── apple-touch-icon.png ├── demo.pdf ├── demo_protected.pdf ├── ebook.pdf ├── favicon-96x96.png ├── favicon.ico ├── favicon.svg ├── logo-192.png ├── profile.jpeg ├── site.webmanifest ├── wasm │ ├── pdfium.js │ └── pdfium.wasm ├── web-app-manifest-192x192.png └── web-app-manifest-512x512.png ├── src ├── app │ ├── [[...mdxPath]] │ │ └── page.tsx │ └── layout.tsx ├── components │ ├── blog.tsx │ ├── breadcrumb.tsx │ ├── button.tsx │ ├── callout.tsx │ ├── collapse.tsx │ ├── documentation-overview.tsx │ ├── homepage.tsx │ ├── icons │ │ ├── javascript.tsx │ │ ├── scribble.tsx │ │ ├── scribble2.tsx │ │ ├── scribble3.tsx │ │ └── typescript.tsx │ ├── logo.tsx │ ├── mdx-components │ │ ├── anchor.tsx │ │ ├── code.tsx │ │ ├── heading-anchor.client.tsx │ │ ├── heading.tsx │ │ ├── image.tsx │ │ ├── index.tsx │ │ ├── link.tsx │ │ ├── pre │ │ │ ├── copy-to-clipboard.tsx │ │ │ ├── index.tsx │ │ │ └── toggle-word-wrap-button.tsx │ │ ├── table.tsx │ │ └── wrapper.client.tsx │ ├── navbar.tsx │ ├── pagination.tsx │ ├── pdf-viewer │ │ └── index.tsx │ ├── preview.tsx │ ├── sidebar.tsx │ ├── steps.tsx │ ├── stores │ │ ├── active-anchor.ts │ │ ├── config.tsx │ │ ├── focused-route.ts │ │ ├── index.ts │ │ ├── menu.ts │ │ └── toc.ts │ ├── tabs │ │ ├── index.client.tsx │ │ └── index.tsx │ ├── tools-overview.tsx │ └── tools │ │ └── pdf-merge │ │ ├── document-view.tsx │ │ ├── index.ts │ │ ├── merge-result.tsx │ │ ├── merge-view.tsx │ │ ├── pdf-engine.ts │ │ ├── pdf-merge-tool.tsx │ │ ├── sortable-page.tsx │ │ ├── types.ts │ │ └── virtual-scroller.tsx ├── content │ ├── _meta.ts │ ├── blog.mdx │ ├── blog │ │ └── test-blog.mdx │ ├── docs │ │ ├── _meta.ts │ │ ├── index.mdx │ │ ├── pdfium │ │ │ ├── _meta.ts │ │ │ ├── code-examples │ │ │ │ ├── extract-text-from-pdf.preview.tsx │ │ │ │ ├── extract-text-from-pdf.ts │ │ │ │ ├── get-last-error-example.preview.tsx │ │ │ │ ├── get-last-error-example.ts │ │ │ │ ├── get-pdf-page-count.preview.tsx │ │ │ │ ├── get-pdf-page-count.ts │ │ │ │ ├── initialize-pdfium.ts │ │ │ │ ├── render-page-to-canvas.preview.tsx │ │ │ │ └── render-page-to-canvas.ts │ │ │ ├── examples │ │ │ │ ├── _meta.ts │ │ │ │ ├── extract-text-from-pdf.mdx │ │ │ │ └── render-page-to-canvas.mdx │ │ │ ├── functions │ │ │ │ ├── FPDFText_ClosePage.mdx │ │ │ │ ├── FPDFText_CountChars.mdx │ │ │ │ ├── FPDFText_GetText.mdx │ │ │ │ ├── FPDFText_LoadPage.mdx │ │ │ │ ├── FPDF_CloseDocument.mdx │ │ │ │ ├── FPDF_ClosePage.mdx │ │ │ │ ├── FPDF_GetLastError.mdx │ │ │ │ ├── FPDF_GetPageCount.mdx │ │ │ │ ├── FPDF_LoadCustomDocument.mdx │ │ │ │ ├── FPDF_LoadMemDocument.mdx │ │ │ │ ├── FPDF_LoadPage.mdx │ │ │ │ ├── PDFiumExt_Init.mdx │ │ │ │ └── _meta.ts │ │ │ ├── getting-started.mdx │ │ │ └── introduction.mdx │ │ └── snippet │ │ │ ├── _meta.ts │ │ │ └── introduction.mdx │ ├── index.mdx │ ├── tools │ │ ├── _meta.ts │ │ ├── index.mdx │ │ └── pdf-merge.mdx │ └── viewer.mdx ├── styles │ └── tailwind.css └── types │ └── wasm.d.ts ├── tailwind.config.ts ├── tools └── copy-wasm.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules 3 | **/node_modules/ 4 | **/dist 5 | **/.turbo 6 | config/tsup.config.bundled* 7 | config/tsup.frameworks.config.bundled* 8 | .next 9 | .cursor 10 | .DS_Store -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | build 4 | coverage 5 | *.log 6 | *.lock 7 | *.pdf 8 | *.wasm 9 | public -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | module.exports = { 3 | semi: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | printWidth: 100, 7 | tabWidth: 2, 8 | useTabs: false, 9 | bracketSpacing: true, 10 | arrowParens: 'always', 11 | jsxSingleQuote: false, 12 | endOfLine: 'lf', 13 | plugins: ['prettier-plugin-tailwindcss'], 14 | overrides: [ 15 | { 16 | files: '*.md', 17 | options: { 18 | printWidth: 80, 19 | }, 20 | }, 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 CloudPDF 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import fs from 'node:fs'; 3 | import { defineConfig } from 'tsup'; 4 | 5 | const PACKAGE_ROOT_PATH = process.cwd(); 6 | const SRC_PATH = path.join(PACKAGE_ROOT_PATH, 'src'); 7 | 8 | export default defineConfig({ 9 | entry: ['src/index.ts'], 10 | dts: true, // Generate declaration files 11 | format: ['cjs', 'esm'], 12 | sourcemap: true, 13 | clean: true, // Clean the dist folder before building 14 | outDir: 'dist', 15 | tsconfig: path.join(PACKAGE_ROOT_PATH, 'tsconfig.json'), 16 | async onSuccess() { 17 | // Copy WASM files if they exist 18 | const wasmFile = path.join(SRC_PATH, 'pdfium.wasm'); 19 | if (fs.existsSync(wasmFile)) { 20 | await fs.promises.copyFile(wasmFile, path.join(PACKAGE_ROOT_PATH, 'dist', 'pdfium.wasm')); 21 | } 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /examples/react-mui/README.md: -------------------------------------------------------------------------------- 1 | # Work in progress. This example is not finished yet 2 | -------------------------------------------------------------------------------- /examples/react-mui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | EmbedPDF + React + MUI 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 22 | 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/react-mui/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { ThemeProvider, createTheme } from '@mui/material/styles'; 4 | import CssBaseline from '@mui/material/CssBaseline'; 5 | import { WebWorkerEngine } from '@embedpdf/engines/worker'; 6 | 7 | import App from './application'; 8 | 9 | const theme = createTheme({ 10 | palette: { 11 | mode: 'light', 12 | primary: { 13 | main: '#1976d2', 14 | }, 15 | secondary: { 16 | main: '#dc004e', 17 | }, 18 | }, 19 | }); 20 | 21 | async function run() { 22 | const worker = new Worker(new URL('./webworker.ts', import.meta.url), { type: 'module' }); 23 | const engine = new WebWorkerEngine(worker); 24 | 25 | createRoot(document.getElementById('root')!).render( 26 | 27 | 28 | 29 | 30 | 31 | , 32 | ); 33 | } 34 | 35 | run(); 36 | -------------------------------------------------------------------------------- /examples/react-mui/src/webworker.ts: -------------------------------------------------------------------------------- 1 | import { PdfiumEngineRunner } from '@embedpdf/engines'; 2 | 3 | async function init() { 4 | const response = await fetch('https://snippet.embedpdf.com/pdfium.wasm'); 5 | const wasmBinary = await response.arrayBuffer(); 6 | const runner = new PdfiumEngineRunner(wasmBinary); 7 | runner.prepare(); 8 | } 9 | 10 | init(); 11 | -------------------------------------------------------------------------------- /examples/react-mui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2022", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "moduleResolution": "Bundler", 9 | "allowImportingTsExtensions": true, 10 | "isolatedModules": true, 11 | "moduleDetection": "force", 12 | "noEmit": true, 13 | "jsx": "react-jsx", 14 | "strict": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "noFallthroughCasesInSwitch": true, 18 | "noUncheckedIndexedAccess": true 19 | }, 20 | "include": ["src"] 21 | } 22 | -------------------------------------------------------------------------------- /examples/react-mui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | server: { 7 | port: 3000, 8 | open: true, 9 | }, 10 | build: { 11 | outDir: 'dist', 12 | sourcemap: true, 13 | }, 14 | optimizeDeps: { 15 | include: ['@mui/material', '@mui/icons-material', '@emotion/react', '@emotion/styled'], 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @embedpdf/core 2 | 3 | Core package for CloudPDF. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | npm install @embedpdf/core 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```typescript 14 | import { PDFCore } from '@embedpdf/core'; 15 | import { createPdfiumModule, PdfiumEngine } from '@embedpdf/engines'; 16 | import { NavigationPlugin } from '@embedpdf/plugin-navigation'; 17 | 18 | const wasmBinary = await loadWasmBinary(); 19 | const wasmModule = await createPdfiumModule({ wasmBinary }); 20 | const engine = new PdfiumEngine(wasmModule, new ConsoleLogger()); 21 | 22 | const core = new PDFCore(engine); 23 | 24 | const navigationPlugin = new NavigationPlugin({ 25 | initialPage: 1, 26 | defaultScrollMode: 'continuous', 27 | }); 28 | 29 | core.registerPlugin(navigationPlugin); 30 | 31 | core.loadDocument('https://cloudpdf.io/example.pdf'); 32 | 33 | core.on('document:loaded', ({ pageCount }) => { 34 | console.log(`Document loaded with ${pageCount} pages`); 35 | }); 36 | 37 | core.on('navigation:pageChanged', ({ pageNumber }) => { 38 | console.log(`Navigated to page ${pageNumber}`); 39 | }); 40 | ``` 41 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/core/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './registry/plugin-registry'; 2 | export * from './utils/dependency-resolver'; 3 | export * from './utils/plugin-helpers'; 4 | export * from './types/plugin'; 5 | export * from './types/errors'; 6 | export * from './base/base-plugin'; 7 | export * from './store/types'; 8 | export * from './store/actions'; 9 | export * from './store/initial-state'; 10 | export * from './store/selectors'; 11 | export * from './utils/event-control'; 12 | export * from './utils/eventing'; 13 | export * from './utils/math'; 14 | -------------------------------------------------------------------------------- /packages/core/src/lib/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './store'; 2 | export * from './plugin-store'; 3 | export * from './types'; 4 | export * from './initial-state'; 5 | export * from './actions'; 6 | export * from './selectors'; 7 | -------------------------------------------------------------------------------- /packages/core/src/lib/store/initial-state.ts: -------------------------------------------------------------------------------- 1 | import { PdfDocumentObject, PdfPageObject, Rotation } from '@embedpdf/models'; 2 | import { PluginRegistryConfig } from '../types/plugin'; 3 | 4 | export interface CoreState { 5 | scale: number; 6 | rotation: Rotation; 7 | document: PdfDocumentObject | null; 8 | pages: PdfPageObject[][]; 9 | loading: boolean; 10 | error: string | null; 11 | } 12 | 13 | export const initialCoreState: (config?: PluginRegistryConfig) => CoreState = (config) => ({ 14 | scale: config?.scale ?? 1, 15 | rotation: config?.rotation ?? Rotation.Degree0, 16 | document: null, 17 | pages: [], 18 | loading: false, 19 | error: null, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/core/src/lib/store/selectors.ts: -------------------------------------------------------------------------------- 1 | import { CoreState } from './initial-state'; 2 | import { transformSize, PdfPageObjectWithRotatedSize } from '@embedpdf/models'; 3 | 4 | export const getPagesWithRotatedSize = (state: CoreState): PdfPageObjectWithRotatedSize[][] => { 5 | return state.pages.map((page) => 6 | page.map((p) => ({ 7 | ...p, 8 | rotatedSize: transformSize(p.size, state.rotation, 1), 9 | })), 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/utils/plugin-helpers.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '../store'; 2 | import { IPlugin, PluginBatchRegistration, PluginPackage } from '../types/plugin'; 3 | 4 | /** 5 | * Helper function to create a properly typed plugin registration 6 | */ 7 | export function createPluginRegistration< 8 | T extends IPlugin, 9 | TConfig, 10 | TState, 11 | TAction extends Action, 12 | >( 13 | pluginPackage: PluginPackage, 14 | config?: Partial, 15 | ): PluginBatchRegistration { 16 | return { 17 | package: pluginPackage, 18 | config, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/core/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './embed-pdf'; 2 | -------------------------------------------------------------------------------- /packages/core/src/preact/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'preact'; 2 | import type { PluginRegistry } from '@embedpdf/core'; 3 | 4 | export interface PDFContextState { 5 | registry: PluginRegistry | null; 6 | isInitializing: boolean; 7 | pluginsReady: boolean; 8 | } 9 | 10 | export const PDFContext = createContext({ 11 | registry: null, 12 | isInitializing: true, 13 | pluginsReady: false, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/core/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-capability'; 2 | export * from './use-registry'; 3 | export * from './use-store-state'; 4 | export * from './use-plugin'; 5 | -------------------------------------------------------------------------------- /packages/core/src/preact/hooks/use-capability.ts: -------------------------------------------------------------------------------- 1 | import type { BasePlugin } from '@embedpdf/core'; 2 | import { usePlugin } from './use-plugin'; 3 | 4 | type CapabilityState = { 5 | provides: ReturnType> | null; 6 | isLoading: boolean; 7 | ready: Promise; 8 | }; 9 | 10 | /** 11 | * Hook to access a plugin's capability. 12 | * @param pluginId The ID of the plugin to access 13 | * @returns The capability provided by the plugin or null during initialization 14 | * @example 15 | * // Get zoom capability 16 | * const zoom = useCapability(ZoomPlugin.id); 17 | */ 18 | export function useCapability(pluginId: T['id']): CapabilityState { 19 | const { plugin, isLoading, ready } = usePlugin(pluginId); 20 | 21 | if (!plugin) { 22 | return { 23 | provides: null, 24 | isLoading, 25 | ready, 26 | }; 27 | } 28 | 29 | if (!plugin.provides) { 30 | throw new Error(`Plugin ${pluginId} does not provide a capability`); 31 | } 32 | 33 | return { 34 | provides: plugin.provides() as ReturnType>, 35 | isLoading, 36 | ready, 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/src/preact/hooks/use-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { BasePlugin } from '@embedpdf/core'; 2 | import { useRegistry } from './use-registry'; 3 | 4 | type PluginState = { 5 | plugin: T | null; 6 | isLoading: boolean; 7 | ready: Promise; 8 | }; 9 | 10 | /** 11 | * Hook to access a plugin. 12 | * @param pluginId The ID of the plugin to access 13 | * @returns The plugin or null during initialization 14 | * @example 15 | * // Get zoom plugin 16 | * const zoom = usePlugin(ZoomPlugin.id); 17 | */ 18 | export function usePlugin(pluginId: T['id']): PluginState { 19 | const { registry } = useRegistry(); 20 | 21 | if (registry === null) { 22 | return { 23 | plugin: null, 24 | isLoading: true, 25 | ready: new Promise(() => {}), 26 | }; 27 | } 28 | 29 | const plugin = registry.getPlugin(pluginId); 30 | 31 | if (!plugin) { 32 | throw new Error(`Plugin ${pluginId} not found`); 33 | } 34 | 35 | return { 36 | plugin, 37 | isLoading: false, 38 | ready: plugin.ready(), 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /packages/core/src/preact/hooks/use-registry.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'preact/hooks'; 2 | import { PDFContext, PDFContextState } from '../context'; 3 | 4 | /** 5 | * Hook to access the PDF registry. 6 | * @returns The PDF registry or null during initialization 7 | */ 8 | export function useRegistry(): PDFContextState { 9 | const contextValue = useContext(PDFContext); 10 | 11 | // Error if used outside of context 12 | if (contextValue === undefined) { 13 | throw new Error('useCapability must be used within a PDFContext.Provider'); 14 | } 15 | 16 | const { registry, isInitializing } = contextValue; 17 | 18 | // During initialization, return null instead of throwing an error 19 | if (isInitializing) { 20 | return contextValue; 21 | } 22 | 23 | // At this point, initialization is complete but registry is still null, which is unexpected 24 | if (registry === null) { 25 | throw new Error('PDF registry failed to initialize properly'); 26 | } 27 | 28 | return contextValue; 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/src/preact/hooks/use-store-state.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'preact/hooks'; 2 | import { CoreState, PluginRegistry, StoreState } from '@embedpdf/core'; 3 | import { useRegistry } from './use-registry'; 4 | 5 | /** 6 | * Hook that provides access to the current global store state 7 | * and re-renders the component when the state changes 8 | */ 9 | export function useStoreState(): StoreState | null { 10 | const { registry } = useRegistry(); 11 | const [state, setState] = useState | null>(null); 12 | 13 | useEffect(() => { 14 | if (!registry) return; 15 | 16 | // Get initial state 17 | setState(registry.getStore().getState() as StoreState); 18 | 19 | // Subscribe to store changes 20 | const unsubscribe = registry.getStore().subscribe((_action, newState) => { 21 | setState(newState as StoreState); 22 | }); 23 | 24 | return () => unsubscribe(); 25 | }, [registry]); 26 | 27 | return state; 28 | } 29 | -------------------------------------------------------------------------------- /packages/core/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './context'; 2 | export * from './components'; 3 | export * from './hooks'; 4 | -------------------------------------------------------------------------------- /packages/core/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './embed-pdf'; 2 | -------------------------------------------------------------------------------- /packages/core/src/react/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { PluginRegistry } from '@embedpdf/core'; 3 | 4 | export interface PDFContextState { 5 | registry: PluginRegistry | null; 6 | isInitializing: boolean; 7 | pluginsReady: boolean; 8 | } 9 | 10 | export const PDFContext = createContext({ 11 | registry: null, 12 | isInitializing: true, 13 | pluginsReady: false, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/core/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-capability'; 2 | export * from './use-registry'; 3 | export * from './use-store-state'; 4 | export * from './use-plugin'; 5 | -------------------------------------------------------------------------------- /packages/core/src/react/hooks/use-capability.ts: -------------------------------------------------------------------------------- 1 | import type { BasePlugin } from '@embedpdf/core'; 2 | import { usePlugin } from './use-plugin'; 3 | 4 | type CapabilityState = { 5 | provides: ReturnType> | null; 6 | isLoading: boolean; 7 | ready: Promise; 8 | }; 9 | 10 | /** 11 | * Hook to access a plugin's capability. 12 | * @param pluginId The ID of the plugin to access 13 | * @returns The capability provided by the plugin or null during initialization 14 | * @example 15 | * // Get zoom capability 16 | * const zoom = useCapability(ZoomPlugin.id); 17 | */ 18 | export function useCapability(pluginId: T['id']): CapabilityState { 19 | const { plugin, isLoading, ready } = usePlugin(pluginId); 20 | 21 | if (!plugin) { 22 | return { 23 | provides: null, 24 | isLoading, 25 | ready, 26 | }; 27 | } 28 | 29 | if (!plugin.provides) { 30 | throw new Error(`Plugin ${pluginId} does not provide a capability`); 31 | } 32 | 33 | return { 34 | provides: plugin.provides() as ReturnType>, 35 | isLoading, 36 | ready, 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/src/react/hooks/use-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { BasePlugin } from '@embedpdf/core'; 2 | import { useRegistry } from './use-registry'; 3 | 4 | type PluginState = { 5 | plugin: T | null; 6 | isLoading: boolean; 7 | ready: Promise; 8 | }; 9 | 10 | /** 11 | * Hook to access a plugin. 12 | * @param pluginId The ID of the plugin to access 13 | * @returns The plugin or null during initialization 14 | * @example 15 | * // Get zoom plugin 16 | * const zoom = usePlugin(ZoomPlugin.id); 17 | */ 18 | export function usePlugin(pluginId: T['id']): PluginState { 19 | const { registry } = useRegistry(); 20 | 21 | if (registry === null) { 22 | return { 23 | plugin: null, 24 | isLoading: true, 25 | ready: new Promise(() => {}), 26 | }; 27 | } 28 | 29 | const plugin = registry.getPlugin(pluginId); 30 | 31 | if (!plugin) { 32 | throw new Error(`Plugin ${pluginId} not found`); 33 | } 34 | 35 | return { 36 | plugin, 37 | isLoading: false, 38 | ready: plugin.ready(), 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /packages/core/src/react/hooks/use-registry.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { PDFContext, PDFContextState } from '../context'; 3 | 4 | /** 5 | * Hook to access the PDF registry. 6 | * @returns The PDF registry or null during initialization 7 | */ 8 | export function useRegistry(): PDFContextState { 9 | const contextValue = useContext(PDFContext); 10 | 11 | // Error if used outside of context 12 | if (contextValue === undefined) { 13 | throw new Error('useCapability must be used within a PDFContext.Provider'); 14 | } 15 | 16 | const { registry, isInitializing } = contextValue; 17 | 18 | // During initialization, return null instead of throwing an error 19 | if (isInitializing) { 20 | return contextValue; 21 | } 22 | 23 | // At this point, initialization is complete but registry is still null, which is unexpected 24 | if (registry === null) { 25 | throw new Error('PDF registry failed to initialize properly'); 26 | } 27 | 28 | return contextValue; 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/src/react/hooks/use-store-state.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { CoreState, StoreState } from '@embedpdf/core'; 3 | import { useRegistry } from './use-registry'; 4 | 5 | /** 6 | * Hook that provides access to the current global store state 7 | * and re-renders the component when the state changes 8 | */ 9 | export function useStoreState(): StoreState | null { 10 | const { registry } = useRegistry(); 11 | const [state, setState] = useState | null>(null); 12 | 13 | useEffect(() => { 14 | if (!registry) return; 15 | 16 | // Get initial state 17 | setState(registry.getStore().getState() as StoreState); 18 | 19 | // Subscribe to store changes 20 | const unsubscribe = registry.getStore().subscribe((_action, newState) => { 21 | setState(newState as StoreState); 22 | }); 23 | 24 | return () => unsubscribe(); 25 | }, [registry]); 26 | 27 | return state; 28 | } 29 | -------------------------------------------------------------------------------- /packages/core/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './context'; 2 | export * from './components'; 3 | export * from './hooks'; 4 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/engines/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 CloudPDF, Ji Chang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/engines/README.md: -------------------------------------------------------------------------------- 1 | ### @embedpdf/engines 2 | 3 | This package defines engines used for parsing PDF files. Right now, we only provide one PDF engine that is based on PDFium and a mock of engine for testing purpose. 4 | 5 | #### Install 6 | 7 | ```bash 8 | npm install @embedpdf/engines 9 | ``` 10 | 11 | #### Usage 12 | 13 | ```typescript 14 | import { createPdfiumModule, PdfiumEngine } from '@embedpdf/engines'; 15 | 16 | // implement loadWasmBinary to load pdifum wasm file 17 | const wasmBinary = await loadWasmBinary(); 18 | const wasmModule = await createPdfiumModule({ wasmBinary }); 19 | const engine = new PdfiumEngine(wasmModule, new ConsoleLogger()); 20 | 21 | engine.initialize(); 22 | 23 | // implement fetchFile to load pdf file 24 | const file = await loadFile(); 25 | const task = engine.openDocument(file); 26 | task.wait( 27 | (doc) => { 28 | console.log('opened: ', doc); 29 | 30 | engine.closeDocument(doc); 31 | }, 32 | (err) => { 33 | console.log('failed: ', err); 34 | }, 35 | ); 36 | ``` 37 | -------------------------------------------------------------------------------- /packages/engines/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CloudPDF Demo 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |

14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/engines/demo/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html, 8 | body { 9 | height: 100%; 10 | width: 100%; 11 | } 12 | 13 | .pdf__application--edit .pdf__page__annotation--link { 14 | border: 1px solid black; 15 | 16 | opacity: 0.5; 17 | } 18 | 19 | .pdf__document { 20 | position: relative; 21 | } 22 | 23 | .pdf__toolbar__container { 24 | position: absolute; 25 | left: 0; 26 | bottom: 0; 27 | display: flex; 28 | justify-content: center; 29 | align-items: center; 30 | 31 | width: 100%; 32 | } 33 | 34 | canvas { 35 | display: block; 36 | margin: 4px auto; 37 | border: 1px solid black; 38 | } 39 | -------------------------------------------------------------------------------- /packages/engines/demo/url.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm' { 2 | const url: string; 3 | export = url; 4 | } 5 | -------------------------------------------------------------------------------- /packages/engines/demo/webworker.ts: -------------------------------------------------------------------------------- 1 | import { PdfiumEngineRunner } from '../src/index'; 2 | import pdfiumWasm from 'url:@embedpdf/pdfium/pdfium.wasm'; 3 | 4 | async function init() { 5 | const response = await fetch(pdfiumWasm); 6 | const wasmBinary = await response.arrayBuffer(); 7 | const runner = new PdfiumEngineRunner(wasmBinary); 8 | runner.prepare(); 9 | } 10 | 11 | init(); 12 | -------------------------------------------------------------------------------- /packages/engines/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Docs for `@embedpdf/engines` module 3 | * @packageDocumentation 4 | */ 5 | 6 | export * from './pdfium'; 7 | export * from './webworker'; 8 | export * from './mock'; 9 | -------------------------------------------------------------------------------- /packages/engines/src/pdfium-engine.ts: -------------------------------------------------------------------------------- 1 | export * from './pdfium'; 2 | -------------------------------------------------------------------------------- /packages/engines/src/pdfium/engine.test.ts: -------------------------------------------------------------------------------- 1 | import { WrappedPdfiumModule } from '@embedpdf/pdfium'; 2 | import { PdfiumEngine } from './engine'; 3 | 4 | describe('PdfiumEngine', () => { 5 | it('should return module with cwrap function', () => { 6 | const wasmModule = { 7 | cwrap: (identity: any, returnType: any, argTypes: any) => { 8 | return { 9 | identity, 10 | returnType, 11 | argTypes, 12 | }; 13 | }, 14 | } as unknown as WrappedPdfiumModule; 15 | const engine = new PdfiumEngine(wasmModule); 16 | 17 | expect(engine).toBeDefined(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/engines/src/pdfium/helper.test.ts: -------------------------------------------------------------------------------- 1 | import { readString } from './helper'; 2 | import { WrappedPdfiumModule } from '@embedpdf/pdfium'; 3 | 4 | describe('readString', () => { 5 | it('should manage memory and call callback with buffer', () => { 6 | const ptr = Math.random(); 7 | const mockWasmModule = { 8 | pdfium: { 9 | wasmExports: { 10 | malloc: jest.fn(() => { 11 | return ptr; 12 | }), 13 | free: jest.fn(), 14 | }, 15 | HEAP8: new Int8Array(100), 16 | }, 17 | } as unknown as WrappedPdfiumModule; 18 | const readChars = jest.fn(() => { 19 | return 10; 20 | }); 21 | const parseChars = jest.fn(() => { 22 | return 'hello'; 23 | }); 24 | 25 | const str = readString(mockWasmModule.pdfium, readChars, parseChars); 26 | expect(mockWasmModule.pdfium.wasmExports.malloc).toHaveBeenCalledWith(100); 27 | expect(mockWasmModule.pdfium.wasmExports.free).toHaveBeenCalledWith(ptr); 28 | expect(readChars).toHaveBeenCalledWith(ptr, 100); 29 | expect(str).toBe('hello'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /packages/engines/src/pdfium/index.ts: -------------------------------------------------------------------------------- 1 | export * from './engine'; 2 | export * from './helper'; 3 | export * from './runner'; 4 | -------------------------------------------------------------------------------- /packages/engines/src/pdfium/runner.ts: -------------------------------------------------------------------------------- 1 | import { init } from '@embedpdf/pdfium'; 2 | import { EngineRunner } from '../webworker'; 3 | import { PdfiumEngine } from './engine'; 4 | 5 | /** 6 | * EngineRunner for pdfium-based wasm engine 7 | */ 8 | export class PdfiumEngineRunner extends EngineRunner { 9 | /** 10 | * Create an instance of PdfiumEngineRunner 11 | * @param wasmBinary - wasm binary that contains the pdfium wasm file 12 | */ 13 | constructor(private wasmBinary: ArrayBuffer) { 14 | super(); 15 | } 16 | 17 | /** 18 | * Initialize runner 19 | */ 20 | async prepare() { 21 | const wasmBinary = this.wasmBinary; 22 | const wasmModule = await init({ wasmBinary }); 23 | this.engine = new PdfiumEngine(wasmModule); 24 | this.ready(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/engines/src/webworker-engine.ts: -------------------------------------------------------------------------------- 1 | export * from './webworker'; 2 | -------------------------------------------------------------------------------- /packages/engines/src/webworker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './engine'; 2 | export * from './runner'; 3 | -------------------------------------------------------------------------------- /packages/engines/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "types": ["node", "jest"] 12 | }, 13 | "include": ["src"], 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/engines/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | import path from 'node:path'; 3 | import fs from 'node:fs/promises'; 4 | 5 | export default defineConfig({ 6 | entry: { 7 | index: 'src/index.ts', 8 | pdfium: 'src/pdfium-engine.ts', 9 | worker: 'src/webworker-engine.ts', 10 | }, 11 | 12 | // one `.d.ts` per entry above 13 | dts: { 14 | entry: { 15 | index: 'src/index.ts', 16 | pdfium: 'src/pdfium-engine.ts', 17 | worker: 'src/webworker-engine.ts', 18 | }, 19 | }, 20 | 21 | format: ['esm', 'cjs'], 22 | outDir: 'dist', 23 | sourcemap: true, 24 | clean: true, 25 | tsconfig: path.resolve(__dirname, 'tsconfig.json'), 26 | }); 27 | -------------------------------------------------------------------------------- /packages/models/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 CloudPDF, Ji Chang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/models/README.md: -------------------------------------------------------------------------------- 1 | ### @embedpdf/models 2 | 3 | This pacakge contains definitions of models used in CloudPDF packages. 4 | 5 | #### Install 6 | 7 | ```bash 8 | npm install @embedpdf/models 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/models/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@embedpdf/models", 3 | "version": "0.0.0", 4 | "private": false, 5 | "description": "core models of embedpdf", 6 | "type": "module", 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.cjs", 9 | "types": "./dist/index.d.ts", 10 | "exports": { 11 | ".": { 12 | "types": "./dist/index.d.ts", 13 | "import": "./dist/index.js", 14 | "require": "./dist/index.cjs" 15 | } 16 | }, 17 | "scripts": { 18 | "build": "PROJECT_CWD=$(pwd) pnpm -w p:build", 19 | "build:watch": "PROJECT_CWD=$(pwd) pnpm -w p:build:watch", 20 | "clean": "PROJECT_CWD=$(pwd) pnpm -w p:clean", 21 | "lint": "PROJECT_CWD=$(pwd) pnpm -w p:lint", 22 | "lint:fix": "PROJECT_CWD=$(pwd) pnpm -w p:lint:fix", 23 | "typecheck": "PROJECT_CWD=$(pwd) pnpm -w p:typecheck" 24 | }, 25 | "files": [ 26 | "dist", 27 | "README.md" 28 | ], 29 | "author": "Bob Singor, Ji Chang", 30 | "license": "MIT", 31 | "devDependencies": { 32 | "tsup": "^8.0.0", 33 | "typescript": "^5.0.0", 34 | "@types/jest": "^29.5.14", 35 | "jest": "^29.7.0" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/models/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Library contains the common definitions of data types and logic 3 | * 4 | * @remarks 5 | * The `@embedpdf/models` defines the interface and classes which are used to 6 | * handling PDF files. 7 | * 8 | * @packageDocumentation 9 | */ 10 | export * from './geometry'; 11 | export * from './logger'; 12 | export * from './pdf'; 13 | export * from './task'; 14 | 15 | /** 16 | * ignore will do nothing when called. 17 | * 18 | * @public 19 | */ 20 | export function ignore() {} 21 | -------------------------------------------------------------------------------- /packages/models/src/logger.test.ts: -------------------------------------------------------------------------------- 1 | import { LevelLogger, LogLevel, Logger } from './logger'; 2 | 3 | const LOG_SOURCE = 'TEST'; 4 | const LOG_CATEGORY = 'TEST'; 5 | 6 | describe('LevelLogger', () => { 7 | it('should call log function based on level', () => { 8 | const testLogger: Logger = { 9 | debug: jest.fn(), 10 | info: jest.fn(), 11 | warn: jest.fn(), 12 | error: jest.fn(), 13 | perf: jest.fn(), 14 | }; 15 | 16 | const levelLogger = new LevelLogger(testLogger, LogLevel.Error); 17 | 18 | levelLogger.debug(LOG_SOURCE, LOG_CATEGORY); 19 | 20 | expect(testLogger.debug).toHaveBeenCalledTimes(0); 21 | 22 | levelLogger.error(LOG_SOURCE, LOG_CATEGORY); 23 | 24 | expect(testLogger.error).toHaveBeenCalledTimes(1); 25 | expect(testLogger.error).toHaveBeenCalledWith(LOG_SOURCE, LOG_CATEGORY); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/models/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "types": ["node", "jest"] 12 | }, 13 | "include": ["src"], 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/pdfium/.gitignore: -------------------------------------------------------------------------------- 1 | docker 2 | build/exported-functions.txt 3 | build/exported-runtime-methods.txt -------------------------------------------------------------------------------- /packages/pdfium/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 CloudPDF, Ji Chang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/pdfium/Makefile: -------------------------------------------------------------------------------- 1 | all: dev 2 | 3 | clean: 4 | rm -rf ./src/pdfium.js ./src/pdfium.wasm 5 | 6 | .PHONY: build 7 | build: 8 | make clean 9 | docker buildx build -o docker . 10 | -------------------------------------------------------------------------------- /packages/pdfium/build/code/cpp/filewriter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "fpdf_save.h" 6 | #include "filewriter.h" 7 | 8 | PDFiumExtFileWriter::PDFiumExtFileWriter() 9 | { 10 | FPDF_FILEWRITE::version = 1; 11 | FPDF_FILEWRITE::WriteBlock = WriteBlockCallback; 12 | } 13 | 14 | PDFiumExtFileWriter::~PDFiumExtFileWriter() 15 | { 16 | } 17 | 18 | int PDFiumExtFileWriter::WriteBlockCallback(FPDF_FILEWRITE *pFileWrite, 19 | const void *data, 20 | unsigned long size) 21 | { 22 | PDFiumExtFileWriter *pThis = static_cast(pFileWrite); 23 | 24 | pThis->data.append(static_cast(data), size); 25 | 26 | return size; 27 | } 28 | -------------------------------------------------------------------------------- /packages/pdfium/build/code/cpp/filewriter.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fpdf_save.h" 3 | 4 | class PDFiumExtFileWriter : public FPDF_FILEWRITE 5 | { 6 | public: 7 | PDFiumExtFileWriter(); 8 | ~PDFiumExtFileWriter(); 9 | 10 | private: 11 | static int WriteBlockCallback(FPDF_FILEWRITE *pFileWrite, 12 | const void *data, 13 | unsigned long size); 14 | 15 | public: 16 | std::string data; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/pdfium/build/compile.sh: -------------------------------------------------------------------------------- 1 | em++ $(ls *.cpp) \ 2 | /build/pdfium/out/prod/obj/libpdfium.a \ 3 | -g \ 4 | -v \ 5 | -sEXPORT_ES6=1 \ 6 | -sENVIRONMENT=worker \ 7 | -sMODULARIZE=1 \ 8 | -sWASM=1 \ 9 | -sALLOW_MEMORY_GROWTH=1 \ 10 | -sALLOW_TABLE_GROWTH=1 \ 11 | -sEXPORT_NAME=createPdfium \ 12 | -sUSE_ZLIB=1 \ 13 | -sUSE_LIBJPEG=1 \ 14 | -sASSERTIONS=1 \ 15 | -sEXPORTED_RUNTIME_METHODS=$(cat ./exported-runtime-methods.txt) \ 16 | -sEXPORTED_FUNCTIONS=$(cat ./exported-functions.txt) \ 17 | -lpdfium \ 18 | -L/build/pdfium/out/prod/obj \ 19 | -I/build/pdfium/public \ 20 | -std=c++11 \ 21 | -Wall \ 22 | --no-entry \ 23 | -o \ 24 | ./pdfium.js 25 | -------------------------------------------------------------------------------- /packages/pdfium/build/patch/build/toolchain/wasm/BUILD.gn: -------------------------------------------------------------------------------- 1 | import("//build/toolchain/gcc_toolchain.gni") 2 | 3 | gcc_toolchain("emscripten") { 4 | cc = "emcc" 5 | cxx = "em++" 6 | 7 | readelf = "llvm-readobj" 8 | ar = "emar" 9 | ld = cxx 10 | nm = "emnm" 11 | 12 | extra_cflags = "-fno-stack-protector -Wno-unknown-warning-option -D_POSIX_C_SOURCE=200112" 13 | extra_cxxflags = "-fno-stack-protector -Wno-unknown-warning-option -D_POSIX_C_SOURCE=200112" 14 | 15 | toolchain_args = { 16 | current_cpu = "wasm" 17 | current_os = "wasm" 18 | } 19 | } -------------------------------------------------------------------------------- /packages/pdfium/scripts/exported-runtime-methods.js: -------------------------------------------------------------------------------- 1 | export const methods = [ 2 | 'wasmExports', 3 | 'cwrap', 4 | 'addFunction', 5 | 'removeFunction', 6 | 'ccall', 7 | 'setValue', 8 | 'getValue', 9 | 'UTF8ToString', 10 | 'UTF16ToString', 11 | 'stringToUTF8', 12 | 'stringToUTF16', 13 | ]; 14 | 15 | export const types = { 16 | wasmExports: 'WasmExports', 17 | }; 18 | -------------------------------------------------------------------------------- /packages/pdfium/scripts/generate-exported-runtime-methods.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import { fileURLToPath } from 'url'; 4 | import { methods, types } from './exported-runtime-methods.js'; 5 | 6 | // Get current directory name in ES modules 7 | const __filename = fileURLToPath(import.meta.url); 8 | const __dirname = path.dirname(__filename); 9 | 10 | const names = methods.join(','); 11 | fs.writeFileSync(path.join(__dirname, '../build/exported-runtime-methods.txt'), names, { 12 | encoding: 'utf-8', 13 | }); 14 | 15 | const defintion = ` 16 | /// 17 | 18 | export interface WasmExports { 19 | malloc: (size: number) => number; 20 | free: (ptr: number) => void; 21 | } 22 | 23 | export interface PdfiumRuntimeMethods { 24 | ${methods 25 | .map((func) => { 26 | if (types[func]) { 27 | return ` ${func}: ${types[func]};`; 28 | } 29 | return ` ${func}: typeof ${func};`; 30 | }) 31 | .join('\n')} 32 | } 33 | `; 34 | 35 | fs.writeFileSync(path.join(__dirname, '../src/runtime.ts'), defintion, { 36 | encoding: 'utf-8', 37 | }); 38 | -------------------------------------------------------------------------------- /packages/pdfium/src/pdfium.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export interface PdfiumModule extends EmscriptenModule {} 4 | 5 | /** 6 | * Create an instance of pdfium wasm module 7 | * @param init - override pdfium methods 8 | */ 9 | export default function createPdfium(init: Partial): Promise; 10 | -------------------------------------------------------------------------------- /packages/pdfium/src/pdfium.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/packages/pdfium/src/pdfium.wasm -------------------------------------------------------------------------------- /packages/pdfium/src/runtime.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export interface WasmExports { 4 | malloc: (size: number) => number; 5 | free: (ptr: number) => void; 6 | } 7 | 8 | export interface PdfiumRuntimeMethods { 9 | wasmExports: WasmExports; 10 | cwrap: typeof cwrap; 11 | addFunction: typeof addFunction; 12 | removeFunction: typeof removeFunction; 13 | ccall: typeof ccall; 14 | setValue: typeof setValue; 15 | getValue: typeof getValue; 16 | UTF8ToString: typeof UTF8ToString; 17 | UTF16ToString: typeof UTF16ToString; 18 | stringToUTF8: typeof stringToUTF8; 19 | stringToUTF16: typeof stringToUTF16; 20 | } 21 | -------------------------------------------------------------------------------- /packages/pdfium/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "verbatimModuleSyntax": true 12 | }, 13 | "include": ["src"], 14 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, ANNOTATION_PLUGIN_ID } from './manifest'; 3 | import { AnnotationPluginConfig, AnnotationState } from './types'; 4 | import { AnnotationPlugin } from './annotation-plugin'; 5 | import { initialState, reducer } from './reducer'; 6 | import { AnnotationAction } from './actions'; 7 | 8 | export const AnnotationPluginPackage: PluginPackage< 9 | AnnotationPlugin, 10 | AnnotationPluginConfig, 11 | AnnotationState, 12 | AnnotationAction 13 | > = { 14 | manifest, 15 | create: (registry, engine) => new AnnotationPlugin(ANNOTATION_PLUGIN_ID, registry, engine), 16 | reducer, 17 | initialState, 18 | }; 19 | 20 | export * from './annotation-plugin'; 21 | export * from './types'; 22 | export * from './manifest'; 23 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { AnnotationPluginConfig } from './types'; 3 | 4 | export const ANNOTATION_PLUGIN_ID = 'annotation'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: ANNOTATION_PLUGIN_ID, 8 | name: 'Annotation Plugin', 9 | version: '1.0.0', 10 | provides: ['annotation'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './annotation-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-annotation'; 2 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/preact/hooks/use-annotation.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { AnnotationPlugin } from '@embedpdf/plugin-annotation'; 3 | 4 | export const useAnnotation = () => usePlugin(AnnotationPlugin.id); 5 | export const useAnnotationCapability = () => useCapability(AnnotationPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-annotation/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-annotation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/lib/attachment-plugin.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin, PluginRegistry } from '@embedpdf/core'; 2 | import { PdfEngine } from '@embedpdf/models'; 3 | 4 | import { AttachmentCapability, AttachmentPluginConfig } from './types'; 5 | 6 | export class AttachmentPlugin extends BasePlugin { 7 | static readonly id = 'attachment' as const; 8 | 9 | private engine: PdfEngine; 10 | 11 | constructor(id: string, registry: PluginRegistry, engine: PdfEngine) { 12 | super(id, registry); 13 | 14 | this.engine = engine; 15 | } 16 | 17 | async initialize(_: AttachmentPluginConfig): Promise {} 18 | 19 | protected buildCapability(): AttachmentCapability { 20 | return {}; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { AttachmentPlugin } from './attachment-plugin'; 4 | import { manifest, ATTACHMENT_PLUGIN_ID } from './manifest'; 5 | import { AttachmentPluginConfig } from './types'; 6 | 7 | export const AttachmentPluginPackage: PluginPackage = { 8 | manifest, 9 | create: (registry, engine) => new AttachmentPlugin(ATTACHMENT_PLUGIN_ID, registry, engine), 10 | reducer: () => {}, 11 | initialState: {}, 12 | }; 13 | 14 | export * from './attachment-plugin'; 15 | export * from './types'; 16 | export * from './manifest'; 17 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { AttachmentPluginConfig } from './types'; 3 | 4 | export const ATTACHMENT_PLUGIN_ID = 'attachment'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: ATTACHMENT_PLUGIN_ID, 8 | name: 'Attachment Plugin', 9 | version: '1.0.0', 10 | provides: ['attachment'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig } from '@embedpdf/core'; 2 | 3 | export interface AttachmentPluginConfig extends BasePluginConfig {} 4 | 5 | export interface AttachmentCapability {} 6 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-attachment'; 2 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/preact/hooks/use-attachment.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { AttachmentPlugin } from '@embedpdf/plugin-attachment'; 3 | 4 | export const useAttachment = () => usePlugin(AttachmentPlugin.id); 5 | export const useAttachmentCapability = () => useCapability(AttachmentPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-attachment/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-attachment/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/lib/bookmark-plugin.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin, PluginRegistry } from '@embedpdf/core'; 2 | import { PdfBookmarkObject, PdfEngine, PdfErrorReason, Task } from '@embedpdf/models'; 3 | 4 | import { BookmarkCapability, BookmarkPluginConfig } from './types'; 5 | 6 | export class BookmarkPlugin extends BasePlugin { 7 | static readonly id = 'bookmark' as const; 8 | 9 | private engine: PdfEngine; 10 | 11 | constructor(id: string, registry: PluginRegistry, engine: PdfEngine) { 12 | super(id, registry); 13 | 14 | this.engine = engine; 15 | } 16 | 17 | async initialize(_: BookmarkPluginConfig): Promise {} 18 | 19 | protected buildCapability(): BookmarkCapability { 20 | return { 21 | getBookmarks: this.getBookmarks.bind(this), 22 | }; 23 | } 24 | 25 | private getBookmarks(): Task<{ bookmarks: PdfBookmarkObject[] }, PdfErrorReason> { 26 | const doc = this.coreState.core.document; 27 | if (!doc) throw new Error('Document not open'); 28 | 29 | return this.engine.getBookmarks(doc); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, BOOKMARK_PLUGIN_ID } from './manifest'; 3 | import { BookmarkPluginConfig } from './types'; 4 | import { BookmarkPlugin } from './bookmark-plugin'; 5 | 6 | export const BookmarkPluginPackage: PluginPackage = { 7 | manifest, 8 | create: (registry, engine) => new BookmarkPlugin(BOOKMARK_PLUGIN_ID, registry, engine), 9 | reducer: () => {}, 10 | initialState: {}, 11 | }; 12 | 13 | export * from './bookmark-plugin'; 14 | export * from './types'; 15 | export * from './manifest'; 16 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { BookmarkPluginConfig } from './types'; 3 | 4 | export const BOOKMARK_PLUGIN_ID = 'bookmark'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: BOOKMARK_PLUGIN_ID, 8 | name: 'Bookmark Plugin', 9 | version: '1.0.0', 10 | provides: ['bookmark'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig } from '@embedpdf/core'; 2 | import { Task } from '@embedpdf/models'; 3 | import { PdfBookmarkObject } from '@embedpdf/models'; 4 | import { PdfErrorReason } from '@embedpdf/models'; 5 | 6 | export interface BookmarkPluginConfig extends BasePluginConfig {} 7 | 8 | export interface BookmarkCapability { 9 | getBookmarks: () => Task< 10 | { 11 | bookmarks: PdfBookmarkObject[]; 12 | }, 13 | PdfErrorReason 14 | >; 15 | } 16 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-bookmark'; 2 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/preact/hooks/use-bookmark.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { BookmarkPlugin } from '@embedpdf/plugin-bookmark'; 3 | 4 | export const useBookmark = () => usePlugin(BookmarkPlugin.id); 5 | export const useBookmarkCapability = () => useCapability(BookmarkPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-bookmark/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-download/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-download/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { DownloadPlugin } from './download-plugin'; 4 | import { manifest, DOWNLOAD_PLUGIN_ID } from './manifest'; 5 | import { DownloadPluginConfig } from './types'; 6 | 7 | export const DownloadPluginPackage: PluginPackage = { 8 | manifest, 9 | create: (registry, engine) => new DownloadPlugin(DOWNLOAD_PLUGIN_ID, registry, engine), 10 | reducer: () => {}, 11 | initialState: {}, 12 | }; 13 | 14 | export * from './download-plugin'; 15 | export * from './types'; 16 | export * from './manifest'; 17 | -------------------------------------------------------------------------------- /packages/plugin-download/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { DownloadPluginConfig } from './types'; 3 | 4 | export const DOWNLOAD_PLUGIN_ID = 'download'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: DOWNLOAD_PLUGIN_ID, 8 | name: 'Download Plugin', 9 | version: '1.0.0', 10 | provides: ['download'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-download/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig, EventHook } from '@embedpdf/core'; 2 | import { PdfErrorReason, Task } from '@embedpdf/models'; 3 | 4 | export interface DownloadPluginConfig extends BasePluginConfig {} 5 | 6 | export interface DownloadCapability { 7 | saveAsCopy: () => Task; 8 | download: () => void; 9 | onRequest: EventHook<'download'>; 10 | } 11 | -------------------------------------------------------------------------------- /packages/plugin-download/src/preact/components/download.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource preact */ 2 | import { ignore } from '@embedpdf/models'; 3 | import { useEffect, useRef } from 'preact/hooks'; 4 | 5 | import { useDownloadCapability } from '../hooks'; 6 | 7 | export function Download() { 8 | const { provides: downloadCapability } = useDownloadCapability(); 9 | const ref = useRef(null); 10 | 11 | useEffect(() => { 12 | if (!downloadCapability) return; 13 | 14 | const unsub = downloadCapability.onRequest(async (action) => { 15 | if (action === 'download') { 16 | const el = ref.current; 17 | if (!el) return; 18 | 19 | const task = downloadCapability.saveAsCopy(); 20 | task.wait((buffer) => { 21 | const url = URL.createObjectURL(new Blob([buffer])); 22 | el.href = url; 23 | el.download = 'document.pdf'; 24 | el.click(); 25 | URL.revokeObjectURL(url); 26 | }, ignore); 27 | } 28 | }); 29 | 30 | return unsub; 31 | }, [downloadCapability]); 32 | 33 | return ; 34 | } 35 | -------------------------------------------------------------------------------- /packages/plugin-download/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './download'; 2 | -------------------------------------------------------------------------------- /packages/plugin-download/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-download'; 2 | -------------------------------------------------------------------------------- /packages/plugin-download/src/preact/hooks/use-download.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { DownloadPlugin } from '@embedpdf/plugin-download'; 3 | 4 | export const useDownload = () => usePlugin(DownloadPlugin.id); 5 | export const useDownloadCapability = () => useCapability(DownloadPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-download/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-download/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-download/src/react/component/download.tsx: -------------------------------------------------------------------------------- 1 | import { ignore } from '@embedpdf/models'; 2 | import { useEffect, useRef } from 'react'; 3 | 4 | import { useDownloadCapability } from '../hooks'; 5 | 6 | export function Download() { 7 | const { provides: downloadCapability } = useDownloadCapability(); 8 | const ref = useRef(null); 9 | 10 | useEffect(() => { 11 | if (!downloadCapability) return; 12 | 13 | const unsub = downloadCapability.onRequest(async (action) => { 14 | if (action === 'download') { 15 | const el = ref.current; 16 | if (!el) return; 17 | 18 | const task = downloadCapability.saveAsCopy(); 19 | task.wait((buffer) => { 20 | const url = URL.createObjectURL(new Blob([buffer])); 21 | el.href = url; 22 | el.download = 'document.pdf'; 23 | el.click(); 24 | URL.revokeObjectURL(url); 25 | }, ignore); 26 | } 27 | }); 28 | 29 | return unsub; 30 | }, [downloadCapability]); 31 | 32 | return ; 33 | } 34 | -------------------------------------------------------------------------------- /packages/plugin-download/src/react/component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './download'; 2 | -------------------------------------------------------------------------------- /packages/plugin-download/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-download'; 2 | -------------------------------------------------------------------------------- /packages/plugin-download/src/react/hooks/use-download.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { DownloadPlugin } from '@embedpdf/plugin-download'; 3 | 4 | export const useDownload = () => usePlugin(DownloadPlugin.id); 5 | export const useDownloadCapability = () => useCapability(DownloadPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-download/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-download/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/lib/actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@embedpdf/core'; 2 | 3 | export const SET_FULLSCREEN = 'SET_FULLSCREEN'; 4 | 5 | export interface SetFullscreenAction extends Action { 6 | type: typeof SET_FULLSCREEN; 7 | payload: boolean; 8 | } 9 | 10 | export type FullscreenAction = SetFullscreenAction; 11 | 12 | export function setFullscreen(payload: boolean): SetFullscreenAction { 13 | return { type: SET_FULLSCREEN, payload }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, FULLSCREEN_PLUGIN_ID } from './manifest'; 3 | import { FullscreenPluginConfig, FullscreenState } from './types'; 4 | import { FullscreenPlugin } from './fullscreen-plugin'; 5 | import { initialState } from './reducer'; 6 | import { reducer } from './reducer'; 7 | import { FullscreenAction } from './actions'; 8 | 9 | export const FullscreenPluginPackage: PluginPackage< 10 | FullscreenPlugin, 11 | FullscreenPluginConfig, 12 | FullscreenState, 13 | FullscreenAction 14 | > = { 15 | manifest, 16 | create: (registry) => new FullscreenPlugin(FULLSCREEN_PLUGIN_ID, registry), 17 | reducer, 18 | initialState, 19 | }; 20 | 21 | export * from './fullscreen-plugin'; 22 | export * from './types'; 23 | export * from './manifest'; 24 | export * from './actions'; 25 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { FullscreenPluginConfig } from './types'; 3 | 4 | export const FULLSCREEN_PLUGIN_ID = 'fullscreen'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: FULLSCREEN_PLUGIN_ID, 8 | name: 'Fullscreen Plugin', 9 | version: '1.0.0', 10 | provides: ['fullscreen'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/lib/reducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from '@embedpdf/core'; 2 | import { FullscreenState } from './types'; 3 | import { FullscreenAction, SET_FULLSCREEN } from './actions'; 4 | 5 | export const initialState: FullscreenState = { 6 | isFullscreen: false, 7 | }; 8 | 9 | export const reducer: Reducer = (state, action) => { 10 | switch (action.type) { 11 | case SET_FULLSCREEN: 12 | return { ...state, isFullscreen: action.payload }; 13 | default: 14 | return state; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig, EventHook } from '@embedpdf/core'; 2 | 3 | export interface FullscreenState { 4 | isFullscreen: boolean; 5 | } 6 | 7 | export interface FullscreenPluginConfig extends BasePluginConfig {} 8 | 9 | export interface FullscreenCapability { 10 | isFullscreen: () => boolean; 11 | enableFullscreen: () => void; 12 | exitFullscreen: () => void; 13 | onRequest: EventHook<'enter' | 'exit'>; 14 | } 15 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './fullscreen'; 2 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-fullscreen'; 2 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/preact/hooks/use-fullscreen.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { FullscreenPlugin } from '@embedpdf/plugin-fullscreen'; 3 | 4 | export const useFullscreen = () => usePlugin(FullscreenPlugin.id); 5 | export const useFullscreenCapability = () => useCapability(FullscreenPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './fullscreen'; 2 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-fullscreen'; 2 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/react/hooks/use-fullscreen.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { FullscreenPlugin } from '@embedpdf/plugin-fullscreen'; 3 | 4 | export const useFullscreen = () => usePlugin(FullscreenPlugin.id); 5 | export const useFullscreenCapability = () => useCapability(FullscreenPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-fullscreen/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/lib/actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@embedpdf/core'; 2 | import { InteractionScope } from './types'; 3 | 4 | export const ACTIVATE_MODE = 'INTERACTION/ACTIVATE_MODE'; 5 | 6 | export interface ActivateModeAction extends Action { 7 | type: typeof ACTIVATE_MODE; 8 | payload: { mode: string }; 9 | } 10 | 11 | export const activateMode = (mode: string): ActivateModeAction => ({ 12 | type: ACTIVATE_MODE, 13 | payload: { mode }, 14 | }); 15 | 16 | export const SET_CURSOR = 'INTERACTION/SET_CURSOR'; 17 | export interface SetCursorAction extends Action { 18 | type: typeof SET_CURSOR; 19 | payload: { cursor: string }; 20 | } 21 | export const setCursor = (cursor: string): SetCursorAction => ({ 22 | type: SET_CURSOR, 23 | payload: { cursor }, 24 | }); 25 | 26 | export type InteractionManagerAction = ActivateModeAction | SetCursorAction; 27 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/lib/helper.ts: -------------------------------------------------------------------------------- 1 | import { PointerEventHandlers } from './types'; 2 | 3 | export function mergeHandlers(list: PointerEventHandlers[]): PointerEventHandlers { 4 | const keys: (keyof PointerEventHandlers)[] = [ 5 | 'onPointerDown', 6 | 'onPointerUp', 7 | 'onPointerMove', 8 | 'onPointerEnter', 9 | 'onPointerLeave', 10 | 'onPointerCancel', 11 | ]; 12 | const out: Partial = {}; 13 | for (const k of keys) { 14 | out[k] = (evt: any, nativeEvt: any) => { 15 | for (const h of list) h[k]?.(evt, nativeEvt); 16 | }; 17 | } 18 | return out as PointerEventHandlers; 19 | } 20 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { InteractionManagerPlugin } from './interaction-manager-plugin'; 4 | import { manifest, INTERACTION_MANAGER_PLUGIN_ID } from './manifest'; 5 | import { InteractionManagerPluginConfig, InteractionManagerState } from './types'; 6 | import { reducer, initialState } from './reducer'; 7 | import { InteractionManagerAction } from './actions'; 8 | 9 | export const InteractionManagerPluginPackage: PluginPackage< 10 | InteractionManagerPlugin, 11 | InteractionManagerPluginConfig, 12 | InteractionManagerState, 13 | InteractionManagerAction 14 | > = { 15 | manifest, 16 | create: (registry) => new InteractionManagerPlugin(INTERACTION_MANAGER_PLUGIN_ID, registry), 17 | reducer, 18 | initialState, 19 | }; 20 | 21 | export * from './interaction-manager-plugin'; 22 | export * from './types'; 23 | export * from './manifest'; 24 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { InteractionManagerPluginConfig } from './types'; 3 | 4 | export const INTERACTION_MANAGER_PLUGIN_ID = 'interaction-manager'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: INTERACTION_MANAGER_PLUGIN_ID, 8 | name: 'Interaction Manager Plugin', 9 | version: '1.0.0', 10 | provides: ['interaction-manager'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/lib/reducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from '@embedpdf/core'; 2 | import { ACTIVATE_MODE, InteractionManagerAction, SET_CURSOR } from './actions'; 3 | import { InteractionManagerState } from './types'; 4 | 5 | export const initialState: InteractionManagerState = { 6 | activeMode: 'default', 7 | cursor: 'auto', 8 | }; 9 | 10 | export const reducer: Reducer = ( 11 | state, 12 | action, 13 | ) => { 14 | switch (action.type) { 15 | case ACTIVATE_MODE: 16 | return { 17 | ...state, 18 | activeMode: action.payload.mode, 19 | }; 20 | case SET_CURSOR: 21 | return { 22 | ...state, 23 | cursor: action.payload.cursor, 24 | }; 25 | default: 26 | return state; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/preact/components/global-pointer-provider.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource preact */ 2 | import { ComponentChildren, JSX } from 'preact'; 3 | import { useEffect, useRef } from 'preact/hooks'; 4 | import { createPointerProvider } from '../../shared/utils'; 5 | 6 | import { useInteractionManagerCapability } from '../hooks'; 7 | 8 | interface GlobalPointerProviderProps extends JSX.HTMLAttributes { 9 | children: ComponentChildren; 10 | } 11 | 12 | export const GlobalPointerProvider = ({ children, ...props }: GlobalPointerProviderProps) => { 13 | const ref = useRef(null); 14 | const { provides: cap } = useInteractionManagerCapability(); 15 | 16 | useEffect(() => { 17 | if (!cap || !ref.current) return; 18 | 19 | return createPointerProvider(cap, { type: 'global' }, ref.current); 20 | }, [cap]); 21 | 22 | return ( 23 |
24 | {children} 25 |
26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './global-pointer-provider'; 2 | export * from './page-pointer-provider'; 3 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-interaction-manager'; 2 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './hooks'; 3 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-interaction-manager'; 2 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/react/hooks/use-interaction-manager.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { InteractionManagerPlugin } from '@embedpdf/plugin-interaction-manager'; 3 | 4 | export const useInteractionManager = () => 5 | usePlugin(InteractionManagerPlugin.id); 6 | export const useInteractionManagerCapability = () => 7 | useCapability(InteractionManagerPlugin.id); 8 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-interaction-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { LoaderPlugin } from './loader-plugin'; 3 | import { LOADER_PLUGIN_ID, manifest } from './manifest'; 4 | import { LoaderPluginConfig } from './types'; 5 | 6 | export const LoaderPluginPackage: PluginPackage = { 7 | manifest, 8 | create: (registry, engine) => new LoaderPlugin(LOADER_PLUGIN_ID, registry, engine), 9 | reducer: () => {}, 10 | initialState: {}, 11 | }; 12 | 13 | export * from './loader-plugin'; 14 | export * from './types'; 15 | export * from './manifest'; 16 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './strategies/loading-strategy'; 2 | export * from './document-loader'; 3 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/loader/strategies/buffer-strategy.ts: -------------------------------------------------------------------------------- 1 | import { PdfDocumentObject } from '@embedpdf/models'; 2 | import { PDFBufferLoadingOptions, PDFLoadingStrategy } from './loading-strategy'; 3 | 4 | export class BufferStrategy implements PDFLoadingStrategy { 5 | async load(loadingOptions: PDFBufferLoadingOptions): Promise { 6 | const { pdfFile, options, engine } = loadingOptions; 7 | 8 | const task = engine.openDocumentFromBuffer(pdfFile, options?.password || ''); 9 | 10 | return new Promise((resolve, reject) => { 11 | task.wait( 12 | // Success callback 13 | (result) => resolve(result), 14 | // Error callback 15 | (error) => { 16 | if (error.type === 'abort') { 17 | reject(new Error(`PDF loading aborted: ${error.reason}`)); 18 | } else { 19 | reject(new Error(`PDF loading failed: ${error.reason}`)); 20 | } 21 | }, 22 | ); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/loader/strategies/loading-strategy.ts: -------------------------------------------------------------------------------- 1 | import { PdfDocumentObject, PdfEngine, PdfFile, PdfFileUrl, PdfUrlOptions } from '@embedpdf/models'; 2 | 3 | export interface PDFUrlLoadingOptions { 4 | type: 'url'; 5 | pdfFile: PdfFileUrl; 6 | options?: PdfUrlOptions; 7 | engine: PdfEngine; 8 | } 9 | 10 | export interface PDFBufferLoadingOptions { 11 | type: 'buffer'; 12 | pdfFile: PdfFile; 13 | options?: { 14 | password?: string; 15 | }; 16 | engine: PdfEngine; 17 | } 18 | 19 | export type PDFLoadingOptions = PDFUrlLoadingOptions | PDFBufferLoadingOptions; 20 | 21 | export interface PDFLoadingStrategy { 22 | load(options?: PDFLoadingOptions): Promise; 23 | } 24 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/loader/strategies/url-strategy.ts: -------------------------------------------------------------------------------- 1 | import { PdfDocumentObject } from '@embedpdf/models'; 2 | import { PDFUrlLoadingOptions, PDFLoadingStrategy } from './loading-strategy'; 3 | 4 | export class UrlStrategy implements PDFLoadingStrategy { 5 | async load(loadingOptions: PDFUrlLoadingOptions): Promise { 6 | const { pdfFile, options, engine } = loadingOptions; 7 | 8 | const task = engine.openDocumentUrl(pdfFile, options); 9 | 10 | return new Promise((resolve, reject) => { 11 | task.wait( 12 | // Success callback 13 | (result) => resolve(result), 14 | // Error callback 15 | (error) => { 16 | if (error.type === 'abort') { 17 | reject(new Error(`PDF loading aborted: ${error.reason}`)); 18 | } else { 19 | reject(new Error(`PDF loading failed: ${error.reason}`)); 20 | } 21 | }, 22 | ); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { LoaderPluginConfig } from './types'; 3 | 4 | export const LOADER_PLUGIN_ID = 'loader'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: LOADER_PLUGIN_ID, 8 | name: 'Loader Plugin', 9 | version: '1.0.0', 10 | provides: ['loader'], 11 | requires: [], 12 | optional: [], 13 | metadata: { 14 | name: 'Loader Plugin', 15 | description: 'A plugin for loading PDF documents', 16 | version: '1.0.0', 17 | author: 'EmbedPDF', 18 | license: 'MIT', 19 | }, 20 | defaultConfig: { 21 | enabled: true, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig, EventHook } from '@embedpdf/core'; 2 | import { PdfDocumentObject } from '@embedpdf/models'; 3 | import { PDFLoadingStrategy, PDFLoadingOptions } from './loader/strategies/loading-strategy'; 4 | import { StrategyResolver } from './loader'; 5 | 6 | export interface LoaderPluginConfig extends BasePluginConfig { 7 | defaultStrategies?: { [key: string]: PDFLoadingStrategy }; 8 | loadingOptions?: Omit; 9 | } 10 | 11 | export interface LoaderEvent { 12 | type: 'start' | 'complete' | 'error'; 13 | documentId?: string; 14 | error?: Error; 15 | } 16 | 17 | export interface LoaderCapability { 18 | onLoaderEvent: EventHook; 19 | onDocumentLoaded: EventHook; 20 | onOpenFileRequest: EventHook<'open'>; 21 | loadDocument(options: Omit): Promise; 22 | registerStrategy(name: string, strategy: PDFLoadingStrategy): void; 23 | getDocument(): PdfDocumentObject | undefined; 24 | addStrategyResolver(resolver: StrategyResolver): void; 25 | openFileDialog: () => void; 26 | } 27 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './file-picker'; 2 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-loader'; 2 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/preact/hooks/use-loader.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { LoaderPlugin } from '@embedpdf/plugin-loader'; 3 | 4 | export const useLoader = () => usePlugin(LoaderPlugin.id); 5 | export const useLoaderCapability = () => useCapability(LoaderPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './file-picker'; 2 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-loader'; 2 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/react/hooks/use-loader.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { LoaderPlugin } from '@embedpdf/plugin-loader'; 3 | 4 | export const useLoader = () => usePlugin(LoaderPlugin.id); 5 | export const useLoaderCapability = () => useCapability(LoaderPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-loader/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-loader/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { PanPlugin } from './pan-plugin'; 4 | import { manifest, PAN_PLUGIN_ID } from './manifest'; 5 | import { PanPluginConfig } from './types'; 6 | 7 | export const PanPluginPackage: PluginPackage = { 8 | manifest, 9 | create: (registry) => new PanPlugin(PAN_PLUGIN_ID, registry), 10 | reducer: () => {}, 11 | initialState: {}, 12 | }; 13 | 14 | export * from './pan-plugin'; 15 | export * from './types'; 16 | export * from './manifest'; 17 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { PanPluginConfig } from './types'; 3 | 4 | export const PAN_PLUGIN_ID = 'pan'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: PAN_PLUGIN_ID, 8 | name: 'Pan Plugin', 9 | version: '1.0.0', 10 | provides: ['pan'], 11 | requires: ['interaction-manager'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig } from '@embedpdf/core'; 2 | 3 | export interface PanPluginConfig extends BasePluginConfig {} 4 | 5 | export interface PanCapability { 6 | enablePan: () => void; 7 | disablePan: () => void; 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './pan-mode'; 2 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-pan'; 2 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/preact/hooks/use-pan.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { PanPlugin } from '@embedpdf/plugin-pan'; 3 | 4 | export const usePan = () => usePlugin(PanPlugin.id); 5 | export const usePanCapability = () => useCapability(PanPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-pan'; 2 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/react/hooks/use-pan.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { PanPlugin } from '@embedpdf/plugin-pan'; 3 | 4 | export const usePan = () => usePlugin(PanPlugin.id); 5 | export const usePanCapability = () => useCapability(PanPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-pan/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-pan/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-print/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-print/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, PRINT_PLUGIN_ID } from './manifest'; 3 | import { PrintPluginConfig } from './types'; 4 | import { PrintPlugin } from './print-plugin'; 5 | 6 | export const PrintPluginPackage: PluginPackage = { 7 | manifest, 8 | create: (registry, _engine, config) => new PrintPlugin(PRINT_PLUGIN_ID, registry, config), 9 | reducer: () => {}, 10 | initialState: {}, 11 | }; 12 | 13 | export * from './print-plugin'; 14 | export * from './types'; 15 | export * from './manifest'; 16 | -------------------------------------------------------------------------------- /packages/plugin-print/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { PrintPluginConfig } from './types'; 3 | 4 | export const PRINT_PLUGIN_ID = 'print'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: PRINT_PLUGIN_ID, 8 | name: 'Print Plugin', 9 | version: '1.0.0', 10 | provides: ['print'], 11 | requires: ['render'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-print/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './print'; 2 | -------------------------------------------------------------------------------- /packages/plugin-print/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-print'; 2 | export * from './use-print-action'; 3 | -------------------------------------------------------------------------------- /packages/plugin-print/src/preact/hooks/use-print-action.ts: -------------------------------------------------------------------------------- 1 | import { PrintOptions } from '@embedpdf/plugin-print'; 2 | import { usePrintContext } from '../components'; 3 | 4 | export const usePrintAction = () => { 5 | const { executePrint, progress, isReady, isPrinting, parsePageRange } = usePrintContext(); 6 | 7 | return { 8 | executePrint, 9 | progress, 10 | isReady, 11 | isPrinting, 12 | parsePageRange, 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/plugin-print/src/preact/hooks/use-print.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { PrintPlugin } from '@embedpdf/plugin-print'; 3 | 4 | export const usePrint = () => usePlugin(PrintPlugin.id); 5 | export const usePrintCapability = () => useCapability(PrintPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-print/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-print/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-print/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-render/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-render/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { RenderPluginConfig } from './types'; 3 | import { RenderPlugin } from './render-plugin'; 4 | import { manifest, RENDER_PLUGIN_ID } from './manifest'; 5 | 6 | export const RenderPluginPackage: PluginPackage = { 7 | manifest, 8 | create: (registry, engine) => new RenderPlugin(RENDER_PLUGIN_ID, registry, engine), 9 | reducer: () => {}, 10 | initialState: {}, 11 | }; 12 | 13 | export * from './render-plugin'; 14 | export * from './types'; 15 | -------------------------------------------------------------------------------- /packages/plugin-render/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { RenderPluginConfig } from './types'; 3 | 4 | export const RENDER_PLUGIN_ID = 'render'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: RENDER_PLUGIN_ID, 8 | name: 'Render Plugin', 9 | version: '1.0.0', 10 | provides: ['render'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-render/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig } from '@embedpdf/core'; 2 | import { PdfErrorReason, Rect, Rotation, Task } from '@embedpdf/models'; 3 | 4 | export interface RenderPluginConfig extends BasePluginConfig {} 5 | 6 | export interface RenderPageRectOptions { 7 | pageIndex: number; 8 | scaleFactor?: number; 9 | rotation?: Rotation; 10 | dpr?: number; 11 | rect: Rect; 12 | options?: { 13 | withAnnotations: boolean; 14 | }; 15 | } 16 | 17 | export interface RenderPageOptions { 18 | pageIndex: number; 19 | scaleFactor?: number; 20 | dpr?: number; 21 | rotation?: Rotation; 22 | options?: { 23 | withAnnotations: boolean; 24 | }; 25 | } 26 | 27 | export interface RenderCapability { 28 | renderPage: (options: RenderPageOptions) => Task; 29 | renderPageRect: (options: RenderPageRectOptions) => Task; 30 | } 31 | -------------------------------------------------------------------------------- /packages/plugin-render/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './render-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-render/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-render'; 2 | -------------------------------------------------------------------------------- /packages/plugin-render/src/preact/hooks/use-render.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { RenderPlugin } from '@embedpdf/plugin-render'; 3 | 4 | export const useRender = () => usePlugin(RenderPlugin.id); 5 | export const useRenderCapability = () => useCapability(RenderPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-render/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-render/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-render/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './render-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-render/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-render'; 2 | -------------------------------------------------------------------------------- /packages/plugin-render/src/react/hooks/use-render.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { RenderPlugin } from '@embedpdf/plugin-render'; 3 | 4 | export const useRender = () => usePlugin(RenderPlugin.id); 5 | export const useRenderCapability = () => useCapability(RenderPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-render/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-render/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, ROTATE_PLUGIN_ID } from './manifest'; 3 | import { RotatePluginConfig } from './types'; 4 | import { RotatePlugin } from './rotate-plugin'; 5 | 6 | export const RotatePluginPackage: PluginPackage = { 7 | manifest, 8 | create: (registry, _engine, config) => new RotatePlugin(ROTATE_PLUGIN_ID, registry, config), 9 | reducer: () => {}, 10 | initialState: {}, 11 | }; 12 | 13 | export * from './rotate-plugin'; 14 | export * from './types'; 15 | export * from './manifest'; 16 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { RotatePluginConfig } from './types'; 3 | 4 | export const ROTATE_PLUGIN_ID = 'rotate'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: ROTATE_PLUGIN_ID, 8 | name: 'Rotate Plugin', 9 | version: '1.0.0', 10 | provides: ['rotate'], 11 | requires: ['loader'], 12 | optional: ['spread'], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig } from '@embedpdf/core'; 2 | import { Rotation } from '@embedpdf/models'; 3 | 4 | export interface RotatePluginConfig extends BasePluginConfig { 5 | defaultRotation?: Rotation; 6 | } 7 | 8 | export interface RotateCapability { 9 | onRotateChange(handler: (rotation: Rotation) => void): void; 10 | setRotation(rotation: Rotation): void; 11 | getRotation(): Rotation; 12 | rotateForward(): void; 13 | rotateBackward(): void; 14 | getMatrix(opts?: { 15 | w?: number; 16 | h?: number; 17 | asString?: boolean; 18 | }): string | [number, number, number, number, number, number]; 19 | } 20 | 21 | export interface RotateState { 22 | rotation: Rotation; 23 | } 24 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './rotate'; 2 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/preact/components/rotate.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource preact */ 2 | import { ComponentChildren, JSX } from 'preact'; 3 | import { Size } from '@embedpdf/models'; 4 | 5 | import { useRotateCapability } from '../hooks'; 6 | 7 | type RotateProps = JSX.HTMLAttributes & { 8 | children: ComponentChildren; 9 | pageSize: Size; 10 | }; 11 | 12 | export function Rotate({ children, pageSize, ...props }: RotateProps) { 13 | const { provides: rotate } = useRotateCapability(); 14 | const matrix = 15 | (rotate?.getMatrix({ 16 | w: pageSize.width, 17 | h: pageSize.height, 18 | }) as string) || 'matrix(1, 0, 0, 1, 0, 0)'; 19 | 20 | return ( 21 |
29 | {children} 30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-rotate'; 2 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/preact/hooks/use-rotate.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { RotatePlugin } from '@embedpdf/plugin-rotate'; 3 | 4 | export const useRotate = () => usePlugin(RotatePlugin.id); 5 | export const useRotateCapability = () => useCapability(RotatePlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './rotate'; 2 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/react/components/rotate.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { Size } from '@embedpdf/models'; 3 | 4 | import { useRotateCapability } from '../hooks'; 5 | 6 | type RotateProps = React.HTMLAttributes & { 7 | children: ReactNode; 8 | pageSize: Size; 9 | }; 10 | 11 | export function Rotate({ children, pageSize, ...props }: RotateProps) { 12 | const { provides: rotate } = useRotateCapability(); 13 | const matrix = 14 | (rotate?.getMatrix({ 15 | w: pageSize.width, 16 | h: pageSize.height, 17 | }) as string) || 'matrix(1, 0, 0, 1, 0, 0)'; 18 | 19 | return ( 20 |
28 | {children} 29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-rotate'; 2 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/react/hooks/use-rotate.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { RotatePlugin } from '@embedpdf/plugin-rotate'; 3 | 4 | export const useRotate = () => usePlugin(RotatePlugin.id); 5 | export const useRotateCapability = () => useCapability(RotatePlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-rotate/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-rotate/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/lib/actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@embedpdf/core'; 2 | import { ScrollState } from './types'; 3 | 4 | export const UPDATE_SCROLL_STATE = 'UPDATE_SCROLL_STATE'; 5 | export const SET_DESIRED_SCROLL_POSITION = 'SET_DESIRED_SCROLL_POSITION'; 6 | 7 | export interface UpdateScrollStateAction extends Action { 8 | type: typeof UPDATE_SCROLL_STATE; 9 | payload: Partial; 10 | } 11 | 12 | export interface SetDesiredScrollPositionAction extends Action { 13 | type: typeof SET_DESIRED_SCROLL_POSITION; 14 | payload: { x: number; y: number }; 15 | } 16 | 17 | export type ScrollAction = UpdateScrollStateAction | SetDesiredScrollPositionAction; 18 | 19 | export function updateScrollState(payload: Partial): UpdateScrollStateAction { 20 | return { type: UPDATE_SCROLL_STATE, payload }; 21 | } 22 | 23 | export function setDesiredScrollPosition(payload: { 24 | x: number; 25 | y: number; 26 | }): SetDesiredScrollPositionAction { 27 | return { type: SET_DESIRED_SCROLL_POSITION, payload }; 28 | } 29 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { ScrollPlugin } from './scroll-plugin'; 3 | import { manifest, SCROLL_PLUGIN_ID } from './manifest'; 4 | import { ScrollPluginConfig, ScrollState } from './types'; 5 | import { scrollReducer, initialState } from './reducer'; 6 | import { ScrollAction } from './actions'; 7 | 8 | export const ScrollPluginPackage: PluginPackage< 9 | ScrollPlugin, 10 | ScrollPluginConfig, 11 | ScrollState, 12 | ScrollAction 13 | > = { 14 | manifest, 15 | create: (registry, _engine, config) => new ScrollPlugin(SCROLL_PLUGIN_ID, registry, config), 16 | reducer: scrollReducer, 17 | initialState: (coreState, config) => initialState(coreState, config), 18 | }; 19 | 20 | export * from './scroll-plugin'; 21 | export * from './types'; 22 | export * from './manifest'; 23 | export * from './types/virtual-item'; 24 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { ScrollPluginConfig } from './types'; 3 | 4 | export const SCROLL_PLUGIN_ID = 'scroll'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: SCROLL_PLUGIN_ID, 8 | name: 'Scroll Plugin', 9 | version: '1.0.0', 10 | provides: ['scroll'], 11 | requires: ['viewport'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | pageGap: 10, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/lib/selectors.ts: -------------------------------------------------------------------------------- 1 | import { ScrollerLayout, ScrollState } from './types'; 2 | 3 | export const getScrollerLayout = (state: ScrollState, scale: number): ScrollerLayout => { 4 | return { 5 | startSpacing: state.startSpacing, 6 | endSpacing: state.endSpacing, 7 | totalWidth: state.totalContentSize.width * scale, 8 | totalHeight: state.totalContentSize.height * scale, 9 | pageGap: state.pageGap * scale, 10 | strategy: state.strategy, 11 | items: state.renderedPageIndexes.map((idx) => { 12 | return { 13 | ...state.virtualItems[idx], 14 | pageLayouts: state.virtualItems[idx].pageLayouts.map((layout) => { 15 | return { 16 | ...layout, 17 | rotatedWidth: layout.rotatedWidth * scale, 18 | rotatedHeight: layout.rotatedHeight * scale, 19 | width: layout.width * scale, 20 | height: layout.height * scale, 21 | }; 22 | }), 23 | }; 24 | }), 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/lib/types/virtual-item.ts: -------------------------------------------------------------------------------- 1 | export interface PageLayout { 2 | pageNumber: number; 3 | pageIndex: number; 4 | x: number; // Relative to item, in original coordinates 5 | y: number; 6 | width: number; 7 | height: number; 8 | rotatedWidth: number; 9 | rotatedHeight: number; 10 | } 11 | 12 | export interface VirtualItem { 13 | id: string; 14 | x: number; // In original coordinates 15 | y: number; 16 | offset: number; 17 | width: number; 18 | height: number; 19 | pageLayouts: PageLayout[]; 20 | pageNumbers: number[]; 21 | index: number; 22 | } 23 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './scroller'; 2 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-scroll'; 2 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/preact/hooks/use-scroll.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { ScrollPlugin } from '@embedpdf/plugin-scroll'; 3 | 4 | export const useScroll = () => usePlugin(ScrollPlugin.id); 5 | export const useScrollCapability = () => useCapability(ScrollPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './scroller'; 2 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-scroll'; 2 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/react/hooks/use-scroll.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { ScrollPlugin } from '@embedpdf/plugin-scroll'; 3 | 4 | export const useScroll = () => usePlugin(ScrollPlugin.id); 5 | export const useScrollCapability = () => useCapability(ScrollPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-scroll/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-scroll/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-search/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-search/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { SearchPlugin } from './search-plugin'; 3 | import { manifest, SEARCH_PLUGIN_ID } from './manifest'; 4 | import { SearchPluginConfig, SearchState } from './types'; 5 | import { searchReducer, initialState } from './reducer'; 6 | import { SearchAction } from './actions'; 7 | 8 | export const SearchPluginPackage: PluginPackage< 9 | SearchPlugin, 10 | SearchPluginConfig, 11 | SearchState, 12 | SearchAction 13 | > = { 14 | manifest, 15 | create: (registry, engine) => new SearchPlugin(SEARCH_PLUGIN_ID, registry, engine), 16 | reducer: searchReducer, 17 | initialState, 18 | }; 19 | 20 | export * from './search-plugin'; 21 | export * from './types'; 22 | export * from './manifest'; 23 | export { initialState }; 24 | -------------------------------------------------------------------------------- /packages/plugin-search/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { SearchPluginConfig } from './types'; 3 | 4 | export const SEARCH_PLUGIN_ID = 'search'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: SEARCH_PLUGIN_ID, 8 | name: 'Search Plugin', 9 | version: '1.0.0', 10 | provides: ['search'], 11 | requires: ['loader'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | flags: [], 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/plugin-search/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './search-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-search/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-search'; 2 | -------------------------------------------------------------------------------- /packages/plugin-search/src/preact/hooks/use-search.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { SearchPlugin } from '@embedpdf/plugin-search'; 3 | 4 | export const useSearch = () => usePlugin(SearchPlugin.id); 5 | export const useSearchCapability = () => useCapability(SearchPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-search/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-search/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-search/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './search-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-search/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-search'; 2 | -------------------------------------------------------------------------------- /packages/plugin-search/src/react/hooks/use-search.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { SearchPlugin } from '@embedpdf/plugin-search'; 3 | 4 | export const useSearch = () => usePlugin(SearchPlugin.id); 5 | export const useSearchCapability = () => useCapability(SearchPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-search/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-search/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, SELECTION_PLUGIN_ID } from './manifest'; 3 | import { SelectionPluginConfig, SelectionState } from './types'; 4 | 5 | import { SelectionPlugin } from './selection-plugin'; 6 | import { SelectionAction } from './actions'; 7 | import { selectionReducer, initialState } from './reducer'; 8 | 9 | export const SelectionPluginPackage: PluginPackage< 10 | SelectionPlugin, 11 | SelectionPluginConfig, 12 | SelectionState, 13 | SelectionAction 14 | > = { 15 | manifest, 16 | create: (registry, engine) => new SelectionPlugin(SELECTION_PLUGIN_ID, registry, engine), 17 | reducer: selectionReducer, 18 | initialState, 19 | }; 20 | 21 | export * from './selection-plugin'; 22 | export * from './types'; 23 | export * from './manifest'; 24 | export * from './utils'; 25 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { SelectionPluginConfig } from './types'; 3 | 4 | export const SELECTION_PLUGIN_ID = 'selection'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: SELECTION_PLUGIN_ID, 8 | name: 'Selection Plugin', 9 | version: '1.0.0', 10 | provides: ['selection'], 11 | requires: ['interaction-manager'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/lib/selectors.ts: -------------------------------------------------------------------------------- 1 | import { Rect, boundingRect } from '@embedpdf/models'; 2 | import { SelectionState } from './types'; 3 | 4 | export function selectRectsForPage(state: SelectionState, page: number) { 5 | return state.rects[page] ?? []; 6 | } 7 | 8 | export function selectBoundingRectForPage(state: SelectionState, page: number) { 9 | return boundingRect(selectRectsForPage(state, page)); 10 | } 11 | 12 | export function selectBoundingRectsForAllPages(state: SelectionState) { 13 | const out: { page: number; rect: Rect }[] = []; 14 | const rectMap = state.rects; 15 | 16 | for (const key in rectMap) { 17 | const page = Number(key); 18 | const bRect = boundingRect(rectMap[page]); 19 | if (bRect) out.push({ page, rect: bRect }); 20 | } 21 | return out; 22 | } 23 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { PdfPageGeometry, Rect } from '@embedpdf/models'; 2 | 3 | /** 4 | * Hit-test helper using runs 5 | * @param geo - page geometry 6 | * @param pt - point 7 | * @returns glyph index 8 | */ 9 | export function glyphAt(geo: PdfPageGeometry, pt: { x: number; y: number }) { 10 | for (const run of geo.runs) { 11 | const inRun = 12 | pt.y >= run.rect.y && 13 | pt.y <= run.rect.y + run.rect.height && 14 | pt.x >= run.rect.x && 15 | pt.x <= run.rect.x + run.rect.width; 16 | 17 | if (!inRun) continue; 18 | 19 | // Simply check if the point is within any glyph's bounding box 20 | const rel = run.glyphs.findIndex( 21 | (g) => pt.x >= g.x && pt.x <= g.x + g.width && pt.y >= g.y && pt.y <= g.y + g.height, 22 | ); 23 | 24 | if (rel !== -1) { 25 | return run.charStart + rel; 26 | } 27 | } 28 | return -1; 29 | } 30 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './selection-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-selection'; 2 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/preact/hooks/use-selection.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { SelectionPlugin } from '@embedpdf/plugin-selection'; 3 | 4 | export const useSelectionCapability = () => useCapability(SelectionPlugin.id); 5 | export const useSelection = () => usePlugin(SelectionPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-selection/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-selection/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/lib/actions.ts: -------------------------------------------------------------------------------- 1 | import { SpreadMode } from './types'; 2 | 3 | export const SET_SPREAD_MODE = 'SET_SPREAD_MODE'; 4 | 5 | export interface SetSpreadModeAction { 6 | type: typeof SET_SPREAD_MODE; 7 | payload: SpreadMode; 8 | } 9 | 10 | export type SpreadAction = SetSpreadModeAction; 11 | 12 | export function setSpreadMode(mode: SpreadMode): SetSpreadModeAction { 13 | return { 14 | type: SET_SPREAD_MODE, 15 | payload: mode, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { SpreadPlugin } from './spread-plugin'; 3 | import { manifest, SPREAD_PLUGIN_ID } from './manifest'; 4 | import { SpreadPluginConfig, SpreadState } from './types'; 5 | import { spreadReducer, initialState } from './reducer'; 6 | import { SpreadAction } from './actions'; 7 | 8 | export const SpreadPluginPackage: PluginPackage< 9 | SpreadPlugin, 10 | SpreadPluginConfig, 11 | SpreadState, 12 | SpreadAction 13 | > = { 14 | manifest, 15 | create: (registry, _engine, config) => new SpreadPlugin(SPREAD_PLUGIN_ID, registry, config), 16 | reducer: spreadReducer, 17 | initialState, 18 | }; 19 | 20 | export * from './spread-plugin'; 21 | export * from './types'; 22 | export * from './manifest'; 23 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { SpreadPluginConfig } from './types'; 3 | 4 | export const SPREAD_PLUGIN_ID = 'spread'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: SPREAD_PLUGIN_ID, 8 | name: 'Spread Plugin', 9 | version: '1.0.0', 10 | provides: ['spread'], 11 | requires: ['loader'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/lib/reducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from '@embedpdf/core'; 2 | import { SpreadState, SpreadMode } from './types'; 3 | import { SET_SPREAD_MODE, SetSpreadModeAction } from './actions'; 4 | 5 | export const initialState: SpreadState = { 6 | spreadMode: SpreadMode.None, 7 | }; 8 | 9 | export const spreadReducer: Reducer = ( 10 | state = initialState, 11 | action, 12 | ) => { 13 | switch (action.type) { 14 | case SET_SPREAD_MODE: 15 | return { 16 | ...state, 17 | spreadMode: action.payload, 18 | }; 19 | default: 20 | return state; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfig, EventHook } from '@embedpdf/core'; 2 | import { PdfPageObject } from '@embedpdf/models'; 3 | 4 | export interface SpreadPluginConfig extends BasePluginConfig { 5 | defaultSpreadMode?: SpreadMode; 6 | } 7 | 8 | export enum SpreadMode { 9 | None = 'none', 10 | Odd = 'odd', 11 | Even = 'even', 12 | } 13 | 14 | export interface SpreadCapability { 15 | onSpreadChange: EventHook; 16 | setSpreadMode(mode: SpreadMode): void; 17 | getSpreadMode(): SpreadMode; 18 | getSpreadPagesObjects(pages: PdfPageObject[]): PdfPageObject[][]; 19 | } 20 | 21 | export interface SpreadState { 22 | spreadMode: SpreadMode; 23 | } 24 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-spread'; 2 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/preact/hooks/use-spread.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { SpreadPlugin } from '@embedpdf/plugin-spread'; 3 | 4 | export const useSpread = () => usePlugin(SpreadPlugin.id); 5 | export const useSpreadCapability = () => useCapability(SpreadPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-spread'; 2 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/react/hooks/use-spread.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { SpreadPlugin } from '@embedpdf/plugin-spread'; 3 | 4 | export const useSpread = () => usePlugin(SpreadPlugin.id); 5 | export const useSpreadCapability = () => useCapability(SpreadPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-spread/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | -------------------------------------------------------------------------------- /packages/plugin-spread/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { manifest, THUMBNAIL_PLUGIN_ID } from './manifest'; 3 | import { ThumbnailPluginConfig } from './types'; 4 | import { ThumbnailPlugin } from './thumbnail-plugin'; 5 | 6 | export const ThumbnailPluginPackage: PluginPackage = { 7 | manifest, 8 | create: (registry, _engine, config) => new ThumbnailPlugin(THUMBNAIL_PLUGIN_ID, registry, config), 9 | reducer: () => {}, 10 | initialState: {}, 11 | }; 12 | 13 | export * from './thumbnail-plugin'; 14 | export * from './types'; 15 | export * from './manifest'; 16 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { ThumbnailPluginConfig } from './types'; 3 | 4 | export const THUMBNAIL_PLUGIN_ID = 'thumbnail'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: THUMBNAIL_PLUGIN_ID, 8 | name: 'Thumbnail Plugin', 9 | version: '1.0.0', 10 | provides: ['thumbnail'], 11 | requires: ['render'], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | width: 150, 16 | gap: 10, 17 | buffer: 3, 18 | labelHeight: 16, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './thumbnails-pane'; 2 | export * from './thumbnail-img'; 3 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-thumbnail'; 2 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/preact/hooks/use-thumbnail.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail'; 3 | 4 | export const useThumbnail = () => usePlugin(ThumbnailPlugin.id); 5 | export const useThumbnailCapability = () => useCapability(ThumbnailPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-thumbnail/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/lib/actions.ts: -------------------------------------------------------------------------------- 1 | import { Tile, TileStatus } from './types'; 2 | 3 | export const UPDATE_VISIBLE_TILES = 'UPDATE_VISIBLE_TILES'; 4 | export const MARK_TILE_STATUS = 'MARK_TILE_STATUS'; 5 | 6 | export type UpdateVisibleTilesAction = { 7 | type: typeof UPDATE_VISIBLE_TILES; 8 | payload: Record; 9 | }; 10 | 11 | export type MarkTileStatusAction = { 12 | type: typeof MARK_TILE_STATUS; 13 | payload: { pageIndex: number; tileId: string; status: TileStatus }; 14 | }; 15 | 16 | export type TilingAction = UpdateVisibleTilesAction | MarkTileStatusAction; 17 | 18 | export const updateVisibleTiles = (tiles: Record): UpdateVisibleTilesAction => ({ 19 | type: UPDATE_VISIBLE_TILES, 20 | payload: tiles, 21 | }); 22 | 23 | export const markTileStatus = ( 24 | pageIndex: number, 25 | tileId: string, 26 | status: TileStatus, 27 | ): MarkTileStatusAction => ({ type: MARK_TILE_STATUS, payload: { pageIndex, tileId, status } }); 28 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { TilingAction } from './actions'; 4 | import { manifest, TILING_PLUGIN_ID } from './manifest'; 5 | import { initialState, tilingReducer } from './reducer'; 6 | import { TilingPlugin } from './tiling-plugin'; 7 | import { TilingPluginConfig, TilingState } from './types'; 8 | 9 | export const TilingPluginPackage: PluginPackage< 10 | TilingPlugin, 11 | TilingPluginConfig, 12 | TilingState, 13 | TilingAction 14 | > = { 15 | manifest, 16 | create: (registry, _engine, config) => new TilingPlugin(TILING_PLUGIN_ID, registry, config), 17 | reducer: (state, action) => tilingReducer(state, action), 18 | initialState, 19 | }; 20 | 21 | export * from './tiling-plugin'; 22 | export * from './types'; 23 | export * from './manifest'; 24 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | 3 | import { TilingPluginConfig } from './types'; 4 | 5 | export const TILING_PLUGIN_ID = 'tiling'; 6 | 7 | export const manifest: PluginManifest = { 8 | id: TILING_PLUGIN_ID, 9 | name: 'Tiling Plugin', 10 | version: '1.0.0', 11 | provides: ['tiling'], 12 | requires: ['render', 'scroll', 'viewport'], 13 | optional: [], 14 | defaultConfig: { 15 | enabled: true, 16 | tileSize: 768, 17 | overlapPx: 2.5, 18 | extraRings: 0, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tiling-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-tiling'; 2 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/preact/hooks/use-tiling.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { TilingPlugin } from '@embedpdf/plugin-tiling'; 3 | 4 | export const useTiling = () => usePlugin(TilingPlugin.id); 5 | export const useTilingCapability = () => useCapability(TilingPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tiling-layer'; 2 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-tiling'; 2 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/react/hooks/use-tiling.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { TilingPlugin } from '@embedpdf/plugin-tiling'; 3 | 4 | export const useTiling = () => usePlugin(TilingPlugin.id); 5 | export const useTilingCapability = () => useCapability(TilingPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-tiling/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-tiling/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/lib/icons/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents an icon in the icon registry 3 | */ 4 | export interface Icon { 5 | id: string; 6 | svg: string; 7 | } 8 | 9 | /** 10 | * Record type for icon registry 11 | */ 12 | export type IconRegistry = Record; 13 | 14 | /** 15 | * An identifier for an icon that can be either a registered icon id or raw SVG 16 | */ 17 | export type IconIdentifier = string; 18 | 19 | /** 20 | * Options for rendering an icon 21 | */ 22 | export interface IconRenderOptions { 23 | className?: string; 24 | title?: string; 25 | } 26 | 27 | /** 28 | * Capabilities for the IconManager 29 | */ 30 | export interface IconCapabilities { 31 | registerIcon: (icon: Icon) => void; 32 | registerIcons: (icons: Icon[] | IconRegistry) => void; 33 | getIcon: (id: string) => Icon | undefined; 34 | getAllIcons: () => IconRegistry; 35 | getSvgString: (identifier: IconIdentifier) => string | undefined; 36 | isSvgString: (identifier: IconIdentifier) => boolean; 37 | isSvgDataUri: (value: string) => boolean; 38 | dataUriToSvgString: (dataUri: string) => string; 39 | svgStringToDataUri: (svgString: string) => string; 40 | } 41 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | import { UIPlugin } from './ui-plugin'; 3 | import { manifest, UI_PLUGIN_ID } from './manifest'; 4 | import { UIPluginConfig, UIPluginState } from './types'; 5 | import { uiReducer, initialState } from './reducer'; 6 | import { UIPluginAction } from './actions'; 7 | 8 | export const UIPluginPackage: PluginPackage< 9 | UIPlugin, 10 | UIPluginConfig, 11 | UIPluginState, 12 | UIPluginAction 13 | > = { 14 | manifest, 15 | create: (registry, _engine, config) => new UIPlugin(UI_PLUGIN_ID, registry, config!), 16 | reducer: uiReducer, 17 | initialState, 18 | }; 19 | 20 | export * from './manifest'; 21 | export * from './ui-plugin'; 22 | export * from './types'; 23 | export * from './ui-component'; 24 | export * from './utils'; 25 | export * from './menu/types'; 26 | export * from './icons/types'; 27 | export * from './menu/utils'; 28 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | import { UIPluginConfig } from './types'; 3 | 4 | export const UI_PLUGIN_ID = 'ui'; 5 | 6 | export const manifest: PluginManifest = { 7 | id: UI_PLUGIN_ID, 8 | name: 'UI Plugin', 9 | version: '1.0.0', 10 | provides: ['ui'], 11 | requires: [], 12 | optional: [], 13 | defaultConfig: { 14 | enabled: true, 15 | components: {}, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugin-ui-provider'; 2 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-ui'; 2 | export * from './use-icon'; 3 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/preact/hooks/use-icon.ts: -------------------------------------------------------------------------------- 1 | import { useUICapability } from './use-ui'; 2 | import { IconIdentifier, Icon as IconType, IconRegistry } from '@embedpdf/plugin-ui'; 3 | 4 | /** 5 | * Hook to access icon functionality in React 6 | */ 7 | export function useIcon() { 8 | const { provides: uiProvides } = useUICapability(); 9 | 10 | if (!uiProvides) { 11 | throw new Error('useIcon must be used within a UI context'); 12 | } 13 | 14 | const { 15 | registerIcon, 16 | registerIcons, 17 | getIcon, 18 | getAllIcons, 19 | getSvgString, 20 | isSvgString, 21 | isSvgDataUri, 22 | dataUriToSvgString, 23 | svgStringToDataUri, 24 | } = uiProvides; 25 | 26 | return { 27 | registerIcon, 28 | registerIcons, 29 | getIcon, 30 | getAllIcons, 31 | getSvgString, 32 | isSvgString, 33 | isSvgDataUri, 34 | dataUriToSvgString, 35 | svgStringToDataUri, 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/preact/hooks/use-ui.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { UIPlugin } from '@embedpdf/plugin-ui'; 3 | 4 | export const useUI = () => usePlugin(UIPlugin.id); 5 | export const useUICapability = () => useCapability(UIPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './hooks'; 3 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-ui/src/react/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/packages/plugin-ui/src/react/index.ts -------------------------------------------------------------------------------- /packages/plugin-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { ViewportAction } from './actions'; 4 | import { manifest, VIEWPORT_PLUGIN_ID } from './manifest'; 5 | import { viewportReducer, initialState } from './reducer'; 6 | import { ViewportPluginConfig, ViewportState } from './types'; 7 | import { ViewportPlugin } from './viewport-plugin'; 8 | 9 | export const ViewportPluginPackage: PluginPackage< 10 | ViewportPlugin, 11 | ViewportPluginConfig, 12 | ViewportState, 13 | ViewportAction 14 | > = { 15 | manifest, 16 | create: (registry, _engine, config) => new ViewportPlugin(VIEWPORT_PLUGIN_ID, registry, config), 17 | reducer: viewportReducer, 18 | initialState: initialState, 19 | }; 20 | 21 | export * from './viewport-plugin'; 22 | export * from './types'; 23 | export * from './manifest'; 24 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/lib/manifest.ts: -------------------------------------------------------------------------------- 1 | import { PluginManifest } from '@embedpdf/core'; 2 | 3 | import { ViewportPluginConfig } from './types'; 4 | 5 | export const VIEWPORT_PLUGIN_ID = 'viewport'; 6 | 7 | export const manifest: PluginManifest = { 8 | id: VIEWPORT_PLUGIN_ID, 9 | name: 'Viewport Plugin', 10 | version: '1.0.0', 11 | provides: ['viewport'], 12 | requires: [], 13 | optional: [], 14 | defaultConfig: { 15 | enabled: true, 16 | viewportGap: 10, 17 | scrollEndDelay: 300, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viewport'; 2 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/preact/components/viewport.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource preact */ 2 | import { ComponentChildren, JSX } from 'preact'; 3 | import { useEffect, useState } from 'preact/hooks'; 4 | 5 | import { useViewportCapability } from '../hooks'; 6 | import { useViewportRef } from '../hooks/use-viewport-ref'; 7 | 8 | type ViewportProps = JSX.HTMLAttributes & { 9 | children: ComponentChildren; 10 | }; 11 | 12 | export function Viewport({ children, ...props }: ViewportProps) { 13 | const [viewportGap, setViewportGap] = useState(0); 14 | const viewportRef = useViewportRef(); 15 | const { provides: viewportProvides } = useViewportCapability(); 16 | 17 | useEffect(() => { 18 | if (viewportProvides) { 19 | setViewportGap(viewportProvides.getViewportGap()); 20 | } 21 | }, [viewportProvides]); 22 | 23 | const { style, ...restProps } = props; 24 | return ( 25 |
33 | {children} 34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-viewport'; 2 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/preact/hooks/use-viewport.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { ViewportPlugin } from '@embedpdf/plugin-viewport'; 3 | 4 | export const useViewport = () => usePlugin(ViewportPlugin.id); 5 | export const useViewportCapability = () => useCapability(ViewportPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/react/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viewport'; 2 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/react/components/viewport.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode, useEffect, useState } from 'react'; 2 | 3 | import { useViewportCapability } from '../hooks'; 4 | import { useViewportRef } from '../hooks/use-viewport-ref'; 5 | 6 | type ViewportProps = React.HTMLAttributes & { 7 | children: ReactNode; 8 | }; 9 | 10 | export function Viewport({ children, ...props }: ViewportProps) { 11 | const [viewportGap, setViewportGap] = useState(0); 12 | const viewportRef = useViewportRef(); 13 | const { provides: viewportProvides } = useViewportCapability(); 14 | 15 | useEffect(() => { 16 | if (viewportProvides) { 17 | setViewportGap(viewportProvides.getViewportGap()); 18 | } 19 | }, [viewportProvides]); 20 | 21 | const { style, ...restProps } = props; 22 | return ( 23 |
31 | {children} 32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/react/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-viewport'; 2 | export * from './use-viewport-ref'; 3 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/react/hooks/use-viewport.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/react'; 2 | import { ViewportPlugin } from '@embedpdf/plugin-viewport'; 3 | 4 | export const useViewport = () => usePlugin(ViewportPlugin.id); 5 | export const useViewportCapability = () => useCapability(ViewportPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-viewport/src/react/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './hooks'; 3 | -------------------------------------------------------------------------------- /packages/plugin-viewport/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginPackage } from '@embedpdf/core'; 2 | 3 | import { ZoomAction } from './actions'; 4 | import { manifest, ZOOM_PLUGIN_ID } from './manifest'; 5 | import { zoomReducer, initialState } from './reducer'; 6 | import { ZoomPluginConfig, ZoomState } from './types'; 7 | import { ZoomPlugin } from './zoom-plugin'; 8 | 9 | export const ZoomPluginPackage: PluginPackage = 10 | { 11 | manifest, 12 | create: (registry, _engine, config) => new ZoomPlugin(ZOOM_PLUGIN_ID, registry, config), 13 | reducer: zoomReducer, 14 | initialState, 15 | }; 16 | 17 | export * from './zoom-plugin'; 18 | export * from './types'; 19 | export * from './manifest'; 20 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/lib/reducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from '@embedpdf/core'; 2 | 3 | import { SET_INITIAL_ZOOM_LEVEL, SET_ZOOM_LEVEL, ZoomAction } from './actions'; 4 | import { ZoomState, ZoomMode } from './types'; 5 | 6 | export const initialState: ZoomState = { 7 | zoomLevel: ZoomMode.Automatic, 8 | currentZoomLevel: 1, 9 | zoomReady: false, 10 | }; 11 | 12 | export const zoomReducer: Reducer = (state = initialState, action) => { 13 | switch (action.type) { 14 | case SET_ZOOM_LEVEL: 15 | return { 16 | ...state, 17 | zoomLevel: action.payload.zoomLevel, 18 | currentZoomLevel: action.payload.currentZoomLevel, 19 | zoomReady: true, 20 | }; 21 | case SET_INITIAL_ZOOM_LEVEL: 22 | return { 23 | ...state, 24 | zoomLevel: action.payload.zoomLevel, 25 | }; 26 | default: 27 | return state; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/preact/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './pinch-wrapper'; 2 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/preact/components/pinch-wrapper.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource preact */ 2 | import { ComponentChildren, JSX } from 'preact'; 3 | import { usePinch } from '../hooks'; 4 | 5 | type PinchWrapperProps = Omit, 'style'> & { 6 | children: ComponentChildren; 7 | style?: JSX.CSSProperties; 8 | }; 9 | 10 | export function PinchWrapper({ children, style, ...props }: PinchWrapperProps) { 11 | const { elementRef } = usePinch(); 12 | 13 | return ( 14 |
26 | {children} 27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/preact/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-zoom'; 2 | export * from './use-pinch-zoom'; 3 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/preact/hooks/use-zoom.ts: -------------------------------------------------------------------------------- 1 | import { useCapability, usePlugin } from '@embedpdf/core/preact'; 2 | import { ZoomPlugin } from '@embedpdf/plugin-zoom'; 3 | 4 | export const useZoomCapability = () => useCapability(ZoomPlugin.id); 5 | export const useZoom = () => usePlugin(ZoomPlugin.id); 6 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/preact/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /packages/plugin-zoom/src/preact/tsconfig.preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact" 6 | }, 7 | "include": ["./**/*.ts", "./**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-zoom/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "jsx": "react-jsx", 12 | "jsxImportSource": "react", 13 | "rootDir": "src", 14 | "paths": { 15 | "preact": ["./node_modules/preact"], 16 | "preact/hooks": ["./node_modules/preact/hooks"] 17 | } 18 | }, 19 | "include": ["src"], 20 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | # include packages in subfolders (change as required) 3 | - 'packages/**' 4 | - 'examples/**' 5 | - 'website' 6 | - 'snippet' -------------------------------------------------------------------------------- /snippet/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/env", 4 | ["@babel/react", { 5 | "pragma": "h", 6 | "pragmaFrag": "Fragment" 7 | }], 8 | "@babel/preset-typescript" 9 | ] 10 | } -------------------------------------------------------------------------------- /snippet/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .env -------------------------------------------------------------------------------- /snippet/demo-pdf/demo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/snippet/demo-pdf/demo.pdf -------------------------------------------------------------------------------- /snippet/demo-pdf/ebook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/snippet/demo-pdf/ebook.pdf -------------------------------------------------------------------------------- /snippet/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('@tailwindcss/postcss') 4 | ] 5 | } -------------------------------------------------------------------------------- /snippet/src/components/loader-local.ts: -------------------------------------------------------------------------------- 1 | import { PdfiumEngine } from '@embedpdf/engines/pdfium'; 2 | import { init } from '@embedpdf/pdfium'; 3 | 4 | export async function createLocalEngine(wasmUrl: string): Promise { 5 | const response = await fetch(wasmUrl); 6 | const wasmBinary = await response.arrayBuffer(); 7 | const wasmModule = await init({ wasmBinary }); 8 | return new PdfiumEngine(wasmModule); 9 | } 10 | -------------------------------------------------------------------------------- /snippet/src/components/loader-worker.ts: -------------------------------------------------------------------------------- 1 | import { WebWorkerEngine } from '@embedpdf/engines/worker'; 2 | 3 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 4 | // @ts-ignore injected at build time 5 | declare const __WEBWORKER_BODY__: string; 6 | 7 | /** Builds a Worker without any network request. */ 8 | export function createWorkerEngine(wasmUrl: string): WebWorkerEngine { 9 | const worker = new Worker( 10 | URL.createObjectURL(new Blob([__WEBWORKER_BODY__], { type: 'application/javascript' })), 11 | { 12 | type: 'module', 13 | }, 14 | ); 15 | 16 | // Send initialization message with WASM URL 17 | worker.postMessage({ type: 'INIT_WASM', wasmUrl }); 18 | 19 | return new WebWorkerEngine(worker); 20 | } 21 | -------------------------------------------------------------------------------- /snippet/src/components/toolbar.tsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/snippet/src/components/toolbar.tsx -------------------------------------------------------------------------------- /snippet/src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import { h, ComponentChildren, Ref, JSX } from 'preact'; 2 | 3 | type ButtonProps = JSX.ButtonHTMLAttributes & { 4 | id?: string; 5 | children: ComponentChildren; 6 | onClick?: h.JSX.MouseEventHandler | undefined; 7 | active?: boolean; 8 | className?: string; 9 | tooltip?: string; 10 | ref?: Ref; 11 | }; 12 | 13 | export function Button({ 14 | id, 15 | children, 16 | onClick, 17 | active = false, 18 | className = '', 19 | tooltip, 20 | ref, 21 | ...props 22 | }: ButtonProps) { 23 | return ( 24 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /snippet/src/components/webworker.ts: -------------------------------------------------------------------------------- 1 | import { PdfiumEngineRunner } from '@embedpdf/engines'; 2 | 3 | let runner: PdfiumEngineRunner | null = null; 4 | 5 | // Listen for initialization message 6 | self.onmessage = async (event) => { 7 | const { type, wasmUrl } = event.data; 8 | 9 | if (type === 'INIT_WASM' && wasmUrl && !runner) { 10 | try { 11 | const response = await fetch(wasmUrl); 12 | const wasmBinary = await response.arrayBuffer(); 13 | runner = new PdfiumEngineRunner(wasmBinary); 14 | runner.prepare(); 15 | 16 | // Notify that initialization is complete 17 | self.postMessage({ type: 'WASM_READY' }); 18 | } catch (error) { 19 | const message = error instanceof Error ? error.message : String(error); 20 | self.postMessage({ type: 'WASM_ERROR', error: message }); 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /snippet/src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.svg'; 3 | -------------------------------------------------------------------------------- /snippet/src/hooks/use-debounce.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'preact/hooks'; // or react/hooks 2 | 3 | export function useDebounce(value: T, delay = 300): T { 4 | const [debounced, setDebounced] = useState(value); 5 | 6 | useEffect(() => { 7 | const id = window.setTimeout(() => setDebounced(value), delay); 8 | return () => clearTimeout(id); // cancel if value changes early 9 | }, [value, delay]); 10 | 11 | return debounced; 12 | } 13 | -------------------------------------------------------------------------------- /snippet/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EmbedPDF 7 | 14 | 15 | 16 |
17 | 35 | 36 | -------------------------------------------------------------------------------- /snippet/src/styles/index.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | @import url('https://fonts.googleapis.com/css2?family=Open Sans:wght@400;600&display=swap'); 3 | 4 | :host { 5 | --tw-translate-x: 0; 6 | --tw-translate-y: 0; 7 | --tw-translate-z: 0; 8 | --tw-rotate-x: rotateX(0); 9 | --tw-rotate-y: rotateY(0); 10 | --tw-rotate-z: rotateZ(0); 11 | --tw-skew-x: skewX(0); 12 | --tw-skew-y: skewY(0); 13 | --tw-border-style: solid; 14 | --tw-gradient-from: #0000; 15 | --tw-gradient-via: #0000; 16 | --tw-gradient-to: #0000; 17 | --tw-gradient-from-position: 0%; 18 | --tw-gradient-via-position: 50%; 19 | --tw-gradient-to-position: 100%; 20 | --tw-shadow: 0 0 #0000; 21 | --tw-inset-shadow: 0 0 #0000; 22 | --tw-ring-shadow: 0 0 #0000; 23 | --tw-inset-ring-shadow: 0 0 #0000; 24 | --tw-ring-offset-width: 0px; 25 | --tw-ring-offset-color: #fff; 26 | --tw-ring-offset-shadow: 0 0 #0000; 27 | --tw-outline-style: solid; 28 | display: flex; 29 | flex-direction: column; 30 | overflow: hidden; 31 | width: 100%; 32 | height: 100%; 33 | } 34 | -------------------------------------------------------------------------------- /snippet/src/web-components/container.tsx: -------------------------------------------------------------------------------- 1 | import { h, render } from 'preact'; 2 | import { PDFViewer, PDFViewerConfig } from '@/components/app'; 3 | 4 | export class EmbedPdfContainer extends HTMLElement { 5 | private root: ShadowRoot; 6 | private _config?: PDFViewerConfig; 7 | 8 | constructor() { 9 | super(); 10 | this.root = this.attachShadow({ mode: 'open' }); 11 | } 12 | 13 | connectedCallback() { 14 | // If config isn’t provided via script, build it from attributes 15 | if (!this._config) { 16 | this._config = { 17 | src: this.getAttribute('src') || '/demo.pdf', 18 | worker: this.getAttribute('worker') !== 'false', 19 | }; 20 | } 21 | this.renderViewer(); 22 | } 23 | 24 | // Setter for config 25 | set config(newConfig: PDFViewerConfig) { 26 | this._config = newConfig; 27 | if (this.isConnected) { 28 | this.renderViewer(); 29 | } 30 | } 31 | 32 | // Getter for config 33 | get config(): PDFViewerConfig | undefined { 34 | return this._config; 35 | } 36 | 37 | renderViewer() { 38 | if (!this._config) return; 39 | render(, this.root); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /snippet/tools/build-worker.js: -------------------------------------------------------------------------------- 1 | import { rollup } from 'rollup'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | import typescript from '@rollup/plugin-typescript'; 4 | import terser from '@rollup/plugin-terser'; 5 | import replace from '@rollup/plugin-replace'; 6 | 7 | export async function bundleWorker() { 8 | const bundle = await rollup({ 9 | input: 'src/components/webworker.ts', 10 | plugins: [ 11 | resolve(), 12 | typescript(), 13 | terser({ 14 | compress: true, 15 | }), 16 | replace({ 17 | preventAssignment: true, 18 | delimiters: ['', ''], 19 | 'new URL("pdfium.wasm",import.meta.url).href': '"pdfium.wasm"', 20 | }), 21 | ], 22 | }); 23 | const { output } = await bundle.generate({ 24 | format: 'es', 25 | inlineDynamicImports: true, 26 | }); 27 | return output[0].code; 28 | } 29 | -------------------------------------------------------------------------------- /snippet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*"], 3 | "exclude": ["dist", "node_modules"], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["src/*"] 8 | }, 9 | "target": "ESNext", 10 | "module": "ESNext", 11 | "strict": true, 12 | "jsx": "react", 13 | "jsxFactory": "h", 14 | "jsxFragmentFactory": "Fragment", 15 | "outDir": "dist", 16 | "declaration": true, 17 | "declarationMap": true, 18 | "moduleResolution": "bundler", 19 | "allowSyntheticDefaultImports": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "tasks": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["dist/**"] 7 | }, 8 | "check-types": { 9 | "dependsOn": ["^check-types"] 10 | }, 11 | "dev": { 12 | "persistent": true, 13 | "cache": false 14 | }, 15 | "clean": { 16 | "cache": false 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /types/assets.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm?url' { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /website/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /website/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Bob Singor 4 | Copyright (c) 2020 Shu Ding 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /website/mdx-components.tsx: -------------------------------------------------------------------------------- 1 | import { MDXComponents } from 'mdx/types' 2 | import { useMDXComponents as getDocsMDXComponents } from '@/components/mdx-components' // nextra-theme-blog or your custom theme 3 | 4 | // Get the default MDX components 5 | const docsComponents = getDocsMDXComponents() 6 | 7 | export const useMDXComponents: typeof getDocsMDXComponents = (components) => ({ 8 | ...docsComponents, 9 | ...components, 10 | }) 11 | -------------------------------------------------------------------------------- /website/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /website/prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Options} */ 2 | module.exports = { 3 | singleQuote: true, 4 | semi: false, 5 | plugins: ['prettier-plugin-tailwindcss'], 6 | tailwindStylesheet: './src/styles/tailwind.css', 7 | } 8 | -------------------------------------------------------------------------------- /website/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/apple-touch-icon.png -------------------------------------------------------------------------------- /website/public/demo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/demo.pdf -------------------------------------------------------------------------------- /website/public/demo_protected.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/demo_protected.pdf -------------------------------------------------------------------------------- /website/public/ebook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/ebook.pdf -------------------------------------------------------------------------------- /website/public/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/favicon-96x96.png -------------------------------------------------------------------------------- /website/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/favicon.ico -------------------------------------------------------------------------------- /website/public/logo-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/logo-192.png -------------------------------------------------------------------------------- /website/public/profile.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/profile.jpeg -------------------------------------------------------------------------------- /website/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EmbedPDF", 3 | "short_name": "EmbedPDF", 4 | "icons": [ 5 | { 6 | "src": "/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /website/public/wasm/pdfium.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/wasm/pdfium.wasm -------------------------------------------------------------------------------- /website/public/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /website/public/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedpdf/embed-pdf-viewer/65e6be8825de4fc240f94deaaa2d2479c2ed63f4/website/public/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /website/src/app/[[...mdxPath]]/page.tsx: -------------------------------------------------------------------------------- 1 | import { generateStaticParamsFor, importPage } from 'nextra/pages' 2 | import { useMDXComponents as getMDXComponents } from '../../../mdx-components' 3 | import { Fragment } from 'react' 4 | import { ComponentType } from 'react' 5 | 6 | export const generateStaticParams = generateStaticParamsFor('mdxPath') 7 | 8 | export async function generateMetadata(props: PageProps) { 9 | const params = await props.params 10 | 11 | const { metadata } = await importPage(params.mdxPath) 12 | return metadata 13 | } 14 | 15 | type PageProps = Readonly<{ 16 | params: Promise<{ 17 | mdxPath: string[] 18 | lang: string 19 | }> 20 | }> 21 | 22 | const Wrapper = getMDXComponents().wrapper 23 | 24 | export default async function Page(props: PageProps) { 25 | const params = await props.params 26 | 27 | const result = await importPage(params.mdxPath) 28 | const { default: MDXContent, toc, metadata } = result 29 | 30 | return ( 31 | 32 | 33 | 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /website/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@/styles/tailwind.css' 2 | import Navbar from '@/components/navbar' 3 | import { ConfigProvider } from '@/components/stores/config' 4 | import { getPageMap } from 'nextra/page-map' 5 | 6 | export const metadata = { 7 | title: 'EmbedPDF: The Lightweight JavaScript PDF Viewer for Any Framework', 8 | description: 9 | 'EmbedPDF is an open-source JavaScript PDF viewer that seamlessly integrates with React, Vue, Angular, Svelte, or vanilla JS. Lightweight (3.2kb gzipped), customizable, and framework-agnostic. Display, annotate, and navigate PDF documents with ease.', 10 | icons: { 11 | icon: '/favicon.ico', 12 | apple: '/apple-touch-icon.png', 13 | }, 14 | manifest: `/site.webmanifest`, 15 | } 16 | 17 | export default async function RootLayout({ 18 | children, 19 | }: { 20 | children: React.ReactNode 21 | }) { 22 | let pageMap = await getPageMap() 23 | 24 | return ( 25 | 26 | 27 | } pageMap={pageMap}> 28 | {children} 29 | 30 | 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /website/src/components/button.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Button as HeadlessButton } from '@headlessui/react' 4 | import type { ButtonProps as HeadlessButtonProps } from '@headlessui/react' 5 | import cn from 'clsx' 6 | import type { FC } from 'react' 7 | import { classes } from './mdx-components/pre' 8 | 9 | export type ButtonProps = HeadlessButtonProps & { 10 | variant?: 'outline' | 'default' 11 | } 12 | 13 | export const Button: FC = ({ 14 | children, 15 | className, 16 | variant = 'default', 17 | ...props 18 | }) => { 19 | return ( 20 | 22 | cn( 23 | 'cursor-pointer transition', 24 | args.focus && 'nextra-focus', 25 | variant === 'outline' && [classes.border, 'rounded-md p-1.5'], 26 | typeof className === 'function' ? className(args) : className, 27 | ) 28 | } 29 | {...props} 30 | > 31 | {children} 32 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /website/src/components/mdx-components/anchor.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'clsx' 2 | import Link from 'next/link' 3 | import type { ComponentPropsWithoutRef, FC } from 'react' 4 | import { LinkArrowIcon } from 'nextra/icons' 5 | 6 | export const EXTERNAL_URL_RE = /^https?:\/\// 7 | 8 | export const Anchor: FC> = ({ 9 | href = '', 10 | ...props 11 | }) => { 12 | props = { 13 | ...props, 14 | className: cn('focus-visible:nextra-focus', props.className), 15 | } 16 | if (EXTERNAL_URL_RE.test(href)) { 17 | const { children } = props 18 | return ( 19 |
20 | {children} 21 | {typeof children === 'string' && ( 22 | <> 23 |   24 | 29 | 30 | )} 31 | 32 | ) 33 | } 34 | const ComponentToUse = href.startsWith('#') ? 'a' : Link 35 | return 36 | } 37 | -------------------------------------------------------------------------------- /website/src/components/mdx-components/code.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'clsx' 2 | import type { ComponentProps, FC } from 'react' 3 | 4 | export const Code: FC< 5 | ComponentProps<'code'> & { 6 | 'data-language'?: string 7 | } 8 | > = ({ children, className, 'data-language': _language, ...props }) => { 9 | return ( 10 | 20 | {children} 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /website/src/components/mdx-components/image.tsx: -------------------------------------------------------------------------------- 1 | import type { ImageProps } from 'next/image' 2 | import NextImage from 'next/image' 3 | import { forwardRef } from 'react' 4 | 5 | export const Image = forwardRef((props, ref) => { 6 | if ( 7 | process.env.NODE_ENV !== 'production' && 8 | typeof props.src === 'object' && 9 | !('blurDataURL' in props.src) 10 | ) { 11 | console.warn( 12 | `[nextra] Failed to load blur image "${(props.src as any).src}" due missing "src.blurDataURL" value. 13 | This is Turbopack bug, which will not occurs on production (since Webpack is used for "next build" command).`, 14 | ) 15 | props = { 16 | ...props, 17 | placeholder: 'empty', 18 | } 19 | } 20 | const ComponentToUse = typeof props.src === 'object' ? NextImage : 'img' 21 | return ( 22 | // @ts-expect-error -- fixme 23 | 28 | ) 29 | }) 30 | 31 | Image.displayName = 'Image' 32 | -------------------------------------------------------------------------------- /website/src/components/mdx-components/link.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'clsx' 2 | import { Anchor } from './anchor' 3 | 4 | export const Link: typeof Anchor = ({ className, ...props }) => { 5 | return ( 6 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /website/src/components/mdx-components/pre/toggle-word-wrap-button.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import type { FC, ReactNode } from 'react' 4 | import { Button } from '../../button' 5 | 6 | function toggleWordWrap() { 7 | const htmlDataset = document.documentElement.dataset 8 | const hasWordWrap = 'nextraWordWrap' in htmlDataset 9 | if (hasWordWrap) { 10 | delete htmlDataset.nextraWordWrap 11 | } else { 12 | htmlDataset.nextraWordWrap = '' 13 | } 14 | } 15 | 16 | export const ToggleWordWrapButton: FC<{ 17 | children: ReactNode 18 | }> = ({ children }) => { 19 | return ( 20 | 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /website/src/components/mdx-components/table.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'clsx' 2 | import type { ComponentProps, FC } from 'react' 3 | 4 | const Table_: FC> = (props) => ( 5 | 6 | ) 7 | const Th: FC> = (props) => { 8 | return ( 9 | 28 | ) 29 | } 30 | const Td: FC> = (props) => { 31 | return ( 32 |
16 | ) 17 | } 18 | const Tr: FC> = (props) => { 19 | return ( 20 |
36 | ) 37 | } 38 | 39 | export const Table = Object.assign(Table_, { 40 | Th, 41 | Tr, 42 | Td, 43 | }) 44 | -------------------------------------------------------------------------------- /website/src/components/preview.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react' 2 | import cn from 'clsx' 3 | import { EyeIcon } from 'lucide-react' 4 | 5 | interface PreviewProps { 6 | title: string 7 | children: ReactNode 8 | } 9 | 10 | export function Preview({ title, children }: PreviewProps) { 11 | return ( 12 |
13 |
18 | 19 | PREVIEW: 20 | {title} 21 |
22 |
23 | {children} 24 |
25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /website/src/components/steps.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'clsx' 2 | import type { ComponentProps, FC } from 'react' 3 | import { useId } from 'react' 4 | 5 | export const Steps: FC> = ({ 6 | children, 7 | className, 8 | style, 9 | ...props 10 | }) => { 11 | const id = useId().replaceAll(':', '') 12 | return ( 13 |
25 | {children} 26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /website/src/components/stores/active-anchor.ts: -------------------------------------------------------------------------------- 1 | 'use no memo' 2 | 3 | import type { Dispatch } from 'react' 4 | import { create } from 'zustand' 5 | 6 | const useActiveAnchorStore = create<{ 7 | activeSlug: string 8 | }>(() => ({ 9 | activeSlug: '', 10 | })) 11 | 12 | export const useActiveAnchor = () => 13 | useActiveAnchorStore((state) => state.activeSlug) 14 | 15 | export const setActiveSlug: Dispatch = (activeSlug) => { 16 | useActiveAnchorStore.setState({ activeSlug }) 17 | } 18 | -------------------------------------------------------------------------------- /website/src/components/stores/focused-route.ts: -------------------------------------------------------------------------------- 1 | 'use no memo' 2 | 3 | import type { Dispatch } from 'react' 4 | import { create } from 'zustand' 5 | 6 | const useFocusedRouteStore = create<{ 7 | focused: string 8 | }>(() => ({ 9 | focused: '', 10 | })) 11 | 12 | export const useFocusedRoute = () => 13 | useFocusedRouteStore((state) => state.focused) 14 | 15 | export const setFocusedRoute: Dispatch = (focused) => { 16 | useFocusedRouteStore.setState({ focused }) 17 | } 18 | -------------------------------------------------------------------------------- /website/src/components/stores/index.ts: -------------------------------------------------------------------------------- 1 | export { useActiveAnchor, setActiveSlug } from './active-anchor' 2 | export { useConfig, ConfigProvider } from './config' 3 | export { useToc, setToc } from './toc' 4 | -------------------------------------------------------------------------------- /website/src/components/stores/menu.ts: -------------------------------------------------------------------------------- 1 | 'use no memo' 2 | 3 | import type { Dispatch, SetStateAction } from 'react' 4 | import { create } from 'zustand' 5 | 6 | const useMenuStore = create<{ 7 | hasMenu: boolean 8 | }>(() => ({ 9 | hasMenu: false, 10 | })) 11 | 12 | export const useMenu = () => useMenuStore((state) => state.hasMenu) 13 | 14 | export const setMenu: Dispatch> = (fn) => { 15 | useMenuStore.setState((state) => { 16 | const hasMenu = typeof fn === 'function' ? fn(state.hasMenu) : fn 17 | // Lock background scroll when menu is opened 18 | document.body.classList.toggle('max-md:overflow-hidden', hasMenu) 19 | return { hasMenu } 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /website/src/components/stores/toc.ts: -------------------------------------------------------------------------------- 1 | 'use no memo' 2 | 3 | import type { Heading } from 'nextra' 4 | import type { Dispatch } from 'react' 5 | import { create } from 'zustand' 6 | 7 | const useTocStore = create<{ 8 | toc: Heading[] 9 | }>(() => ({ 10 | toc: [], 11 | })) 12 | 13 | export const useToc = () => useTocStore((state) => state.toc) 14 | 15 | export const setToc: Dispatch = (toc) => { 16 | useTocStore.setState({ toc }) 17 | } 18 | -------------------------------------------------------------------------------- /website/src/components/tabs/index.tsx: -------------------------------------------------------------------------------- 1 | 'use no memo' 2 | 3 | import type { ComponentProps } from 'react' 4 | import { Tabs as _Tabs, Tab } from './index.client' 5 | 6 | // Workaround to fix 7 | // Error: Cannot access Tab.propTypes on the server. You cannot dot into a client module from a 8 | // server component. You can only pass the imported name through. 9 | export const Tabs = Object.assign( 10 | (props: ComponentProps) => <_Tabs {...props} />, 11 | { Tab }, 12 | ) 13 | -------------------------------------------------------------------------------- /website/src/components/tools/pdf-merge/index.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { PdfMergeTool } from './pdf-merge-tool' 4 | 5 | export { PdfMergeTool } 6 | -------------------------------------------------------------------------------- /website/src/components/tools/pdf-merge/merge-result.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React from 'react' 4 | 5 | interface MergeResultProps { 6 | mergedPdfUrl: string 7 | onReset: () => void 8 | } 9 | 10 | export const MergeResult: React.FC = ({ 11 | mergedPdfUrl, 12 | onReset, 13 | }) => { 14 | return ( 15 |
16 |

Your merged PDF is ready!

17 |
18 | 23 | Download PDF 24 | 25 | 31 |
32 |
33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /website/src/components/tools/pdf-merge/types.ts: -------------------------------------------------------------------------------- 1 | import { PdfDocumentObject } from '@embedpdf/models' 2 | 3 | /** 4 | * Represents a page in a source document 5 | */ 6 | export type DocumentPage = { 7 | docId: string 8 | pageIndex: number 9 | thumbnail?: string 10 | selected?: boolean 11 | } 12 | 13 | /** 14 | * Represents a page in the merged document 15 | */ 16 | export type MergeDocPage = { 17 | id: string 18 | docId: string 19 | pageIndex: number 20 | thumbnail?: string 21 | } 22 | 23 | /** 24 | * Representation of a PDF document with its pages 25 | */ 26 | export type DocumentWithPages = { 27 | doc: PdfDocumentObject 28 | pages: DocumentPage[] 29 | } 30 | -------------------------------------------------------------------------------- /website/src/content/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | index: { 3 | title: 'Home', 4 | type: 'page', 5 | theme: { 6 | timestamp: false, 7 | }, 8 | }, 9 | docs: { 10 | title: 'Docs', 11 | type: 'page', 12 | }, 13 | blog: { 14 | title: 'Blog', 15 | type: 'page', 16 | theme: { 17 | sidebar: false, 18 | typesetting: 'article', 19 | breadcrumb: false, 20 | pagination: false, 21 | timestamp: false, 22 | }, 23 | }, 24 | tools: { 25 | title: 'Tools', 26 | type: 'page', 27 | }, 28 | viewer: { 29 | title: 'Viewer', 30 | type: 'page', 31 | theme: { 32 | timestamp: false, 33 | }, 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /website/src/content/blog.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | searchable: false 3 | --- 4 | 5 | import Blog from '@/components/blog' 6 | 7 | -------------------------------------------------------------------------------- /website/src/content/blog/test-blog.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Test Blog 3 | description: A simple test blog 4 | searchable: false 5 | --- 6 | 7 | # Test Blog 8 | 9 | This is a test blog. -------------------------------------------------------------------------------- /website/src/content/docs/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | pdfium: { 3 | title: 'PDFium JavaScript API', 4 | type: 'page', 5 | }, 6 | snippet: { 7 | title: 'EmbedPDF Snippet', 8 | type: 'page', 9 | }, 10 | index: { 11 | title: 'Introduction', 12 | type: 'page', 13 | theme: { 14 | timestamp: false, 15 | }, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /website/src/content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: EmbedPDF Documentation 3 | description: Comprehensive documentation for all EmbedPDF packages, with guides, API references, and examples. 4 | searchable: false 5 | --- 6 | 7 | import DocsOverview from '@/components/documentation-overview'; 8 | 9 | -------------------------------------------------------------------------------- /website/src/content/docs/pdfium/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | introduction: 'Introduction', 3 | 'getting-started': 'Getting Started', 4 | } 5 | -------------------------------------------------------------------------------- /website/src/content/docs/pdfium/code-examples/get-pdf-page-count.ts: -------------------------------------------------------------------------------- 1 | import { initializePdfium } from './initialize-pdfium' 2 | 3 | async function getPdfPageCount(pdfData: Uint8Array) { 4 | // Step 1: Initialize PDFium 5 | const pdfium = await initializePdfium() 6 | 7 | // Step 2: Load the PDF document 8 | const filePtr = pdfium.pdfium.wasmExports.malloc(pdfData.length) 9 | pdfium.pdfium.HEAPU8.set(pdfData, filePtr) 10 | const docPtr = pdfium.FPDF_LoadMemDocument(filePtr, pdfData.length, 0) 11 | 12 | if (!docPtr) { 13 | const error = pdfium.FPDF_GetLastError() 14 | pdfium.pdfium.wasmExports.free(filePtr) 15 | throw new Error(`Failed to load PDF: ${error}`) 16 | } 17 | 18 | try { 19 | // Step 3: Get the page count 20 | const pageCount = pdfium.FPDF_GetPageCount(docPtr) 21 | return pageCount 22 | } finally { 23 | // Step 4: Clean up 24 | pdfium.FPDF_CloseDocument(docPtr) 25 | pdfium.pdfium.wasmExports.free(filePtr) 26 | } 27 | } 28 | 29 | export { getPdfPageCount } 30 | -------------------------------------------------------------------------------- /website/src/content/docs/pdfium/code-examples/initialize-pdfium.ts: -------------------------------------------------------------------------------- 1 | import { init, WrappedPdfiumModule } from '@embedpdf/pdfium' 2 | 3 | const pdfiumWasm = '/wasm/pdfium.wasm' 4 | 5 | let pdfiumInstance: WrappedPdfiumModule | null = null 6 | 7 | async function initializePdfium() { 8 | if (pdfiumInstance) return pdfiumInstance 9 | 10 | const response = await fetch(pdfiumWasm) 11 | const wasmBinary = await response.arrayBuffer() 12 | pdfiumInstance = await init({ wasmBinary }) 13 | 14 | pdfiumInstance.PDFiumExt_Init() 15 | 16 | return pdfiumInstance 17 | } 18 | 19 | export { initializePdfium } 20 | -------------------------------------------------------------------------------- /website/src/content/docs/pdfium/examples/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'render-page-to-canvas': 'Render Page to Canvas', 3 | 'extract-text-from-pdf': 'Extract Text from PDF', 4 | } 5 | -------------------------------------------------------------------------------- /website/src/content/docs/pdfium/functions/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | PDFiumExt_Init: '', 3 | FPDF_LoadMemDocument: '', 4 | FPDF_LoadCustomDocument: '', 5 | FPDF_GetPageCount: '', 6 | FPDF_LoadPage: '', 7 | FPDFText_LoadPage: '', 8 | FPDFText_CountChars: '', 9 | FPDFText_GetText: '', 10 | FPDFText_ClosePage: '', 11 | FPDF_ClosePage: '', 12 | FPDF_CloseDocument: '', 13 | FPDF_GetLastError: '', 14 | } 15 | -------------------------------------------------------------------------------- /website/src/content/docs/snippet/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | introduction: 'Introduction', 3 | } 4 | -------------------------------------------------------------------------------- /website/src/content/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Open-Source JavaScript PDF Viewer – Fast, Customizable & Framework-Agnostic | EmbedPDF 3 | description: EmbedPDF is a blazing-fast, MIT-licensed JavaScript PDF viewer that works with React, Vue, Svelte, and plain JS. Fully customizable, zero vendor lock-in, and perfect for modern web apps. 4 | searchable: false 5 | --- 6 | 7 | import Homepage from '@/components/homepage' 8 | 9 | -------------------------------------------------------------------------------- /website/src/content/tools/_meta.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | ['pdf-merge']: { 3 | title: 'PDF Merge Tool', 4 | type: 'page', 5 | theme: { 6 | timestamp: false, 7 | }, 8 | }, 9 | index: { 10 | title: 'Tools', 11 | type: 'page', 12 | theme: { 13 | timestamp: false, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /website/src/content/tools/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: PDF Tools 3 | description: Free browser-based tools for working with PDF files. Merge, edit, and manipulate PDFs securely without uploading your files anywhere. 4 | --- 5 | 6 | import ToolsOverview from '@/components/tools-overview' 7 | 8 | 9 | -------------------------------------------------------------------------------- /website/src/content/tools/pdf-merge.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: PDF Merge Tool - Combine PDFs in Your Browser 3 | description: Merge multiple PDF files into one document securely in your browser. Select and reorder specific pages, combine documents, and create new PDFs without uploading your files anywhere. Free, private, and browser-based. 4 | --- 5 | 6 | import { PdfMergeTool } from '@/components/tools/pdf-merge' 7 | 8 | -------------------------------------------------------------------------------- /website/src/content/viewer.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: EmbedPDF - The Lightweight JavaScript PDF Viewer for Any Framework 3 | description: EmbedPDF is an open-source JavaScript PDF viewer that seamlessly integrates with React, Vue, Angular, Svelte, or vanilla JS. Lightweight (3.2kb gzipped), customizable, and framework-agnostic. Display, annotate, and navigate PDF documents with ease. 4 | searchable: false 5 | --- 6 | 7 | import PDFViewer from '@/components/pdf-viewer' 8 | 9 | -------------------------------------------------------------------------------- /website/src/types/wasm.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm' { 2 | const content: string 3 | export default content 4 | } 5 | -------------------------------------------------------------------------------- /website/tools/copy-wasm.ts: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | const copyFiles = async (): Promise => { 4 | try { 5 | await fs.copy( 6 | './node_modules/@embedpdf/pdfium/dist/pdfium.wasm', 7 | './public/wasm/pdfium.wasm', 8 | ) 9 | console.log('PDFium files copied over successfully') 10 | } catch (err) { 11 | console.error(err) 12 | } 13 | } 14 | 15 | copyFiles() 16 | -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "ESNext", 12 | "moduleResolution": "bundler", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": [ 27 | "next-env.d.ts", 28 | "**/*.ts", 29 | "**/*.tsx", 30 | ".next/types/**/*.ts", 31 | "next.config.ts" 32 | ], 33 | "exclude": ["node_modules"] 34 | } 35 | --------------------------------------------------------------------------------