From 03f484e0c084f07cc267ea228c43101185fc6df2 Mon Sep 17 00:00:00 2001
From: Reece Browne <74901996+reecebrowne@users.noreply.github.com>
Date: Fri, 26 Sep 2025 10:03:35 +0100
Subject: [PATCH 1/2] Fix (#4495)
# Description of Changes
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
---
docker/frontend/nginx.conf | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/docker/frontend/nginx.conf b/docker/frontend/nginx.conf
index af4ca85f2..ffe913738 100644
--- a/docker/frontend/nginx.conf
+++ b/docker/frontend/nginx.conf
@@ -6,6 +6,11 @@ http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
+ # Add .mjs MIME type mapping
+ types {
+ text/javascript mjs;
+ }
+
# Gzip compression
gzip on;
gzip_vary on;
@@ -90,6 +95,14 @@ http {
proxy_set_header X-Forwarded-Port $server_port;
}
+ # Serve .mjs files with correct MIME type (must come before general static assets)
+ location ~* \.mjs$ {
+ try_files $uri =404;
+ add_header Content-Type "text/javascript; charset=utf-8" always;
+ expires 1y;
+ add_header Cache-Control "public, immutable";
+ }
+
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
From d613a4659eeb95c305b7f28fdbc540381b20dcfe Mon Sep 17 00:00:00 2001
From: Reece Browne <74901996+reecebrowne@users.noreply.github.com>
Date: Fri, 26 Sep 2025 10:28:09 +0100
Subject: [PATCH 2/2] Feature/v2/exportpdf (#4487)
# Description of Changes
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
---
frontend/package-lock.json | 251 ++++++++++--------
frontend/package.json | 29 +-
frontend/src/components/shared/RightRail.tsx | 14 +-
.../src/components/viewer/ExportAPIBridge.tsx | 25 ++
.../src/components/viewer/LocalEmbedPDF.tsx | 8 +
frontend/src/contexts/ViewerContext.tsx | 47 ++++
6 files changed, 247 insertions(+), 127 deletions(-)
create mode 100644 frontend/src/components/viewer/ExportAPIBridge.tsx
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index ece2aba60..0fefee3d1 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -10,21 +10,22 @@
"license": "SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE",
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
- "@embedpdf/core": "^1.2.1",
+ "@embedpdf/core": "^1.3.0",
"@embedpdf/engines": "^1.2.1",
- "@embedpdf/plugin-interaction-manager": "^1.2.1",
- "@embedpdf/plugin-loader": "^1.2.1",
- "@embedpdf/plugin-pan": "^1.2.1",
- "@embedpdf/plugin-render": "^1.2.1",
- "@embedpdf/plugin-rotate": "^1.2.1",
- "@embedpdf/plugin-scroll": "^1.2.1",
- "@embedpdf/plugin-search": "^1.2.1",
- "@embedpdf/plugin-selection": "^1.2.1",
- "@embedpdf/plugin-spread": "^1.2.1",
- "@embedpdf/plugin-thumbnail": "^1.2.1",
- "@embedpdf/plugin-tiling": "^1.2.1",
- "@embedpdf/plugin-viewport": "^1.2.1",
- "@embedpdf/plugin-zoom": "^1.2.1",
+ "@embedpdf/plugin-export": "^1.3.0",
+ "@embedpdf/plugin-interaction-manager": "^1.3.0",
+ "@embedpdf/plugin-loader": "^1.3.0",
+ "@embedpdf/plugin-pan": "^1.3.0",
+ "@embedpdf/plugin-render": "^1.3.0",
+ "@embedpdf/plugin-rotate": "^1.3.0",
+ "@embedpdf/plugin-scroll": "^1.3.0",
+ "@embedpdf/plugin-search": "^1.3.0",
+ "@embedpdf/plugin-selection": "^1.3.0",
+ "@embedpdf/plugin-spread": "^1.3.0",
+ "@embedpdf/plugin-thumbnail": "^1.3.0",
+ "@embedpdf/plugin-tiling": "^1.3.0",
+ "@embedpdf/plugin-viewport": "^1.3.0",
+ "@embedpdf/plugin-zoom": "^1.3.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@iconify/react": "^6.0.2",
@@ -488,12 +489,13 @@
}
},
"node_modules/@embedpdf/core": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.2.1.tgz",
- "integrity": "sha512-2VwRPsN3+LmaBrD8TCN1t1ni/Vc9CxAfl/SApDjZYwE7zOieQT4ZHt+nkgF0F4I3xSgvvyHDjmOonhjBIrT6xA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.3.0.tgz",
+ "integrity": "sha512-KEic1NA9JrtNRoTq3O3m93YTglRKweR6uqjzX3sLGCmy+LsUjiH5WOCJAztlSlmZEXysAlZlyzG/09gz4tpBAg==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/engines": "1.2.1",
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/engines": "1.3.0",
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
"preact": "^10.26.4",
@@ -503,13 +505,13 @@
}
},
"node_modules/@embedpdf/engines": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-1.2.1.tgz",
- "integrity": "sha512-nhycZ7Buq2B34dcpo6n7RdFwdhwTvKzvnRy7QX+uU00Dz5vftkCG4OK+pBVzxE4y7vAu+Yb4wNpdc7HmIj3B6w==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-1.3.0.tgz",
+ "integrity": "sha512-6WbYwxtCCjOazEMGKbhKRkos6S1VkzI4R2u6dUuIsUw9G2HLP4bwJCBKj9A0FuMAJkKQ3VL5eVCSGfqaCaRoyQ==",
"license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1",
- "@embedpdf/pdfium": "1.2.1"
+ "@embedpdf/models": "1.3.0",
+ "@embedpdf/pdfium": "1.3.0"
},
"peerDependencies": {
"preact": "^10.26.4",
@@ -519,26 +521,43 @@
}
},
"node_modules/@embedpdf/models": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-1.2.1.tgz",
- "integrity": "sha512-FzJU51jsqihfgt50B00FEpgyym87/Dn2iGmMq4++Vu/oO6qBx/y69m4/cCAh4p4KkTJsvKNWC7T7dwSKa0FjHA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-1.3.0.tgz",
+ "integrity": "sha512-LIY6T+nQoc1hi6nq1NlH6sR43J3PYOg9Bux8ouEnKjEGiZMgyd1cMxhBfrrY+Ft6DsSkqqujFOVEwjeYQYy3dg==",
"license": "MIT"
},
"node_modules/@embedpdf/pdfium": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-1.2.1.tgz",
- "integrity": "sha512-QWf1jg7EqUlku2q6KYhlXCNfk5IAykFerPuzKJepHTeAEaRcAfu84fJgEsoUTCK4D6dfzVNp2Iuxw6Kv7MpSeg==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-1.3.0.tgz",
+ "integrity": "sha512-rSBFYjxwQ58L/HcqR0l5Vv4G5t+CCOKlFYrDReTZYNN7fhzKPUWbXUn4ARahZWCNmF8svHumV2P4ArakJJviuw==",
"license": "MIT"
},
- "node_modules/@embedpdf/plugin-interaction-manager": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.2.1.tgz",
- "integrity": "sha512-HhEBuDjDNMH6wu76Eo3yHwjG01U1lNZShkOsFoib/rtx8HByTgZS8iVpovaOprr6gfS04ZLqWcsN1nt5qAH90w==",
+ "node_modules/@embedpdf/plugin-export": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-export/-/plugin-export-1.3.0.tgz",
+ "integrity": "sha512-R6VItLmXmXbb0/4AsH1YGUZd0c64K/8kxQd0XAvgUJwcL7Z4s8bLsqRx4sVQqwVllaPEJbAdFn1CC/ymkGB+fg==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "preact": "^10.26.4",
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0",
+ "vue": ">=3.2.0"
+ }
+ },
+ "node_modules/@embedpdf/plugin-interaction-manager": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.3.0.tgz",
+ "integrity": "sha512-iMG7mW+4YpNjBeSAcC5kK9VnjwmNu71HTxVtKnN73t3EBfukbMH4y7Tp2ds+4I97H6vc18RK5xuUCSesEOBgww==",
+ "license": "MIT",
+ "dependencies": {
+ "@embedpdf/models": "1.3.0"
+ },
+ "peerDependencies": {
+ "@embedpdf/core": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -546,14 +565,15 @@
}
},
"node_modules/@embedpdf/plugin-loader": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.2.1.tgz",
- "integrity": "sha512-VblKErfEiHcVao18TfCmc0UJlKAkqxE29DaLJrXQHGUw/qc+pC9HlvMVpDz3+Eb13UafYS6ZUZuEng2/fQ+JJw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.3.0.tgz",
+ "integrity": "sha512-tkOa1UwFOimueSxxm2hRAAh64K75itDvUO6wHjb5X5s0Hx4DccfrJ7KusDhxBkeQLFXtZknPG0Q2/9T+joAqeQ==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
+ "@embedpdf/core": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -561,16 +581,17 @@
}
},
"node_modules/@embedpdf/plugin-pan": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-1.2.1.tgz",
- "integrity": "sha512-/BTOyRl31tvnCmoLs4qNPROMRLaG34jGYNyMQquB0uPUXZjwdMloikriwos91qCOLUrhvs4SaDpC3Ghv2BO5kA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-1.3.0.tgz",
+ "integrity": "sha512-tZxUpX9dvd/VDHCTqM9Yjss4M8pkJWFUA5GDNmPkExRXIASuB98wEP8fh0rQt13TEZ30rV77cEsNXngju56kjg==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-interaction-manager": "1.2.1",
- "@embedpdf/plugin-viewport": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-interaction-manager": "1.3.0",
+ "@embedpdf/plugin-viewport": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -578,14 +599,15 @@
}
},
"node_modules/@embedpdf/plugin-render": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.2.1.tgz",
- "integrity": "sha512-iMfuVJqttJmm7Zb8oOaqNVNrC3NS57bDNNAc4MIc2f2TxIFSznvBPlwWN+PN45qNcTQiGzFc1ZMqIQDOG4qFnQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.3.0.tgz",
+ "integrity": "sha512-ZyxoGIIUa2HBLt1IB64EdWqBxHh01AX/1HJ7/cnoQK1h/oKXRbMAX6Mb23JCh2PGa4sGeyV3psoFMt037Eew3g==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
+ "@embedpdf/core": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -593,14 +615,15 @@
}
},
"node_modules/@embedpdf/plugin-rotate": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-1.2.1.tgz",
- "integrity": "sha512-UhHds5donLDXm3i9nKrhSmo3yawVtjb6gID0MDrhj3+Lci/YQ3wDvGUhk7dNmgLcOt7G8pMa0wesnnpVWirUXA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-1.3.0.tgz",
+ "integrity": "sha512-EyLLwf9VKQCsMRTe0KwGe+ZAaFqmcYS5WW/qqPBNfvSuBaybNpdI+C72IQFr41X7cYQV58OgEL3bfDb1MBPGHQ==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
+ "@embedpdf/core": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -608,15 +631,16 @@
}
},
"node_modules/@embedpdf/plugin-scroll": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.2.1.tgz",
- "integrity": "sha512-I1haDXIOzs59uhOWEP6UvP5jzjcQHMLQuQbfRVJM0zdWU6t3jwSfcwPUI7iv4CAAepbuyJKL328yc8736r/FYw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.3.0.tgz",
+ "integrity": "sha512-o1n6Mkoc92BHAkoCX0mSLXgOj4uAkokNbvP+2QMijShzTsl95gU5UzK6siZ5o6WgZBznJcceYmLuPR5ODqZDWg==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-viewport": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-viewport": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -624,15 +648,16 @@
}
},
"node_modules/@embedpdf/plugin-search": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-1.2.1.tgz",
- "integrity": "sha512-sl9FBQzbOBtdmPpf6UI0bnWCTPWDkj47rTxyK07bpnGfGuFof4zhcxmMaFdyP7zqBh4Y9XqGu4A0uMTO2d/t7g==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-1.3.0.tgz",
+ "integrity": "sha512-DilSRfPQR38picjx7eyyuXNeduD7hcW/PjT9DZrjXxfLrAQtd17CXJs7HtJevl1wErh/CCSvZlHhjp1++O6GAg==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-loader": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-loader": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -640,16 +665,17 @@
}
},
"node_modules/@embedpdf/plugin-selection": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.2.1.tgz",
- "integrity": "sha512-wgG1X1sl6sed3pv7WLIO74SX0x3389/ax+/OLMty/LFbDNYMRO+n8ZQss8aUM700HARIqkPJy7UoSQt91o4nwA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.3.0.tgz",
+ "integrity": "sha512-1PEtreNofysaLxZvgO2CSNCxXhevjYnBdu4IHTFeJKXoq3ckKwkX8fJjyyN4D6+6uXZsnFkHhewl1yKCfKWAWw==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-interaction-manager": "1.2.1",
- "@embedpdf/plugin-viewport": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-interaction-manager": "1.3.0",
+ "@embedpdf/plugin-viewport": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -657,15 +683,16 @@
}
},
"node_modules/@embedpdf/plugin-spread": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-1.2.1.tgz",
- "integrity": "sha512-rpadnutT1wSdBQV7RQz40zYdKgCRgmJde/tamgB8oHQypcnZGQcAG6/ZfX5j12s9pG18hKwwL+KmMoBnXD9IjQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-1.3.0.tgz",
+ "integrity": "sha512-oRLimcod8RhdknN94CQeG+0QndQeiZKIhFUCXDIGxN1Z/qvspZCUty2TC+1kc3G318nZi55pWWphq9sB7ZpqEw==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-loader": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-loader": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -673,32 +700,34 @@
}
},
"node_modules/@embedpdf/plugin-thumbnail": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-1.2.1.tgz",
- "integrity": "sha512-TjHPkK8p3+FDMLcUdb3/4VREjm+liVooufLPVZ3FCXHbiC0PeUkqnwAxpCS2Jw1n+EtkY8pefRdRJeZhO6plOQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-1.3.0.tgz",
+ "integrity": "sha512-w2wzL7m6/sUF54sMVEi8Y8+7VE3BcZqI8THDqobkEkno4Dgmb77FHNPFD6YtAhaRmIoyPnlZf05RDd6Z8ohhkQ==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-render": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-render": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@embedpdf/plugin-tiling": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-1.2.1.tgz",
- "integrity": "sha512-C9uOGVIsoxUw+uQMXfJFZ8ibRLQeNOnaKC2izjx967iGu0ZoecAv+mKtH/Ge0vMEKYM1109AlF5T2EGwKQW2YA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-1.3.0.tgz",
+ "integrity": "sha512-huYi4BJa9KSfqC424bEHw72KBLCR2rfApMeKnpUzAFSdWA6MSYmVBSk8ghnU7XbcLuL6fFBarNsziNrSSnVWTw==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-render": "1.2.1",
- "@embedpdf/plugin-scroll": "1.2.1",
- "@embedpdf/plugin-viewport": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-render": "1.3.0",
+ "@embedpdf/plugin-scroll": "1.3.0",
+ "@embedpdf/plugin-viewport": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -706,14 +735,15 @@
}
},
"node_modules/@embedpdf/plugin-viewport": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.2.1.tgz",
- "integrity": "sha512-yvftOis7FLBjM3w2VYO5LXVKXoHkmFV/SPy7U6SbuLJTX126F4ohSij9euMHJjaqOgr5tBNvrf4xemVRglxM9w==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.3.0.tgz",
+ "integrity": "sha512-AZ7U8DEgEQ8nK5kdrqtukLl5au9NE3mIlFmloyo6Ddrt2rN/Jw1Lt9dsl6wU20GcFQX+hWsg9uAJboLq6AdOCA==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1"
+ "@embedpdf/models": "1.3.0"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
+ "@embedpdf/core": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -721,18 +751,19 @@
}
},
"node_modules/@embedpdf/plugin-zoom": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-1.2.1.tgz",
- "integrity": "sha512-hsp/nM4C8q0FM9P6FkpQLbU8IYawUgmiYgD3HXqHWBVRk30OIaXs4N0KC9vsHwn8ZAiyLl7jhlAXpgoacH5xEQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-1.3.0.tgz",
+ "integrity": "sha512-1VA9aFxoP+BoEpwlR0//jtlD9ESS8nhU8OGGHBRu7IgoWzIx4GqOHgpgXVxzFl9IaLOv69E9DVmwe/yaC6F+0g==",
+ "license": "MIT",
"dependencies": {
- "@embedpdf/models": "1.2.1",
+ "@embedpdf/models": "1.3.0",
"hammerjs": "^2.0.8"
},
"peerDependencies": {
- "@embedpdf/core": "1.2.1",
- "@embedpdf/plugin-interaction-manager": "1.2.1",
- "@embedpdf/plugin-scroll": "1.2.1",
- "@embedpdf/plugin-viewport": "1.2.1",
+ "@embedpdf/core": "1.3.0",
+ "@embedpdf/plugin-interaction-manager": "1.3.0",
+ "@embedpdf/plugin-scroll": "1.3.0",
+ "@embedpdf/plugin-viewport": "1.3.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
diff --git a/frontend/package.json b/frontend/package.json
index 0cd9713d0..f3ebfacf9 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -6,21 +6,22 @@
"proxy": "http://localhost:8080",
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
- "@embedpdf/core": "^1.2.1",
+ "@embedpdf/core": "^1.3.0",
"@embedpdf/engines": "^1.2.1",
- "@embedpdf/plugin-interaction-manager": "^1.2.1",
- "@embedpdf/plugin-loader": "^1.2.1",
- "@embedpdf/plugin-pan": "^1.2.1",
- "@embedpdf/plugin-render": "^1.2.1",
- "@embedpdf/plugin-rotate": "^1.2.1",
- "@embedpdf/plugin-scroll": "^1.2.1",
- "@embedpdf/plugin-search": "^1.2.1",
- "@embedpdf/plugin-selection": "^1.2.1",
- "@embedpdf/plugin-spread": "^1.2.1",
- "@embedpdf/plugin-thumbnail": "^1.2.1",
- "@embedpdf/plugin-tiling": "^1.2.1",
- "@embedpdf/plugin-viewport": "^1.2.1",
- "@embedpdf/plugin-zoom": "^1.2.1",
+ "@embedpdf/plugin-export": "^1.3.0",
+ "@embedpdf/plugin-interaction-manager": "^1.3.0",
+ "@embedpdf/plugin-loader": "^1.3.0",
+ "@embedpdf/plugin-pan": "^1.3.0",
+ "@embedpdf/plugin-render": "^1.3.0",
+ "@embedpdf/plugin-rotate": "^1.3.0",
+ "@embedpdf/plugin-scroll": "^1.3.0",
+ "@embedpdf/plugin-search": "^1.3.0",
+ "@embedpdf/plugin-selection": "^1.3.0",
+ "@embedpdf/plugin-spread": "^1.3.0",
+ "@embedpdf/plugin-thumbnail": "^1.3.0",
+ "@embedpdf/plugin-tiling": "^1.3.0",
+ "@embedpdf/plugin-viewport": "^1.3.0",
+ "@embedpdf/plugin-zoom": "^1.3.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@iconify/react": "^6.0.2",
diff --git a/frontend/src/components/shared/RightRail.tsx b/frontend/src/components/shared/RightRail.tsx
index 8e970e551..92e9daac0 100644
--- a/frontend/src/components/shared/RightRail.tsx
+++ b/frontend/src/components/shared/RightRail.tsx
@@ -66,6 +66,9 @@ export default function RightRail() {
const { totalItems, selectedCount } = getSelectionState();
+ // Get export state for viewer mode
+ const exportState = viewerContext?.getExportState?.();
+
const handleSelectAll = useCallback(() => {
if (currentView === 'fileEditor' || currentView === 'viewer') {
// Select all file IDs
@@ -96,7 +99,10 @@ export default function RightRail() {
}, [currentView, setSelectedFiles, pageEditorFunctions]);
const handleExportAll = useCallback(() => {
- if (currentView === 'fileEditor' || currentView === 'viewer') {
+ if (currentView === 'viewer') {
+ // Use EmbedPDF export functionality for viewer mode
+ viewerContext?.exportActions?.download();
+ } else if (currentView === 'fileEditor') {
// Download selected files (or all if none selected)
const filesToDownload = selectedFiles.length > 0 ? selectedFiles : activeFiles;
@@ -113,7 +119,7 @@ export default function RightRail() {
// Export all pages (not just selected)
pageEditorFunctions?.onExportAll?.();
}
- }, [currentView, activeFiles, selectedFiles, pageEditorFunctions]);
+ }, [currentView, activeFiles, selectedFiles, pageEditorFunctions, viewerContext]);
const handleCloseSelected = useCallback(() => {
if (currentView !== 'fileEditor') return;
@@ -445,7 +451,9 @@ export default function RightRail() {
radius="md"
className="right-rail-icon"
onClick={handleExportAll}
- disabled={currentView === 'viewer' || totalItems === 0}
+ disabled={
+ currentView === 'viewer' ? !exportState?.canExport : totalItems === 0
+ }
>
diff --git a/frontend/src/components/viewer/ExportAPIBridge.tsx b/frontend/src/components/viewer/ExportAPIBridge.tsx
new file mode 100644
index 000000000..20983bc92
--- /dev/null
+++ b/frontend/src/components/viewer/ExportAPIBridge.tsx
@@ -0,0 +1,25 @@
+import { useEffect } from 'react';
+import { useExportCapability } from '@embedpdf/plugin-export/react';
+import { useViewer } from '../../contexts/ViewerContext';
+
+/**
+ * Component that runs inside EmbedPDF context and provides export functionality
+ */
+export function ExportAPIBridge() {
+ const { provides: exportApi } = useExportCapability();
+ const { registerBridge } = useViewer();
+
+ useEffect(() => {
+ if (exportApi) {
+ // Register this bridge with ViewerContext
+ registerBridge('export', {
+ state: {
+ canExport: true,
+ },
+ api: exportApi
+ });
+ }
+ }, [exportApi, registerBridge]);
+
+ return null;
+}
\ No newline at end of file
diff --git a/frontend/src/components/viewer/LocalEmbedPDF.tsx b/frontend/src/components/viewer/LocalEmbedPDF.tsx
index 52c2ff2fd..3c4159d6d 100644
--- a/frontend/src/components/viewer/LocalEmbedPDF.tsx
+++ b/frontend/src/components/viewer/LocalEmbedPDF.tsx
@@ -17,6 +17,7 @@ import { SpreadPluginPackage, SpreadMode } from '@embedpdf/plugin-spread/react';
import { SearchPluginPackage } from '@embedpdf/plugin-search/react';
import { ThumbnailPluginPackage } from '@embedpdf/plugin-thumbnail/react';
import { RotatePluginPackage, Rotate } from '@embedpdf/plugin-rotate/react';
+import { ExportPluginPackage } from '@embedpdf/plugin-export/react';
import { Rotation } from '@embedpdf/models';
import { CustomSearchLayer } from './CustomSearchLayer';
import { ZoomAPIBridge } from './ZoomAPIBridge';
@@ -29,6 +30,7 @@ import { SpreadAPIBridge } from './SpreadAPIBridge';
import { SearchAPIBridge } from './SearchAPIBridge';
import { ThumbnailAPIBridge } from './ThumbnailAPIBridge';
import { RotateAPIBridge } from './RotateAPIBridge';
+import { ExportAPIBridge } from './ExportAPIBridge';
interface LocalEmbedPDFProps {
file?: File | Blob;
@@ -112,6 +114,11 @@ export function LocalEmbedPDF({ file, url }: LocalEmbedPDFProps) {
createPluginRegistration(RotatePluginPackage, {
defaultRotation: Rotation.Degree0, // Start with no rotation
}),
+
+ // Register export plugin for downloading PDFs
+ createPluginRegistration(ExportPluginPackage, {
+ defaultFileName: 'document.pdf',
+ }),
];
}, [pdfUrl]);
@@ -170,6 +177,7 @@ export function LocalEmbedPDF({ file, url }: LocalEmbedPDFProps) {
+
{ toPromise: () => Promise };
}
+interface ExportAPIWrapper {
+ download: () => void;
+ saveAsCopy: () => { toPromise: () => Promise };
+}
+
// State interfaces - represent the shape of data from each bridge
interface ScrollState {
@@ -93,6 +98,10 @@ interface SearchState {
activeIndex: number;
}
+interface ExportState {
+ canExport: boolean;
+}
+
// Bridge registration interface - bridges register with state and API
interface BridgeRef {
state: TState;
@@ -122,6 +131,7 @@ interface ViewerContextType {
getRotationState: () => RotationState;
getSearchState: () => SearchState;
getThumbnailAPI: () => ThumbnailAPIWrapper | null;
+ getExportState: () => ExportState;
// Immediate update callbacks
registerImmediateZoomUpdate: (callback: (percent: number) => void) => void;
@@ -179,6 +189,11 @@ interface ViewerContextType {
clear: () => void;
};
+ exportActions: {
+ download: () => void;
+ saveAsCopy: () => Promise;
+ };
+
// Bridge registration - internal use by bridges
registerBridge: (type: string, ref: BridgeRef) => void;
}
@@ -203,6 +218,7 @@ export const ViewerProvider: React.FC = ({ children }) => {
spread: null as BridgeRef | null,
rotation: null as BridgeRef | null,
thumbnail: null as BridgeRef | null,
+ export: null as BridgeRef | null,
});
// Immediate zoom callback for responsive display updates
@@ -238,6 +254,9 @@ export const ViewerProvider: React.FC = ({ children }) => {
case 'thumbnail':
bridgeRefs.current.thumbnail = ref as BridgeRef;
break;
+ case 'export':
+ bridgeRefs.current.export = ref as BridgeRef;
+ break;
}
};
@@ -278,6 +297,10 @@ export const ViewerProvider: React.FC = ({ children }) => {
return bridgeRefs.current.thumbnail?.api || null;
};
+ const getExportState = (): ExportState => {
+ return bridgeRefs.current.export?.state || { canExport: false };
+ };
+
// Action handlers - call APIs directly
const scrollActions = {
scrollToPage: (page: number) => {
@@ -473,6 +496,28 @@ export const ViewerProvider: React.FC = ({ children }) => {
}
};
+ const exportActions = {
+ download: () => {
+ const api = bridgeRefs.current.export?.api;
+ if (api?.download) {
+ api.download();
+ }
+ },
+ saveAsCopy: async () => {
+ const api = bridgeRefs.current.export?.api;
+ if (api?.saveAsCopy) {
+ try {
+ const result = api.saveAsCopy();
+ return await result.toPromise();
+ } catch (error) {
+ console.error('Failed to save PDF copy:', error);
+ return null;
+ }
+ }
+ return null;
+ }
+ };
+
const registerImmediateZoomUpdate = (callback: (percent: number) => void) => {
immediateZoomUpdateCallback.current = callback;
};
@@ -507,6 +552,7 @@ export const ViewerProvider: React.FC = ({ children }) => {
getRotationState,
getSearchState,
getThumbnailAPI,
+ getExportState,
// Immediate updates
registerImmediateZoomUpdate,
@@ -522,6 +568,7 @@ export const ViewerProvider: React.FC = ({ children }) => {
spreadActions,
rotationActions,
searchActions,
+ exportActions,
// Bridge registration
registerBridge,