mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-12-30 20:06:30 +01:00
initial commit for manual redaction tool
This commit is contained in:
parent
8060934ee9
commit
013122cb25
517
frontend/package-lock.json
generated
517
frontend/package-lock.json
generated
@ -10,24 +10,25 @@
|
||||
"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.3.14",
|
||||
"@embedpdf/engines": "^1.3.14",
|
||||
"@embedpdf/plugin-annotation": "^1.3.14",
|
||||
"@embedpdf/plugin-export": "^1.3.14",
|
||||
"@embedpdf/plugin-history": "^1.3.14",
|
||||
"@embedpdf/plugin-interaction-manager": "^1.3.14",
|
||||
"@embedpdf/plugin-loader": "^1.3.14",
|
||||
"@embedpdf/plugin-pan": "^1.3.14",
|
||||
"@embedpdf/plugin-render": "^1.3.14",
|
||||
"@embedpdf/plugin-rotate": "^1.3.14",
|
||||
"@embedpdf/plugin-scroll": "^1.3.14",
|
||||
"@embedpdf/plugin-search": "^1.3.14",
|
||||
"@embedpdf/plugin-selection": "^1.3.14",
|
||||
"@embedpdf/plugin-spread": "^1.3.14",
|
||||
"@embedpdf/plugin-thumbnail": "^1.3.14",
|
||||
"@embedpdf/plugin-tiling": "^1.3.14",
|
||||
"@embedpdf/plugin-viewport": "^1.3.14",
|
||||
"@embedpdf/plugin-zoom": "^1.3.14",
|
||||
"@embedpdf/core": "^1.4.1",
|
||||
"@embedpdf/engines": "^1.4.1",
|
||||
"@embedpdf/plugin-annotation": "^1.4.1",
|
||||
"@embedpdf/plugin-export": "^1.4.1",
|
||||
"@embedpdf/plugin-history": "^1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "^1.4.1",
|
||||
"@embedpdf/plugin-loader": "^1.4.1",
|
||||
"@embedpdf/plugin-pan": "^1.4.1",
|
||||
"@embedpdf/plugin-redaction": "^1.4.1",
|
||||
"@embedpdf/plugin-render": "^1.4.1",
|
||||
"@embedpdf/plugin-rotate": "^1.4.1",
|
||||
"@embedpdf/plugin-scroll": "^1.4.1",
|
||||
"@embedpdf/plugin-search": "^1.4.1",
|
||||
"@embedpdf/plugin-selection": "^1.4.1",
|
||||
"@embedpdf/plugin-spread": "^1.4.1",
|
||||
"@embedpdf/plugin-thumbnail": "^1.4.1",
|
||||
"@embedpdf/plugin-tiling": "^1.4.1",
|
||||
"@embedpdf/plugin-viewport": "^1.4.1",
|
||||
"@embedpdf/plugin-zoom": "^1.4.1",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@iconify/react": "^6.0.2",
|
||||
@ -502,63 +503,65 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/core": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.3.14.tgz",
|
||||
"integrity": "sha512-lE/vfhA53CxamaCfGWEibrEPr+JeZT42QCF+cOELUwv4+Zt6b+IE6+4wsznx/8wjjJYwllXJ3GJ/un1UzTqARw==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.4.1.tgz",
|
||||
"integrity": "sha512-TGpxn2CvAKRnOJWJ3bsK+dKBiCp75ehxftRUmv7wAmPomhnG5XrDfoWJungvO+zbbqAwso6PocdeXINVt3hlAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/engines": "1.3.14",
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/engines": "1.4.1",
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/engines": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-1.3.14.tgz",
|
||||
"integrity": "sha512-+/FPW2gAzj2lQYvsMH/Oj9+MEXgkyEuyYDC+HFkltTuXvmiP2S/3BD0YslZDX9K4BzcmMxnWB+BiQpNJokbDVg==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-1.4.1.tgz",
|
||||
"integrity": "sha512-yugIb5OwTI/1VnAaEvSYxAd2DvYBPkV/D7wytagyaOq98o3sqzcY2Q9zHt+LhnawA5KKG1e/FDPjCd4qm8gsvg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14",
|
||||
"@embedpdf/pdfium": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1",
|
||||
"@embedpdf/pdfium": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/models": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-1.3.14.tgz",
|
||||
"integrity": "sha512-BujY4bmr8b2DQdoZkOge03SzoRVoWxzfIQATLSPPtp4WiFh1U4BPp6cADlGuCwGkp6zBcH/aM4h8PwwA75d/eg==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-1.4.1.tgz",
|
||||
"integrity": "sha512-2nTg8Q1qpplBvspZJXMCZOA+/OILpfdNRPddlplxZXY/Upx0rzKXx/e6pXWW7AuOgtfGneT4h9tMs3A595/PdQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@embedpdf/pdfium": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-1.3.14.tgz",
|
||||
"integrity": "sha512-TQMZabXzHmzvvfPwopubFcYgQuYV7POvMgjICYu3Pgfn3sgr+UdIUh3aNXR/COcl3q8sXPMFQ2GDuyOHR9QQnA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-1.4.1.tgz",
|
||||
"integrity": "sha512-BekKEK4UNCwzj7xOffKn6WpL0FQHxq+mTj2iGI3N7OwAX2J/BO2G+rDOB+lvojQG+Dkpg8uqm427ZKJDRyLgVQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-annotation": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-annotation/-/plugin-annotation-1.3.14.tgz",
|
||||
"integrity": "sha512-JJYqEWwUKCdBZsXCDq/CW96p3pVLn8N+XZ4W3OyL7djI2fvYC9x6ys9m82vwlSathAVOxk1D7xXiY8AzJQVF0Q==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-annotation/-/plugin-annotation-1.4.1.tgz",
|
||||
"integrity": "sha512-d4HibNy6ecyDqx2Y2R8VjaqppSdjNofAJmU6VenOd88wn080sAUqvnkeVJ6ehJH5BoND4ymQrcAkcbVeYK0myA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14",
|
||||
"@embedpdf/utils": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1",
|
||||
"@embedpdf/utils": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-history": "1.3.14",
|
||||
"@embedpdf/plugin-interaction-manager": "1.3.14",
|
||||
"@embedpdf/plugin-selection": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-history": "1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "1.4.1",
|
||||
"@embedpdf/plugin-selection": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
@ -566,31 +569,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-export": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-export/-/plugin-export-1.3.14.tgz",
|
||||
"integrity": "sha512-fMGp2YxvI4uTRIViUKxfnJts2Jw/vktEM45XUNGNSjT/kAW6znVNgdceYjpK++xU8CGs2grAQ1i5UvMd3aRNDA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-export/-/plugin-export-1.4.1.tgz",
|
||||
"integrity": "sha512-g89fREFM/zkt2Ai2Q5dWwDkhXgC/JmVyUniaMgm1fTG/MZ0Z05E7f34DUzX/CKcJyVjxEgl6tojBTMeUbm15bA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-history": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-1.3.14.tgz",
|
||||
"integrity": "sha512-77hnNLp0W0FHw8lT7SeqzCgp8bOClfeOAPZdcInu/jPDhVASUGYbtE/0fkLhiaqPH7kyMirNCLif4sF6n4b5vg==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-1.4.1.tgz",
|
||||
"integrity": "sha512-5WLDiNMH6tACkLGGv/lJtNsDeozOhSbrh0mjD1btHun8u7Yscu/Vf8tdJRUOsd+nULivo2nQ2NFNKu0OTbVo8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
@ -598,49 +602,71 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-interaction-manager": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.3.14.tgz",
|
||||
"integrity": "sha512-nR0ZxNoTQtGqOHhweFh6QJ+nUJ4S4Ag1wWur6vAUAi8U95HUOfZhOEa0polZo0zR9WmmblGqRWjFM+mVSOoi1w==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.4.1.tgz",
|
||||
"integrity": "sha512-Ng02S9SFIAi9JZS5rI+NXSnZZ1Yk9YYRw4MlN2pig49qOyivZdz0oScZaYxQPewo8ccJkLeghjdeWswOBW/6cA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-loader": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.3.14.tgz",
|
||||
"integrity": "sha512-KoJX1MacEWE2DrO1OeZeG/Ehz76//u+ida/xb4r9BfwqAp5TfYlksq09cOvcF8LMW5FY4pbAL+AHKI1Hjz+HNA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.4.1.tgz",
|
||||
"integrity": "sha512-m3ZOk8JygsLxoa4cZ+0BVB5pfRWuBCg2/gPqjhoFZNKTqAFw4J6HGUrhYKg94GRYe+w1cTJl/NbTBYuU5DOrsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-pan": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-1.3.14.tgz",
|
||||
"integrity": "sha512-7EG+I5nn8yDCV8pT4x/g5mv7zJli2t3wPrh6Kt8uIpUorPHNb6J0Z67gl0uc/8rEasNzuKOuT0er46Y6/UYLzQ==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-1.4.1.tgz",
|
||||
"integrity": "sha512-zmOZJ9dUqXiaV0F5GPf/5WTWf3jAEkiv153Tl3x8HT9Rfff+WQhV48NruCIBAy/T4jVt4aH7D1zt/B/ftvcdkA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-interaction-manager": "1.3.14",
|
||||
"@embedpdf/plugin-viewport": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "1.4.1",
|
||||
"@embedpdf/plugin-viewport": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-redaction": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-redaction/-/plugin-redaction-1.4.1.tgz",
|
||||
"integrity": "sha512-lyVIDxAwU8mUbhxh8J1dhWZ90086YSZ1+RB50hfCAyaxftRF3XpHPhmLZhr6lr3z1lDx+w9VIcoCU6IvhcweTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.4.1",
|
||||
"@embedpdf/utils": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "1.4.1",
|
||||
"@embedpdf/plugin-selection": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
@ -648,182 +674,192 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-render": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.3.14.tgz",
|
||||
"integrity": "sha512-IPj7GCQXJBsY++JaU+z7y+FwX5NaDBj4YYV6hsHNtSGf42Y1AdlwJzDYetivG2bA84xmk7KgD1X2Y3eIFBhjwA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.4.1.tgz",
|
||||
"integrity": "sha512-gKCdNKw6WBHBEpTc2DLBWIWOxzsNnaNbpfeY6C4f2Bum0EO+XW3Hl2oIx1uaRHjIhhnXso1J3QweqelsPwDGwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-rotate": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-1.3.14.tgz",
|
||||
"integrity": "sha512-OroEm11x/fPPXI9C0X+nm9LOjwaI0MvsToZRH+HpV60/FbQeOJvt6D8wThCDVLK95Na6A+JeYIMEu+Hiix7H+A==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-1.4.1.tgz",
|
||||
"integrity": "sha512-hVzHkKwMNH3tUhxqJGsj5qTLpYZXbj6E74AEcG0w/fz5FrK7EnofPqt0gRfYmIzxnQGIh+39BRtcp8gmx8UNnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-scroll": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.3.14.tgz",
|
||||
"integrity": "sha512-fQbt7OlRMLQJMuZj/Bzh0qpRxMw1ld5Qe/OTw8N54b/plljnFA52joE7cITl3H03huWWyHS3NKOScbw7f34dog==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.4.1.tgz",
|
||||
"integrity": "sha512-Y9O+matB4j4fLim5s/jn7qIi+lMC9vmDJRpJhiWe8bvD9oYLP2xfD/DdhFgAjRKcNhPoxC+j8q8QN5BMeGAv2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-viewport": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-viewport": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-search": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-1.3.14.tgz",
|
||||
"integrity": "sha512-tlZEgR2tG+GSNnh2u1SjCxhUHfTDgcr38sE/xRK1bRLDGPZWlr6Ln7qP7JSWqeYBGni75sGrj0iZqcZbPWyJag==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-1.4.1.tgz",
|
||||
"integrity": "sha512-8JG4CbOcUsLuT0vHJJ4cECmu+Yn53EokWFUVXi2Mo/XvHjhrQuWmD7+y6s/qQPEpctFYWmUCXTDAX9ynPud+2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-loader": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-loader": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-selection": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.3.14.tgz",
|
||||
"integrity": "sha512-EXENuaAsse3rT6cjA1nYzyrNvoy62ojJl28wblCng6zcs3HSlGPemIQZAvaYKPUxoY608M+6nKlcMQ5neRnk/A==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.4.1.tgz",
|
||||
"integrity": "sha512-lo5Ytk1PH0PrRKv6zKVupm4t02VGsqIrnSIeP6NO8Ujx0wfqEhj//sqIuO/EwfFVJD8lcQIP9UUo9y8baCrEog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-interaction-manager": "1.3.14",
|
||||
"@embedpdf/plugin-viewport": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "1.4.1",
|
||||
"@embedpdf/plugin-viewport": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-spread": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-1.3.14.tgz",
|
||||
"integrity": "sha512-DVlk6tDgUoDRkp2S4Jc3LrRTuf4DPMlph9vywJw5z6Qpbh0vgcMnObg896/S0Eu5FgACNAj0WGcXpLrcrn5b9Q==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-1.4.1.tgz",
|
||||
"integrity": "sha512-l+SrDVGTiiItkt2cEtzv7V/X5HhmLbYHcQ8CFobGeIKdJtzKS1Nu/JSKqg7Ki7eCNgyPL1yMNfNE92bNKYVN4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-loader": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-loader": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-thumbnail": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-1.3.14.tgz",
|
||||
"integrity": "sha512-cnwb5dG8Jph8XSArys1WFCQ6kK2R5FKoO0B5mDrHFv9Fcm2pKszlmZC/NDoskX4pgNUgSnwhI1X3cP37ebF9Ng==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-1.4.1.tgz",
|
||||
"integrity": "sha512-bN3msjI0PovazgbPK3LyugYVTwIDo0RyBUhBaG42FgJxeY3hmFOWTPgfUH1QF7twHlySnksIvHRFYR3nViryVw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-render": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-render": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-tiling": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-1.3.14.tgz",
|
||||
"integrity": "sha512-SaCTo2LdZwGeE6jCqkwJxvwt8YKbsI3QGxa9S7Ez+5OcBchlhHeTfLQswcErDQ3WH2p8WHtGuucAcOLrVVOm0A==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-1.4.1.tgz",
|
||||
"integrity": "sha512-wgTfj5T8HV6KP61iiR63DVNrbVp8sPxTqa1Sm+2/D0jY+EPSSCmpt1/qYWiAXd1X+t78foOjCnfbo7fEMn5/pg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-render": "1.3.14",
|
||||
"@embedpdf/plugin-scroll": "1.3.14",
|
||||
"@embedpdf/plugin-viewport": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-render": "1.4.1",
|
||||
"@embedpdf/plugin-scroll": "1.4.1",
|
||||
"@embedpdf/plugin-viewport": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-viewport": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.3.14.tgz",
|
||||
"integrity": "sha512-mfJ7EbbU68eKk6oFvQ4ozGJNpxUxWbjQ5Gm3uuB+Gj5/tWgBocBOX36k/9LgivEEeX7g2S0tOgyErljApmH8Vg==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.4.1.tgz",
|
||||
"integrity": "sha512-+TgFHKPCLTBiDYe2DdsmTS37hwQgcZ3dYIc7bE0l5cp+GVwouu1h0MTmjL+90loizeWwCiu10E/zXR6hz+CUaQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14"
|
||||
"@embedpdf/models": "1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/plugin-zoom": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-1.3.14.tgz",
|
||||
"integrity": "sha512-/N5tyMk+8OzhObrS3O9yPkcmX8EPiuTo+WaT2QCVSmIUqKnOO4AnKpHJ6Vl0uVhcuXHCMwLucZKyhJ7tRqavwg==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-1.4.1.tgz",
|
||||
"integrity": "sha512-9HocmXnPZxqN06q7kyNAmLjgDHOEW8/8QfgNE3nMpRyNHIgnAjxvsWc9lApgp5ErDPG0cSDt0Cduil6nB3wSBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@embedpdf/models": "1.3.14",
|
||||
"@embedpdf/models": "1.4.1",
|
||||
"hammerjs": "^2.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@embedpdf/core": "1.3.14",
|
||||
"@embedpdf/plugin-interaction-manager": "1.3.14",
|
||||
"@embedpdf/plugin-scroll": "1.3.14",
|
||||
"@embedpdf/plugin-viewport": "1.3.14",
|
||||
"@embedpdf/core": "1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "1.4.1",
|
||||
"@embedpdf/plugin-scroll": "1.4.1",
|
||||
"@embedpdf/plugin-viewport": "1.4.1",
|
||||
"preact": "^10.26.4",
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"svelte": ">=5 <6",
|
||||
"vue": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embedpdf/utils": {
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/utils/-/utils-1.3.14.tgz",
|
||||
"integrity": "sha512-gxEJD12nageCMqAjdbicNfDQolXU3nvnV0EX96OdZITRNj0Q1tisutVYoaxcCiJu3vvIEOzipjsAnQOubbFCEA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@embedpdf/utils/-/utils-1.4.1.tgz",
|
||||
"integrity": "sha512-vvJ51Qsz3PyJWR2YvDMMpJXg4+YqdV7Vn2cusmW9sx+4EnAiBiw0HevEE+FepgFV8k+A0WbwXzmsujDIQJ7R4A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"preact": "^10.26.4",
|
||||
@ -3045,6 +3081,16 @@
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/acorn-typescript": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz",
|
||||
"integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.13.5",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz",
|
||||
@ -3802,7 +3848,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/gapi": {
|
||||
@ -4605,13 +4650,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz",
|
||||
"integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz",
|
||||
"integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.3",
|
||||
"@vue/shared": "3.5.21",
|
||||
"@babel/parser": "^7.28.4",
|
||||
"@vue/shared": "3.5.22",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
@ -4636,28 +4681,28 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz",
|
||||
"integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz",
|
||||
"integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.21",
|
||||
"@vue/shared": "3.5.21"
|
||||
"@vue/compiler-core": "3.5.22",
|
||||
"@vue/shared": "3.5.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz",
|
||||
"integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.22.tgz",
|
||||
"integrity": "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.3",
|
||||
"@vue/compiler-core": "3.5.21",
|
||||
"@vue/compiler-dom": "3.5.21",
|
||||
"@vue/compiler-ssr": "3.5.21",
|
||||
"@vue/shared": "3.5.21",
|
||||
"@babel/parser": "^7.28.4",
|
||||
"@vue/compiler-core": "3.5.22",
|
||||
"@vue/compiler-dom": "3.5.22",
|
||||
"@vue/compiler-ssr": "3.5.22",
|
||||
"@vue/shared": "3.5.22",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.18",
|
||||
"magic-string": "^0.30.19",
|
||||
"postcss": "^8.5.6",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
@ -4669,67 +4714,67 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz",
|
||||
"integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.22.tgz",
|
||||
"integrity": "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.21",
|
||||
"@vue/shared": "3.5.21"
|
||||
"@vue/compiler-dom": "3.5.22",
|
||||
"@vue/shared": "3.5.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz",
|
||||
"integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz",
|
||||
"integrity": "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.21"
|
||||
"@vue/shared": "3.5.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz",
|
||||
"integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.22.tgz",
|
||||
"integrity": "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.21",
|
||||
"@vue/shared": "3.5.21"
|
||||
"@vue/reactivity": "3.5.22",
|
||||
"@vue/shared": "3.5.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz",
|
||||
"integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.22.tgz",
|
||||
"integrity": "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.21",
|
||||
"@vue/runtime-core": "3.5.21",
|
||||
"@vue/shared": "3.5.21",
|
||||
"@vue/reactivity": "3.5.22",
|
||||
"@vue/runtime-core": "3.5.22",
|
||||
"@vue/shared": "3.5.22",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz",
|
||||
"integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.22.tgz",
|
||||
"integrity": "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.21",
|
||||
"@vue/shared": "3.5.21"
|
||||
"@vue/compiler-ssr": "3.5.22",
|
||||
"@vue/shared": "3.5.22"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.5.21"
|
||||
"vue": "3.5.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz",
|
||||
"integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz",
|
||||
"integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
@ -4743,7 +4788,6 @@
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
@ -5147,6 +5191,16 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axobject-query": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz",
|
||||
@ -7176,6 +7230,13 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/esm-env": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
|
||||
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||
@ -7234,6 +7295,16 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/esrap": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.1.tgz",
|
||||
"integrity": "sha512-ebTT9B6lOtZGMgJ3o5r12wBacHctG7oEWazIda8UlPfA3HD/Wrv8FdXoVo73vzdpwCxNyXjPauyN2bbJzMkB9A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/esrecurse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||
@ -8747,6 +8818,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-reference": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
|
||||
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/is-regex": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
||||
@ -9623,6 +9704,13 @@
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-character": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@ -12959,6 +13047,42 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.43.0.tgz",
|
||||
"integrity": "sha512-1sRxVbgJAB+UGzwkc3GUoiBSzEOf0jqzccMaVoI2+pI+kASUe9qubslxace8+Mzhqw19k4syTA5niCIJwfXpOA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||
"@types/estree": "^1.0.5",
|
||||
"acorn": "^8.12.1",
|
||||
"aria-query": "^5.3.1",
|
||||
"axobject-query": "^4.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
"esm-env": "^1.2.1",
|
||||
"esrap": "^2.1.0",
|
||||
"is-reference": "^3.0.3",
|
||||
"locate-character": "^3.0.0",
|
||||
"magic-string": "^0.30.11",
|
||||
"zimmerframe": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte/node_modules/aria-query": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/symbol-tree": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
||||
@ -14026,17 +14150,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.21",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz",
|
||||
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
||||
"version": "3.5.22",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
||||
"integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.21",
|
||||
"@vue/compiler-sfc": "3.5.21",
|
||||
"@vue/runtime-dom": "3.5.21",
|
||||
"@vue/server-renderer": "3.5.21",
|
||||
"@vue/shared": "3.5.21"
|
||||
"@vue/compiler-dom": "3.5.22",
|
||||
"@vue/compiler-sfc": "3.5.22",
|
||||
"@vue/runtime-dom": "3.5.22",
|
||||
"@vue/server-renderer": "3.5.22",
|
||||
"@vue/shared": "3.5.22"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
@ -14447,6 +14571,13 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zimmerframe": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
|
||||
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
|
||||
@ -6,24 +6,25 @@
|
||||
"proxy": "http://localhost:8080",
|
||||
"dependencies": {
|
||||
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
|
||||
"@embedpdf/core": "^1.3.14",
|
||||
"@embedpdf/engines": "^1.3.14",
|
||||
"@embedpdf/plugin-annotation": "^1.3.14",
|
||||
"@embedpdf/plugin-export": "^1.3.14",
|
||||
"@embedpdf/plugin-history": "^1.3.14",
|
||||
"@embedpdf/plugin-interaction-manager": "^1.3.14",
|
||||
"@embedpdf/plugin-loader": "^1.3.14",
|
||||
"@embedpdf/plugin-pan": "^1.3.14",
|
||||
"@embedpdf/plugin-render": "^1.3.14",
|
||||
"@embedpdf/plugin-rotate": "^1.3.14",
|
||||
"@embedpdf/plugin-scroll": "^1.3.14",
|
||||
"@embedpdf/plugin-search": "^1.3.14",
|
||||
"@embedpdf/plugin-selection": "^1.3.14",
|
||||
"@embedpdf/plugin-spread": "^1.3.14",
|
||||
"@embedpdf/plugin-thumbnail": "^1.3.14",
|
||||
"@embedpdf/plugin-tiling": "^1.3.14",
|
||||
"@embedpdf/plugin-viewport": "^1.3.14",
|
||||
"@embedpdf/plugin-zoom": "^1.3.14",
|
||||
"@embedpdf/core": "^1.4.1",
|
||||
"@embedpdf/engines": "^1.4.1",
|
||||
"@embedpdf/plugin-annotation": "^1.4.1",
|
||||
"@embedpdf/plugin-export": "^1.4.1",
|
||||
"@embedpdf/plugin-history": "^1.4.1",
|
||||
"@embedpdf/plugin-interaction-manager": "^1.4.1",
|
||||
"@embedpdf/plugin-loader": "^1.4.1",
|
||||
"@embedpdf/plugin-pan": "^1.4.1",
|
||||
"@embedpdf/plugin-redaction": "^1.4.1",
|
||||
"@embedpdf/plugin-render": "^1.4.1",
|
||||
"@embedpdf/plugin-rotate": "^1.4.1",
|
||||
"@embedpdf/plugin-scroll": "^1.4.1",
|
||||
"@embedpdf/plugin-search": "^1.4.1",
|
||||
"@embedpdf/plugin-selection": "^1.4.1",
|
||||
"@embedpdf/plugin-spread": "^1.4.1",
|
||||
"@embedpdf/plugin-thumbnail": "^1.4.1",
|
||||
"@embedpdf/plugin-tiling": "^1.4.1",
|
||||
"@embedpdf/plugin-viewport": "^1.4.1",
|
||||
"@embedpdf/plugin-zoom": "^1.4.1",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@iconify/react": "^6.0.2",
|
||||
|
||||
@ -68,6 +68,11 @@
|
||||
color: var(--right-rail-icon);
|
||||
}
|
||||
|
||||
.right-rail-icon--active {
|
||||
background-color: var(--accent-interactive) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.right-rail-icon[aria-disabled="true"],
|
||||
.right-rail-icon[disabled] {
|
||||
color: var(--right-rail-icon-disabled) !important;
|
||||
|
||||
@ -0,0 +1,671 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { createPluginRegistration } from '@embedpdf/core';
|
||||
import { EmbedPDF } from '@embedpdf/core/react';
|
||||
import { usePdfiumEngine } from '@embedpdf/engines/react';
|
||||
import { Viewport, ViewportPluginPackage } from '@embedpdf/plugin-viewport/react';
|
||||
import { Scroller, ScrollPluginPackage, ScrollStrategy } from '@embedpdf/plugin-scroll/react';
|
||||
import { LoaderPluginPackage } from '@embedpdf/plugin-loader/react';
|
||||
import { RenderPluginPackage } from '@embedpdf/plugin-render/react';
|
||||
import { ZoomPluginPackage } from '@embedpdf/plugin-zoom/react';
|
||||
import { InteractionManagerPluginPackage, PagePointerProvider, GlobalPointerProvider } from '@embedpdf/plugin-interaction-manager/react';
|
||||
import { SelectionLayer, SelectionPluginPackage } from '@embedpdf/plugin-selection/react';
|
||||
import { TilingLayer, TilingPluginPackage } from '@embedpdf/plugin-tiling/react';
|
||||
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 { HistoryPluginPackage } from '@embedpdf/plugin-history/react';
|
||||
import { RedactionPluginPackage, RedactionLayer, useRedaction } from '@embedpdf/plugin-redaction/react';
|
||||
import type { SelectionMenuProps } from '@embedpdf/plugin-redaction/react';
|
||||
import { Stack, Group, Text, Button, Alert, Loader } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CropFreeRoundedIcon from '@mui/icons-material/CropFreeRounded';
|
||||
import TextFieldsRoundedIcon from '@mui/icons-material/TextFieldsRounded';
|
||||
import UndoRoundedIcon from '@mui/icons-material/UndoRounded';
|
||||
import RedoRoundedIcon from '@mui/icons-material/RedoRounded';
|
||||
import ToolLoadingFallback from '@app/components/tools/ToolLoadingFallback';
|
||||
import { alert } from '@app/components/toast';
|
||||
import { useRightRailButtons, type RightRailButtonWithAction } from '@app/hooks/useRightRailButtons';
|
||||
import { useNavigationActions } from '@app/contexts/NavigationContext';
|
||||
import type { ManualRedactionWorkbenchData } from '@app/types/redact';
|
||||
|
||||
interface ManualRedactionWorkbenchViewProps {
|
||||
data: ManualRedactionWorkbenchData | null;
|
||||
}
|
||||
|
||||
const toPdfBlob = async (value: any): Promise<Blob | null> => {
|
||||
if (!value) return null;
|
||||
if (value instanceof Blob) return value;
|
||||
if (value instanceof ArrayBuffer) return new Blob([value], { type: 'application/pdf' });
|
||||
if (value instanceof Uint8Array) {
|
||||
const copy = new Uint8Array(value.byteLength);
|
||||
copy.set(value);
|
||||
return new Blob([copy.buffer], { type: 'application/pdf' });
|
||||
}
|
||||
if (value.data instanceof ArrayBuffer) return new Blob([value.data], { type: 'application/pdf' });
|
||||
if (value.blob instanceof Blob) return value.blob;
|
||||
if (typeof value.toBlob === 'function') {
|
||||
return value.toBlob();
|
||||
}
|
||||
if (typeof value.toPromise === 'function') {
|
||||
const result = await value.toPromise();
|
||||
if (result instanceof ArrayBuffer) return new Blob([result], { type: 'application/pdf' });
|
||||
}
|
||||
if (typeof value.arrayBuffer === 'function') {
|
||||
const buffer = await value.arrayBuffer();
|
||||
return new Blob([buffer], { type: 'application/pdf' });
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const buildRedactedFileName = (name: string | undefined | null) => {
|
||||
if (!name || name.trim() === '') {
|
||||
return 'redacted.pdf';
|
||||
}
|
||||
|
||||
const lower = name.toLowerCase();
|
||||
if (lower.includes('redacted')) {
|
||||
return name;
|
||||
}
|
||||
|
||||
const dotIndex = name.lastIndexOf('.');
|
||||
if (dotIndex === -1) {
|
||||
return `${name}_redacted.pdf`;
|
||||
}
|
||||
|
||||
const base = name.slice(0, dotIndex);
|
||||
const ext = name.slice(dotIndex);
|
||||
return `${base}_redacted${ext}`;
|
||||
};
|
||||
|
||||
const ManualRedactionWorkbenchView = ({ data }: ManualRedactionWorkbenchViewProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { actions: navigationActions } = useNavigationActions();
|
||||
const redactionApiRef = useRef<Record<string, any> | null>(null);
|
||||
const exportApiRef = useRef<Record<string, any> | null>(null);
|
||||
const selectionApiRef = useRef<Record<string, any> | null>(null);
|
||||
const historyApiRef = useRef<Record<string, any> | null>(null);
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
const [isApplying, setIsApplying] = useState(false);
|
||||
const [canUndo, setCanUndo] = useState(false);
|
||||
const [canRedo, setCanRedo] = useState(false);
|
||||
const [activeType, setActiveType] = useState<string | null>(null);
|
||||
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
||||
const [objectUrl, setObjectUrl] = useState<string | null>(null);
|
||||
const selectedFile = data?.file ?? null;
|
||||
const redactionPluginPackage = RedactionPluginPackage;
|
||||
const RedactionLayerComponent = RedactionLayer;
|
||||
const hasRedactionSupport = Boolean(redactionPluginPackage && RedactionLayerComponent);
|
||||
const exitWorkbench = useCallback(() => {
|
||||
if (data?.onExit) {
|
||||
data.onExit();
|
||||
} else {
|
||||
navigationActions.setWorkbench('fileEditor');
|
||||
}
|
||||
}, [data, navigationActions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedFile) {
|
||||
const url = URL.createObjectURL(selectedFile);
|
||||
setPdfUrl(url);
|
||||
setObjectUrl(url);
|
||||
return () => {
|
||||
URL.revokeObjectURL(url);
|
||||
setObjectUrl(null);
|
||||
};
|
||||
}
|
||||
|
||||
setPdfUrl(null);
|
||||
return () => {};
|
||||
}, [selectedFile]);
|
||||
|
||||
const { engine, isLoading, error } = usePdfiumEngine();
|
||||
|
||||
const plugins = useMemo(() => {
|
||||
if (!pdfUrl) return [];
|
||||
|
||||
const rootFontSize = typeof window !== 'undefined'
|
||||
? parseFloat(getComputedStyle(document.documentElement).fontSize)
|
||||
: 16;
|
||||
const viewportGap = rootFontSize * 3.5;
|
||||
|
||||
const baseRegistrations: any[] = [
|
||||
createPluginRegistration(LoaderPluginPackage, {
|
||||
loadingOptions: {
|
||||
type: 'url',
|
||||
pdfFile: {
|
||||
id: 'stirling-pdf-manual-redaction',
|
||||
url: pdfUrl,
|
||||
},
|
||||
},
|
||||
}),
|
||||
createPluginRegistration(ViewportPluginPackage, { viewportGap }),
|
||||
createPluginRegistration(ScrollPluginPackage, {
|
||||
strategy: ScrollStrategy.Vertical,
|
||||
initialPage: 0,
|
||||
}),
|
||||
createPluginRegistration(RenderPluginPackage),
|
||||
createPluginRegistration(InteractionManagerPluginPackage),
|
||||
createPluginRegistration(SelectionPluginPackage),
|
||||
createPluginRegistration(HistoryPluginPackage),
|
||||
// Intentionally omit Pan plugin here so drag gestures are captured by redaction/selection layers
|
||||
createPluginRegistration(ZoomPluginPackage, {
|
||||
defaultZoomLevel: 1.2,
|
||||
minZoom: 0.25,
|
||||
maxZoom: 4,
|
||||
}),
|
||||
createPluginRegistration(TilingPluginPackage, {
|
||||
tileSize: 768,
|
||||
overlapPx: 5,
|
||||
extraRings: 1,
|
||||
}),
|
||||
createPluginRegistration(SpreadPluginPackage, {
|
||||
defaultSpreadMode: SpreadMode.None,
|
||||
}),
|
||||
createPluginRegistration(SearchPluginPackage),
|
||||
createPluginRegistration(ThumbnailPluginPackage),
|
||||
createPluginRegistration(RotatePluginPackage),
|
||||
createPluginRegistration(ExportPluginPackage, {
|
||||
defaultFileName: buildRedactedFileName(data?.fileName),
|
||||
}),
|
||||
];
|
||||
if (hasRedactionSupport) {
|
||||
baseRegistrations.splice(6, 0, createPluginRegistration(redactionPluginPackage, { autoPreview: true }));
|
||||
}
|
||||
return baseRegistrations;
|
||||
}, [pdfUrl, data?.fileName, hasRedactionSupport, redactionPluginPackage]);
|
||||
|
||||
const assignPluginApi = useCallback((plugin: any, ref: React.MutableRefObject<Record<string, any> | null>, onReady?: () => void) => {
|
||||
if (!plugin || typeof plugin.provides !== 'function') return;
|
||||
|
||||
try {
|
||||
const provided = plugin.provides();
|
||||
if (provided && typeof provided.then === 'function') {
|
||||
provided
|
||||
.then((resolved: any) => {
|
||||
ref.current = resolved ?? null;
|
||||
onReady?.();
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.warn('[manual-redaction] Failed to resolve plugin capability', err);
|
||||
});
|
||||
} else {
|
||||
ref.current = provided ?? null;
|
||||
onReady?.();
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[manual-redaction] Plugin capability unavailable', err);
|
||||
}
|
||||
}, [hasRedactionSupport]);
|
||||
|
||||
const handleInitialized = useCallback(async (registry: any) => {
|
||||
const redactionPlugin = hasRedactionSupport ? registry.getPlugin?.('redaction') : null;
|
||||
const exportPlugin = registry.getPlugin?.('export');
|
||||
const historyPlugin = registry.getPlugin?.('history');
|
||||
|
||||
if (hasRedactionSupport) {
|
||||
assignPluginApi(redactionPlugin, redactionApiRef, () => {
|
||||
setIsReady(true);
|
||||
// default to area redaction mode
|
||||
enableAreaRedaction();
|
||||
// no pan plugin: drags go to redaction/selection layers
|
||||
// subscribe to state changes to drive undo/redo availability
|
||||
try {
|
||||
const api = redactionApiRef.current;
|
||||
api?.onStateChange?.((state: any) => {
|
||||
// heuristics: if there are any pending or previous operations, enable undo
|
||||
const pending = Number(state?.pendingCount ?? 0);
|
||||
setCanUndo(pending > 0 || Boolean(state?.canUndo));
|
||||
setCanRedo(Boolean(state?.canRedo));
|
||||
setActiveType(state?.activeType ?? null);
|
||||
});
|
||||
} catch {}
|
||||
});
|
||||
} else {
|
||||
setIsReady(false);
|
||||
}
|
||||
assignPluginApi(exportPlugin, exportApiRef);
|
||||
assignPluginApi(historyPlugin, historyApiRef);
|
||||
const selectionPlugin = registry.getPlugin?.('selection');
|
||||
assignPluginApi(selectionPlugin, selectionApiRef);
|
||||
}, [assignPluginApi, hasRedactionSupport]);
|
||||
|
||||
const invokeRedactionMethod = useCallback((names: string[], args: any[] = []) => {
|
||||
if (!hasRedactionSupport) return false;
|
||||
const api = redactionApiRef.current;
|
||||
if (!api) return false;
|
||||
for (const name of names) {
|
||||
const candidate = (api as Record<string, any>)[name];
|
||||
if (typeof candidate === 'function') {
|
||||
try {
|
||||
const result = candidate.apply(api, args);
|
||||
if (result && typeof result.then === 'function') {
|
||||
// Fire and forget for interactive methods
|
||||
result.catch((err: any) => console.warn(`[manual-redaction] ${name} failed`, err));
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.warn(`[manual-redaction] ${name} threw`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, []);
|
||||
|
||||
const invokeRedactionMethodAsync = useCallback(async (names: string[], args: any[] = []) => {
|
||||
if (!hasRedactionSupport) return false;
|
||||
const api = redactionApiRef.current;
|
||||
if (!api) return false;
|
||||
for (const name of names) {
|
||||
const candidate = (api as Record<string, any>)[name];
|
||||
if (typeof candidate === 'function') {
|
||||
try {
|
||||
const result = candidate.apply(api, args);
|
||||
if (result && typeof result.then === 'function') {
|
||||
await result;
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.warn(`[manual-redaction] ${name} failed`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, []);
|
||||
|
||||
const enableAreaRedaction = useCallback(() => {
|
||||
if (!hasRedactionSupport) return;
|
||||
const api = redactionApiRef.current;
|
||||
// Ensure selection plugin is not intercepting as text selection
|
||||
try { selectionApiRef.current?.setMode?.('none'); } catch {}
|
||||
// Prefer official capability
|
||||
if (api?.toggleMarqueeRedact) {
|
||||
try { api.toggleMarqueeRedact(); setActiveType('marqueeRedact'); return; } catch {}
|
||||
}
|
||||
// Fall back to common method names
|
||||
const areaNames = ['area', 'box', 'rectangle', 'shape'];
|
||||
for (const mode of areaNames) {
|
||||
if (invokeRedactionMethod(['activateAreaRedaction', 'startAreaRedaction', 'enableAreaRedaction', 'activateMode'], [mode])) return;
|
||||
if (invokeRedactionMethod(['setRedactionMode', 'setMode'], [mode])) return;
|
||||
if (invokeRedactionMethod(['setRedactionMode', 'setMode'], [{ mode }])) return;
|
||||
if (invokeRedactionMethod(['setMode'], [{ type: mode }])) return;
|
||||
if (invokeRedactionMethod(['setMode'], [mode.toUpperCase?.() ?? mode])) return;
|
||||
}
|
||||
console.warn('[manual-redaction] No compatible area redaction activation method found');
|
||||
}, [hasRedactionSupport, invokeRedactionMethod]);
|
||||
|
||||
const enableTextRedaction = useCallback(() => {
|
||||
if (!hasRedactionSupport) return;
|
||||
const api = redactionApiRef.current;
|
||||
// Ensure selection plugin is in text mode when redacting text
|
||||
try { selectionApiRef.current?.setMode?.('text'); } catch {}
|
||||
if (api?.toggleRedactSelection) {
|
||||
try { api.toggleRedactSelection(); setActiveType('redactSelection'); return; } catch {}
|
||||
}
|
||||
const textModes = ['text', 'search', 'pattern'];
|
||||
for (const mode of textModes) {
|
||||
if (invokeRedactionMethod(['activateTextRedaction', 'startTextRedaction', 'enableTextRedaction', 'activateMode'], [mode])) return;
|
||||
if (invokeRedactionMethod(['setRedactionMode', 'setMode'], [mode])) return;
|
||||
if (invokeRedactionMethod(['setRedactionMode', 'setMode'], [{ mode }])) return;
|
||||
if (invokeRedactionMethod(['setMode'], [{ type: mode }])) return;
|
||||
if (invokeRedactionMethod(['setMode'], [mode.toUpperCase?.() ?? mode])) return;
|
||||
}
|
||||
console.warn('[manual-redaction] No compatible text redaction activation method found');
|
||||
}, [hasRedactionSupport, invokeRedactionMethod]);
|
||||
|
||||
const handleUndo = useCallback(() => {
|
||||
if (!hasRedactionSupport) return;
|
||||
// Prefer redaction-aware undo
|
||||
if (invokeRedactionMethod(['undo', 'stepBack', 'undoLast'])) {
|
||||
return;
|
||||
}
|
||||
// Fallback: remove the most recent pending mark if available
|
||||
try {
|
||||
const state = (redactionApiRef.current?.getState?.() as any) || {};
|
||||
const pendingMap = state.pending || {};
|
||||
const pages = Object.keys(pendingMap).map(n => parseInt(n, 10)).sort((a,b) => b-a);
|
||||
for (const page of pages) {
|
||||
const items = pendingMap[page];
|
||||
const last = Array.isArray(items) ? items[items.length - 1] : null;
|
||||
if (last) {
|
||||
redactionApiRef.current?.removePending?.(page, last.id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
const historyApi = historyApiRef.current;
|
||||
if (historyApi && typeof historyApi.undo === 'function') {
|
||||
historyApi.undo();
|
||||
return;
|
||||
}
|
||||
console.warn('[manual-redaction] Undo not available');
|
||||
}, [hasRedactionSupport, invokeRedactionMethod]);
|
||||
|
||||
const handleRedo = useCallback(() => {
|
||||
if (!hasRedactionSupport) return;
|
||||
if (invokeRedactionMethod(['redo', 'stepForward', 'redoLast'])) {
|
||||
return;
|
||||
}
|
||||
const historyApi = historyApiRef.current;
|
||||
if (historyApi && typeof historyApi.redo === 'function') {
|
||||
historyApi.redo();
|
||||
return;
|
||||
}
|
||||
console.warn('[manual-redaction] Redo not available');
|
||||
}, [hasRedactionSupport, invokeRedactionMethod]);
|
||||
|
||||
const exportRedactedBlob = useCallback(async (): Promise<Blob | null> => {
|
||||
if (!hasRedactionSupport) {
|
||||
throw new Error('Manual redaction plugin is not available.');
|
||||
}
|
||||
const redactionApi = redactionApiRef.current;
|
||||
const exportApi = exportApiRef.current;
|
||||
|
||||
const tryCall = async (api: Record<string, any> | null, method: string, args: any[] = []): Promise<any> => {
|
||||
if (!api) return null;
|
||||
const candidate = api[method];
|
||||
if (typeof candidate !== 'function') return null;
|
||||
try {
|
||||
const result = candidate.apply(api, args);
|
||||
if (result && typeof result.then === 'function') {
|
||||
return await result;
|
||||
}
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.warn(`[manual-redaction] ${method} failed`, err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const attempts: Array<[Record<string, any> | null, string, any[]]> = [
|
||||
[redactionApi, 'exportRedactedDocument', [{ type: 'blob' }]],
|
||||
[redactionApi, 'exportRedactedDocument', []],
|
||||
[redactionApi, 'getRedactedDocument', []],
|
||||
[redactionApi, 'getBlob', []],
|
||||
[redactionApi, 'download', [{ type: 'blob' }]],
|
||||
[exportApi, 'exportDocument', [{ type: 'blob' }]],
|
||||
[exportApi, 'exportDocument', []],
|
||||
[exportApi, 'download', [{ type: 'blob' }]],
|
||||
];
|
||||
|
||||
for (const [api, method, args] of attempts) {
|
||||
const result = await tryCall(api, method, args);
|
||||
const blob = await toPdfBlob(result);
|
||||
if (blob) return blob;
|
||||
}
|
||||
|
||||
// Fallback: some export APIs return handles with toPromise()
|
||||
if (exportApi && typeof exportApi.saveAsCopy === 'function') {
|
||||
const handle = exportApi.saveAsCopy();
|
||||
const blob = await toPdfBlob(handle);
|
||||
if (blob) return blob;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [hasRedactionSupport]);
|
||||
|
||||
const handleApplyAndSave = useCallback(async () => {
|
||||
if (!selectedFile) {
|
||||
alert({
|
||||
alertType: 'error',
|
||||
title: t('redact.manual.noFileSelected', 'No PDF selected'),
|
||||
body: t('redact.manual.noFileSelectedBody', 'Select a PDF before opening the redaction editor.'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setIsApplying(true);
|
||||
try {
|
||||
const applied = await invokeRedactionMethodAsync([
|
||||
'applyRedactions',
|
||||
'applyPendingRedactions',
|
||||
'apply',
|
||||
'commit',
|
||||
'finalizeRedactions',
|
||||
'performRedactions',
|
||||
]);
|
||||
|
||||
if (!applied) {
|
||||
console.warn('[manual-redaction] No compatible apply method found');
|
||||
}
|
||||
|
||||
const blob = await exportRedactedBlob();
|
||||
if (!blob) {
|
||||
throw new Error('Unable to export redacted PDF');
|
||||
}
|
||||
|
||||
const outputName = buildRedactedFileName(selectedFile.name);
|
||||
const exportedFile = new File([blob], outputName, { type: 'application/pdf' });
|
||||
|
||||
if (data?.onExport) {
|
||||
await data.onExport(exportedFile);
|
||||
}
|
||||
|
||||
alert({
|
||||
alertType: 'success',
|
||||
title: t('redact.manual.exportSuccess', 'Redacted copy saved'),
|
||||
body: t('redact.manual.exportSuccessBody', 'A redacted PDF has been added to your files.'),
|
||||
});
|
||||
|
||||
exitWorkbench();
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : t('redact.manual.exportUnknownError', 'Failed to export redacted PDF.');
|
||||
alert({
|
||||
alertType: 'error',
|
||||
title: t('redact.manual.exportFailed', 'Export failed'),
|
||||
body: message,
|
||||
});
|
||||
} finally {
|
||||
setIsApplying(false);
|
||||
}
|
||||
}, [data, exitWorkbench, exportRedactedBlob, invokeRedactionMethodAsync, navigationActions, selectedFile, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isReady || !hasRedactionSupport) return;
|
||||
return () => {
|
||||
setIsReady(false);
|
||||
redactionApiRef.current = null;
|
||||
exportApiRef.current = null;
|
||||
historyApiRef.current = null;
|
||||
};
|
||||
}, [hasRedactionSupport, isReady, objectUrl]);
|
||||
|
||||
const rightRailButtons = useMemo<RightRailButtonWithAction[]>(() => ([
|
||||
{
|
||||
id: 'manual-redaction-area',
|
||||
icon: <CropFreeRoundedIcon fontSize="small" />,
|
||||
tooltip: t('redact.manual.buttons.area', 'Mark area for redaction'),
|
||||
ariaLabel: t('redact.manual.buttons.area', 'Mark area for redaction'),
|
||||
section: 'top',
|
||||
order: 0,
|
||||
disabled: !isReady || !hasRedactionSupport,
|
||||
className: activeType === 'marqueeRedact' ? 'right-rail-icon--active' : undefined,
|
||||
onClick: enableAreaRedaction,
|
||||
},
|
||||
{
|
||||
id: 'manual-redaction-text',
|
||||
icon: <TextFieldsRoundedIcon fontSize="small" />,
|
||||
tooltip: t('redact.manual.buttons.text', 'Mark text for redaction'),
|
||||
ariaLabel: t('redact.manual.buttons.text', 'Mark text for redaction'),
|
||||
section: 'top',
|
||||
order: 1,
|
||||
disabled: !isReady || !hasRedactionSupport,
|
||||
className: activeType === 'redactSelection' ? 'right-rail-icon--active' : undefined,
|
||||
onClick: enableTextRedaction,
|
||||
},
|
||||
{
|
||||
id: 'manual-redaction-undo',
|
||||
icon: <UndoRoundedIcon fontSize="small" />,
|
||||
tooltip: t('redact.manual.buttons.undo', 'Undo last change'),
|
||||
ariaLabel: t('redact.manual.buttons.undo', 'Undo last change'),
|
||||
section: 'top',
|
||||
order: 2,
|
||||
disabled: !isReady || !hasRedactionSupport || !canUndo,
|
||||
onClick: handleUndo,
|
||||
},
|
||||
{
|
||||
id: 'manual-redaction-redo',
|
||||
icon: <RedoRoundedIcon fontSize="small" />,
|
||||
tooltip: t('redact.manual.buttons.redo', 'Redo change'),
|
||||
ariaLabel: t('redact.manual.buttons.redo', 'Redo change'),
|
||||
section: 'top',
|
||||
order: 3,
|
||||
disabled: !isReady || !hasRedactionSupport || !canRedo,
|
||||
onClick: handleRedo,
|
||||
},
|
||||
]), [enableAreaRedaction, enableTextRedaction, handleUndo, handleRedo, hasRedactionSupport, isReady, t, canUndo, canRedo]);
|
||||
|
||||
useRightRailButtons(rightRailButtons);
|
||||
|
||||
if (!selectedFile) {
|
||||
return (
|
||||
<Stack gap="md" p="lg" h="100%" align="center" justify="center">
|
||||
<Alert color="blue" variant="light">
|
||||
{t('redact.manual.selectFilePrompt', 'Select a single PDF from the sidebar to start manual redaction.')}
|
||||
</Alert>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading || !engine || !pdfUrl) {
|
||||
return <ToolLoadingFallback toolName="Manual Redaction Viewer" />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<Stack gap="sm" align="center" justify="center" h="100%" p="xl">
|
||||
<Alert color="red" variant="light" title={t('redact.manual.loadFailed', 'Unable to open PDF')}>
|
||||
{error.message}
|
||||
</Alert>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap="sm" h="100%" p="md" className="manual-redaction-workbench">
|
||||
<Group justify="space-between" align="center">
|
||||
<Stack gap={2}>
|
||||
<Text fw={600}>{t('redact.manual.editorHeading', 'Manual redaction')}</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
{t('redact.manual.editorSubheading', 'Draw rectangles or search for text to mark redactions, then apply the changes.')}
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed">
|
||||
{t('redact.manual.currentFile', 'Current file: {{name}}', { name: selectedFile.name })}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Group gap="sm">
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={exitWorkbench}
|
||||
>
|
||||
{t('redact.manual.exit', 'Back to files')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="filled"
|
||||
color="dark"
|
||||
onClick={handleApplyAndSave}
|
||||
disabled={!isReady || isApplying}
|
||||
leftSection={isApplying ? <Loader size="xs" color="white" /> : undefined}
|
||||
>
|
||||
{isApplying
|
||||
? t('redact.manual.applying', 'Applying…')
|
||||
: t('redact.manual.applyAndSave', 'Apply & save copy')}
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
minWidth: 0,
|
||||
position: 'relative',
|
||||
borderRadius: '0.5rem',
|
||||
overflow: 'hidden',
|
||||
boxShadow: 'var(--shadow-md)',
|
||||
backgroundColor: 'var(--bg-elevated)',
|
||||
}}
|
||||
>
|
||||
<EmbedPDF
|
||||
engine={engine}
|
||||
plugins={plugins}
|
||||
onInitialized={handleInitialized}
|
||||
>
|
||||
<GlobalPointerProvider>
|
||||
<Viewport
|
||||
style={{
|
||||
backgroundColor: 'var(--bg-background)',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
maxHeight: '100%',
|
||||
maxWidth: '100%',
|
||||
overflow: 'auto',
|
||||
position: 'relative',
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
minWidth: 0,
|
||||
contain: 'strict',
|
||||
}}
|
||||
>
|
||||
<Scroller
|
||||
renderPage={({ document, width, height, pageIndex, scale, rotation }) => (
|
||||
<Rotate key={document?.id} pageSize={{ width, height }}>
|
||||
<PagePointerProvider pageIndex={pageIndex} pageWidth={width} pageHeight={height} scale={scale} rotation={rotation}>
|
||||
<div
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
position: 'relative',
|
||||
userSelect: 'none',
|
||||
WebkitUserSelect: 'none',
|
||||
MozUserSelect: 'none',
|
||||
msUserSelect: 'none',
|
||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
|
||||
backgroundColor: 'white',
|
||||
cursor: activeType === 'marqueeRedact' ? 'crosshair' : activeType === 'redactSelection' ? 'text' : 'auto',
|
||||
}}
|
||||
>
|
||||
<TilingLayer pageIndex={pageIndex} scale={scale} />
|
||||
<SelectionLayer pageIndex={pageIndex} scale={scale} />
|
||||
{hasRedactionSupport && RedactionLayerComponent && (
|
||||
<RedactionLayerComponent
|
||||
pageIndex={pageIndex}
|
||||
scale={scale}
|
||||
rotation={rotation}
|
||||
selectionMenu={(props: SelectionMenuProps) => <InlineRedactionMenu {...props} />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</PagePointerProvider>
|
||||
</Rotate>
|
||||
)}
|
||||
/>
|
||||
</Viewport>
|
||||
</GlobalPointerProvider>
|
||||
</EmbedPDF>
|
||||
</div>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManualRedactionWorkbenchView;
|
||||
|
||||
// Inline redaction menu displayed beneath selection/rectangle
|
||||
function InlineRedactionMenu({ item, selected, menuWrapperProps }: SelectionMenuProps) {
|
||||
const { provides } = useRedaction();
|
||||
if (!selected) return null;
|
||||
return (
|
||||
<div {...menuWrapperProps} style={{ ...menuWrapperProps?.style, pointerEvents: 'auto' }}>
|
||||
<Group gap="xs" p={4} style={{ background: 'var(--bg-surface)', border: '1px solid var(--border-default)', borderRadius: 8, boxShadow: 'var(--shadow-sm)' }}>
|
||||
<Button size="xs" color="red" onClick={() => provides?.commitPending?.(item.page, item.id)}>
|
||||
Apply
|
||||
</Button>
|
||||
<Button size="xs" variant="default" onClick={() => provides?.removePending?.(item.page, item.id)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Group>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -24,7 +24,6 @@ export default function RedactModeSelector({ mode, onModeChange, disabled }: Red
|
||||
{
|
||||
value: 'manual' as const,
|
||||
label: t('redact.modeSelector.manual', 'Manual'),
|
||||
disabled: true, // Keep manual mode disabled until implemented
|
||||
},
|
||||
]}
|
||||
disabled={disabled}
|
||||
|
||||
@ -15,7 +15,7 @@ export const useRedactModeTips = (): TooltipContent => {
|
||||
},
|
||||
{
|
||||
title: t("redact.tooltip.mode.manual.title", "Manual Redaction"),
|
||||
description: t("redact.tooltip.mode.manual.text", "Click and drag to manually select specific areas to redact. Gives you precise control over what gets redacted. (Coming soon)")
|
||||
description: t("redact.tooltip.mode.manual.text", "Click and drag to manually select specific areas or search for text to redact. Gives you precise control over what gets removed.")
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@ -17,8 +17,7 @@ export const buildRedactFormData = (parameters: RedactParameters, file: File): F
|
||||
formData.append("customPadding", parameters.customPadding.toString());
|
||||
formData.append("convertPDFToImage", parameters.convertPDFToImage.toString());
|
||||
} else {
|
||||
// Manual mode parameters would go here when implemented
|
||||
throw new Error('Manual redaction not yet implemented');
|
||||
throw new Error('Manual redaction is handled directly in the editor');
|
||||
}
|
||||
|
||||
return formData;
|
||||
@ -30,12 +29,11 @@ export const redactOperationConfig = {
|
||||
buildFormData: buildRedactFormData,
|
||||
operationType: 'redact',
|
||||
endpoint: (parameters: RedactParameters) => {
|
||||
if (parameters.mode === 'automatic') {
|
||||
return '/api/v1/security/auto-redact';
|
||||
} else {
|
||||
// Manual redaction endpoint would go here when implemented
|
||||
throw new Error('Manual redaction not yet implemented');
|
||||
}
|
||||
if (parameters.mode === 'automatic') {
|
||||
return '/api/v1/security/auto-redact';
|
||||
} else {
|
||||
throw new Error('Manual redaction is handled directly in the editor');
|
||||
}
|
||||
},
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
@ -34,15 +34,13 @@ export const useRedactParameters = (): RedactParametersHook => {
|
||||
if (params.mode === 'automatic') {
|
||||
return '/api/v1/security/auto-redact';
|
||||
}
|
||||
// Manual redaction endpoint would go here when implemented
|
||||
throw new Error('Manual redaction not yet implemented');
|
||||
return '';
|
||||
},
|
||||
validateFn: (params) => {
|
||||
if (params.mode === 'automatic') {
|
||||
return params.wordsToRedact.length > 0 && params.wordsToRedact.some(word => word.trim().length > 0);
|
||||
}
|
||||
// Manual mode validation would go here when implemented
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Alert, Button, Stack, Text } from "@mantine/core";
|
||||
import VisibilityOffRoundedIcon from "@mui/icons-material/VisibilityOffRounded";
|
||||
import { createToolFlow } from "@app/components/tools/shared/createToolFlow";
|
||||
import type { MiddleStepConfig } from "@app/components/tools/shared/createToolFlow";
|
||||
import RedactModeSelector from "@app/components/tools/redact/RedactModeSelector";
|
||||
import { useRedactParameters } from "@app/hooks/tools/redact/useRedactParameters";
|
||||
import { useRedactOperation } from "@app/hooks/tools/redact/useRedactOperation";
|
||||
@ -9,9 +12,28 @@ import { BaseToolProps, ToolComponent } from "@app/types/tool";
|
||||
import { useRedactModeTips, useRedactWordsTips, useRedactAdvancedTips } from "@app/components/tooltips/useRedactTips";
|
||||
import RedactAdvancedSettings from "@app/components/tools/redact/RedactAdvancedSettings";
|
||||
import WordsToRedactInput from "@app/components/tools/redact/WordsToRedactInput";
|
||||
import { useToolWorkflow } from "@app/contexts/ToolWorkflowContext";
|
||||
import { useNavigationActions, useNavigationState } from "@app/contexts/NavigationContext";
|
||||
import ManualRedactionWorkbenchView from "@app/components/tools/redact/ManualRedactionWorkbenchView";
|
||||
import type { ManualRedactionWorkbenchData } from "@app/types/redact";
|
||||
import { useFileContext } from "@app/contexts/file/fileHooks";
|
||||
import type { StirlingFile } from "@app/types/fileContext";
|
||||
|
||||
const MANUAL_VIEW_ID = "manualRedactionWorkbench";
|
||||
const MANUAL_WORKBENCH_ID = "custom:manualRedactionWorkbench" as const;
|
||||
|
||||
const Redact = (props: BaseToolProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
registerCustomWorkbenchView,
|
||||
unregisterCustomWorkbenchView,
|
||||
setCustomWorkbenchViewData,
|
||||
clearCustomWorkbenchViewData,
|
||||
} = useToolWorkflow();
|
||||
const { actions: navigationActions } = useNavigationActions();
|
||||
const navigationState = useNavigationState();
|
||||
const { actions: fileActions } = useFileContext();
|
||||
const manualWorkbenchIcon = useMemo(() => <VisibilityOffRoundedIcon fontSize="small" />, []);
|
||||
|
||||
// State for managing step collapse status
|
||||
const [methodCollapsed, setMethodCollapsed] = useState(false);
|
||||
@ -25,14 +47,92 @@ const Redact = (props: BaseToolProps) => {
|
||||
props
|
||||
);
|
||||
|
||||
const createManualWorkbenchData = useCallback((file: StirlingFile): ManualRedactionWorkbenchData => ({
|
||||
fileId: file.fileId,
|
||||
file,
|
||||
fileName: file.name,
|
||||
onExport: async (exportedFile: File) => {
|
||||
await fileActions.addFiles([exportedFile], { selectFiles: true });
|
||||
},
|
||||
onExit: () => {
|
||||
clearCustomWorkbenchViewData(MANUAL_VIEW_ID);
|
||||
navigationActions.setWorkbench('fileEditor');
|
||||
},
|
||||
}), [clearCustomWorkbenchViewData, fileActions, navigationActions]);
|
||||
|
||||
const handleOpenManualEditor = useCallback(() => {
|
||||
if (base.selectedFiles.length !== 1) {
|
||||
return;
|
||||
}
|
||||
const [selected] = base.selectedFiles as [StirlingFile];
|
||||
const workbenchData = createManualWorkbenchData(selected);
|
||||
setCustomWorkbenchViewData(MANUAL_VIEW_ID, workbenchData);
|
||||
navigationActions.setWorkbench(MANUAL_WORKBENCH_ID);
|
||||
}, [base.selectedFiles, createManualWorkbenchData, navigationActions, setCustomWorkbenchViewData]);
|
||||
|
||||
useEffect(() => {
|
||||
registerCustomWorkbenchView({
|
||||
id: MANUAL_VIEW_ID,
|
||||
workbenchId: MANUAL_WORKBENCH_ID,
|
||||
label: t('redact.manual.workbenchLabel', 'Manual redaction'),
|
||||
icon: manualWorkbenchIcon,
|
||||
component: ManualRedactionWorkbenchView,
|
||||
});
|
||||
|
||||
return () => {
|
||||
clearCustomWorkbenchViewData(MANUAL_VIEW_ID);
|
||||
unregisterCustomWorkbenchView(MANUAL_VIEW_ID);
|
||||
};
|
||||
}, [
|
||||
clearCustomWorkbenchViewData,
|
||||
manualWorkbenchIcon,
|
||||
registerCustomWorkbenchView,
|
||||
t,
|
||||
unregisterCustomWorkbenchView,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (base.params.parameters.mode !== 'manual') {
|
||||
clearCustomWorkbenchViewData(MANUAL_VIEW_ID);
|
||||
if (navigationState.workbench === MANUAL_WORKBENCH_ID) {
|
||||
navigationActions.setWorkbench('fileEditor');
|
||||
}
|
||||
}
|
||||
}, [
|
||||
base.params.parameters.mode,
|
||||
clearCustomWorkbenchViewData,
|
||||
navigationActions,
|
||||
navigationState.workbench,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
navigationState.workbench !== MANUAL_WORKBENCH_ID ||
|
||||
base.params.parameters.mode !== 'manual' ||
|
||||
base.selectedFiles.length !== 1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const [selected] = base.selectedFiles as [StirlingFile];
|
||||
setCustomWorkbenchViewData(MANUAL_VIEW_ID, createManualWorkbenchData(selected));
|
||||
}, [
|
||||
base.params.parameters.mode,
|
||||
base.selectedFiles,
|
||||
createManualWorkbenchData,
|
||||
navigationState.workbench,
|
||||
setCustomWorkbenchViewData,
|
||||
]);
|
||||
|
||||
// Tooltips for each step
|
||||
const modeTips = useRedactModeTips();
|
||||
const wordsTips = useRedactWordsTips();
|
||||
const advancedTips = useRedactAdvancedTips();
|
||||
|
||||
const isManualMode = base.params.parameters.mode === 'manual';
|
||||
|
||||
const isExecuteDisabled = () => {
|
||||
if (base.params.parameters.mode === 'manual') {
|
||||
return true; // Manual mode not implemented yet
|
||||
if (isManualMode) {
|
||||
return true;
|
||||
}
|
||||
return !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled;
|
||||
};
|
||||
@ -44,7 +144,7 @@ const Redact = (props: BaseToolProps) => {
|
||||
|
||||
// Build conditional steps based on redaction mode
|
||||
const buildSteps = () => {
|
||||
const steps = [
|
||||
const steps: MiddleStepConfig[] = [
|
||||
// Method selection step (always present)
|
||||
{
|
||||
title: t("redact.modeSelector.title", "Redaction Method"),
|
||||
@ -62,7 +162,7 @@ const Redact = (props: BaseToolProps) => {
|
||||
];
|
||||
|
||||
// Add mode-specific steps
|
||||
if (base.params.parameters.mode === 'automatic') {
|
||||
if (!isManualMode && base.params.parameters.mode === 'automatic') {
|
||||
steps.push(
|
||||
{
|
||||
title: t("redact.auto.settings.title", "Redaction Settings"),
|
||||
@ -87,8 +187,43 @@ const Redact = (props: BaseToolProps) => {
|
||||
/>,
|
||||
},
|
||||
);
|
||||
} else if (base.params.parameters.mode === 'manual') {
|
||||
// Manual mode steps would go here when implemented
|
||||
} else if (isManualMode) {
|
||||
const manualHasFile = base.selectedFiles.length > 0;
|
||||
const manualHasSingleFile = base.selectedFiles.length === 1;
|
||||
const manualTooManyFiles = base.selectedFiles.length > 1;
|
||||
const selectedName = manualHasSingleFile ? base.selectedFiles[0].name : null;
|
||||
|
||||
steps.push({
|
||||
title: t("redact.manual.stepTitle", "Manual redaction editor"),
|
||||
isCollapsed: false,
|
||||
content: (
|
||||
<Stack gap="sm">
|
||||
<Text size="sm">
|
||||
{manualHasSingleFile
|
||||
? t("redact.manual.stepDescriptionSelected", "Launch the editor to mark redactions on {{file}}.", { file: selectedName })
|
||||
: t("redact.manual.stepDescription", "Open the embedded redaction editor to draw boxes or search for sensitive text.")}
|
||||
</Text>
|
||||
{manualTooManyFiles && (
|
||||
<Alert color="red" variant="light">
|
||||
{t("redact.manual.multipleNotSupported", "Manual redaction works on one PDF at a time. Deselect extra files to continue.")}
|
||||
</Alert>
|
||||
)}
|
||||
{!manualHasFile && (
|
||||
<Alert color="blue" variant="light">
|
||||
{t("redact.manual.noFileSelectedInfo", "Select a PDF from the file sidebar to begin manual redaction.")}
|
||||
</Alert>
|
||||
)}
|
||||
<Button
|
||||
variant="filled"
|
||||
color="dark"
|
||||
disabled={!manualHasSingleFile || manualTooManyFiles}
|
||||
onClick={handleOpenManualEditor}
|
||||
>
|
||||
{t("redact.manual.openEditorCta", "Open redaction editor")}
|
||||
</Button>
|
||||
</Stack>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return steps;
|
||||
@ -98,9 +233,10 @@ const Redact = (props: BaseToolProps) => {
|
||||
files: {
|
||||
selectedFiles: base.selectedFiles,
|
||||
isCollapsed: base.hasResults,
|
||||
minFiles: isManualMode ? 1 : undefined,
|
||||
},
|
||||
steps: buildSteps(),
|
||||
executeButton: {
|
||||
executeButton: isManualMode ? undefined : {
|
||||
text: t("redact.submit", "Redact"),
|
||||
isVisible: !base.hasResults,
|
||||
loadingText: t("loading"),
|
||||
@ -108,7 +244,7 @@ const Redact = (props: BaseToolProps) => {
|
||||
disabled: isExecuteDisabled(),
|
||||
},
|
||||
review: {
|
||||
isVisible: base.hasResults,
|
||||
isVisible: !isManualMode && base.hasResults,
|
||||
operation: base.operation,
|
||||
title: t("redact.title", "Redaction Results"),
|
||||
onFileClick: base.handleThumbnailClick,
|
||||
|
||||
11
frontend/src/core/types/redact.ts
Normal file
11
frontend/src/core/types/redact.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { FileId } from '@app/types/file';
|
||||
import type { StirlingFile } from '@app/types/fileContext';
|
||||
|
||||
export interface ManualRedactionWorkbenchData {
|
||||
fileId: FileId;
|
||||
file: StirlingFile | null;
|
||||
fileName: string;
|
||||
onExport?: (file: File) => Promise<void>;
|
||||
onExit?: () => void;
|
||||
contextId?: string;
|
||||
}
|
||||
6
frontend/src/global.d.ts
vendored
6
frontend/src/global.d.ts
vendored
@ -12,4 +12,10 @@ declare module 'assets/material-symbols-icons.json' {
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module '@embedpdf/plugin-redaction/react' {
|
||||
export const RedactionPluginPackage: any;
|
||||
export const RedactionLayer: any;
|
||||
export function useRedactionCapability(): { provides?: () => any } | undefined;
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user