From 687ab392864167441f1cabddcee27f16819fa920 Mon Sep 17 00:00:00 2001 From: Reece Browne Date: Thu, 11 Sep 2025 19:36:44 +0100 Subject: [PATCH] Text selection --- frontend/package-lock.json | 18 +++++++++++++++ frontend/package.json | 1 + .../src/components/viewer/LocalEmbedPDF.tsx | 17 +++++++++----- .../viewer/SelectionControlsExporter.tsx | 22 +++++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/viewer/SelectionControlsExporter.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6bd83b76c..3ba0d732e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,7 @@ "@embedpdf/plugin-loader": "^1.1.1", "@embedpdf/plugin-render": "^1.1.1", "@embedpdf/plugin-scroll": "^1.1.1", + "@embedpdf/plugin-selection": "^1.1.1", "@embedpdf/plugin-viewport": "^1.1.1", "@embedpdf/plugin-zoom": "^1.1.1", "@emotion/react": "^11.14.0", @@ -708,6 +709,23 @@ "vue": ">=3.2.0" } }, + "node_modules/@embedpdf/plugin-selection": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.1.1.tgz", + "integrity": "sha512-VHiLcXvM0a/bkWF2yAc7ltEIrwp1HHahtd5pMO0egODTqGKFzX6QhQ4PkL35KlVyDxMpowHj4pjgYYKPTqla0A==", + "dependencies": { + "@embedpdf/models": "1.1.1" + }, + "peerDependencies": { + "@embedpdf/core": "1.1.1", + "@embedpdf/plugin-interaction-manager": "1.1.1", + "@embedpdf/plugin-viewport": "1.1.1", + "preact": "^10.26.4", + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "vue": ">=3.2.0" + } + }, "node_modules/@embedpdf/plugin-viewport": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.1.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5a10c0387..16bae6f9e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "@embedpdf/plugin-loader": "^1.1.1", "@embedpdf/plugin-render": "^1.1.1", "@embedpdf/plugin-scroll": "^1.1.1", + "@embedpdf/plugin-selection": "^1.1.1", "@embedpdf/plugin-viewport": "^1.1.1", "@embedpdf/plugin-zoom": "^1.1.1", "@emotion/react": "^11.14.0", diff --git a/frontend/src/components/viewer/LocalEmbedPDF.tsx b/frontend/src/components/viewer/LocalEmbedPDF.tsx index d354fadcf..7c0d5191e 100644 --- a/frontend/src/components/viewer/LocalEmbedPDF.tsx +++ b/frontend/src/components/viewer/LocalEmbedPDF.tsx @@ -9,9 +9,11 @@ import { Scroller, ScrollPluginPackage, ScrollStrategy } from '@embedpdf/plugin- import { LoaderPluginPackage } from '@embedpdf/plugin-loader/react'; import { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/react'; import { ZoomPluginPackage, ZoomMode } from '@embedpdf/plugin-zoom/react'; -import { InteractionManagerPluginPackage } from '@embedpdf/plugin-interaction-manager/react'; +import { InteractionManagerPluginPackage, PagePointerProvider } from '@embedpdf/plugin-interaction-manager/react'; +import { SelectionLayer, SelectionPluginPackage } from '@embedpdf/plugin-selection/react'; import { ZoomControlsExporter } from './ZoomControlsExporter'; import { ScrollControlsExporter } from './ScrollControlsExporter'; +import { SelectionControlsExporter } from './SelectionControlsExporter'; interface LocalEmbedPDFProps { file?: File | Blob; @@ -59,9 +61,12 @@ export function LocalEmbedPDF({ file, url, colorScheme }: LocalEmbedPDFProps) { }), createPluginRegistration(RenderPluginPackage), - // Register interaction manager (required for zoom features) + // Register interaction manager (required for zoom and selection features) createPluginRegistration(InteractionManagerPluginPackage), + // Register selection plugin (depends on InteractionManager) + createPluginRegistration(SelectionPluginPackage), + // Register zoom plugin with configuration createPluginRegistration(ZoomPluginPackage, { defaultZoomLevel: ZoomMode.FitPage, @@ -136,6 +141,7 @@ export function LocalEmbedPDF({ file, url, colorScheme }: LocalEmbedPDFProps) { + ( -
+ renderPage={({ width, height, pageIndex, scale, rotation }: { width: number; height: number; pageIndex: number; scale: number; rotation?: number }) => ( + -
+ + )} />
diff --git a/frontend/src/components/viewer/SelectionControlsExporter.tsx b/frontend/src/components/viewer/SelectionControlsExporter.tsx new file mode 100644 index 000000000..cddb64c3c --- /dev/null +++ b/frontend/src/components/viewer/SelectionControlsExporter.tsx @@ -0,0 +1,22 @@ +import { useEffect } from 'react'; +import { useSelectionCapability } from '@embedpdf/plugin-selection/react'; + +/** + * Component that runs inside EmbedPDF context and exports selection controls globally + */ +export function SelectionControlsExporter() { + const { provides: selection } = useSelectionCapability(); + + useEffect(() => { + if (selection) { + // Export selection controls to global window + (window as any).embedPdfSelection = { + copyToClipboard: () => selection.copyToClipboard(), + getSelectedText: () => selection.getSelectedText(), + getFormattedSelection: () => selection.getFormattedSelection(), + }; + } + }, [selection]); + + return null; // This component doesn't render anything +} \ No newline at end of file