├── .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 | |
16 | )
17 | }
18 | const Tr: FC> = (props) => {
19 | return (
20 |
28 | )
29 | }
30 | const Td: FC> = (props) => {
31 | return (
32 | |
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 |
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 |
--------------------------------------------------------------------------------