@embedpdf/plugin-selection 2.15.0 → 3.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/LICENSE +192 -21
  2. package/dist/index.cjs +575 -2
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +167 -0
  5. package/dist/index.d.ts +167 -1
  6. package/dist/index.js +549 -1508
  7. package/dist/index.js.map +1 -1
  8. package/package.json +21 -62
  9. package/dist/lib/actions.d.ts +0 -103
  10. package/dist/lib/handlers/index.d.ts +0 -2
  11. package/dist/lib/handlers/marquee-selection.handler.d.ts +0 -30
  12. package/dist/lib/handlers/text-selection.handler.d.ts +0 -52
  13. package/dist/lib/index.d.ts +0 -9
  14. package/dist/lib/manifest.d.ts +0 -4
  15. package/dist/lib/reducer.d.ts +0 -5
  16. package/dist/lib/selection-plugin.d.ts +0 -121
  17. package/dist/lib/selectors.d.ts +0 -14
  18. package/dist/lib/types.d.ts +0 -268
  19. package/dist/lib/utils.d.ts +0 -108
  20. package/dist/preact/adapter.d.ts +0 -4
  21. package/dist/preact/core.d.ts +0 -1
  22. package/dist/preact/index.cjs +0 -2
  23. package/dist/preact/index.cjs.map +0 -1
  24. package/dist/preact/index.d.ts +0 -1
  25. package/dist/preact/index.js +0 -218
  26. package/dist/preact/index.js.map +0 -1
  27. package/dist/preact/interaction-manager.d.ts +0 -1
  28. package/dist/preact/utils.d.ts +0 -1
  29. package/dist/react/adapter.d.ts +0 -2
  30. package/dist/react/core.d.ts +0 -1
  31. package/dist/react/index.cjs +0 -2
  32. package/dist/react/index.cjs.map +0 -1
  33. package/dist/react/index.d.ts +0 -1
  34. package/dist/react/index.js +0 -217
  35. package/dist/react/index.js.map +0 -1
  36. package/dist/react/interaction-manager.d.ts +0 -1
  37. package/dist/react/utils.d.ts +0 -1
  38. package/dist/shared/components/copy-to-clipboard.d.ts +0 -1
  39. package/dist/shared/components/index.d.ts +0 -4
  40. package/dist/shared/components/marquee-selection.d.ts +0 -36
  41. package/dist/shared/components/selection-layer.d.ts +0 -29
  42. package/dist/shared/components/text-selection.d.ts +0 -21
  43. package/dist/shared/hooks/index.d.ts +0 -1
  44. package/dist/shared/hooks/use-selection.d.ts +0 -11
  45. package/dist/shared/index.d.ts +0 -5
  46. package/dist/shared/types.d.ts +0 -7
  47. package/dist/shared-preact/components/copy-to-clipboard.d.ts +0 -1
  48. package/dist/shared-preact/components/index.d.ts +0 -4
  49. package/dist/shared-preact/components/marquee-selection.d.ts +0 -36
  50. package/dist/shared-preact/components/selection-layer.d.ts +0 -29
  51. package/dist/shared-preact/components/text-selection.d.ts +0 -21
  52. package/dist/shared-preact/hooks/index.d.ts +0 -1
  53. package/dist/shared-preact/hooks/use-selection.d.ts +0 -11
  54. package/dist/shared-preact/index.d.ts +0 -5
  55. package/dist/shared-preact/types.d.ts +0 -7
  56. package/dist/shared-react/components/copy-to-clipboard.d.ts +0 -1
  57. package/dist/shared-react/components/index.d.ts +0 -4
  58. package/dist/shared-react/components/marquee-selection.d.ts +0 -36
  59. package/dist/shared-react/components/selection-layer.d.ts +0 -29
  60. package/dist/shared-react/components/text-selection.d.ts +0 -21
  61. package/dist/shared-react/hooks/index.d.ts +0 -1
  62. package/dist/shared-react/hooks/use-selection.d.ts +0 -11
  63. package/dist/shared-react/index.d.ts +0 -5
  64. package/dist/shared-react/types.d.ts +0 -7
  65. package/dist/svelte/components/CopyToClipboard.svelte.d.ts +0 -3
  66. package/dist/svelte/components/MarqueeSelection.svelte.d.ts +0 -27
  67. package/dist/svelte/components/SelectionLayer.svelte.d.ts +0 -32
  68. package/dist/svelte/components/TextSelection.svelte.d.ts +0 -22
  69. package/dist/svelte/components/index.d.ts +0 -4
  70. package/dist/svelte/hooks/index.d.ts +0 -1
  71. package/dist/svelte/hooks/use-selection.svelte.d.ts +0 -19
  72. package/dist/svelte/index.cjs +0 -2
  73. package/dist/svelte/index.cjs.map +0 -1
  74. package/dist/svelte/index.d.ts +0 -5
  75. package/dist/svelte/index.js +0 -359
  76. package/dist/svelte/index.js.map +0 -1
  77. package/dist/svelte/types.d.ts +0 -7
  78. package/dist/vue/components/copy-to-clipboard.vue.d.ts +0 -3
  79. package/dist/vue/components/index.d.ts +0 -4
  80. package/dist/vue/components/marquee-selection.vue.d.ts +0 -29
  81. package/dist/vue/components/selection-layer.vue.d.ts +0 -60
  82. package/dist/vue/components/text-selection.vue.d.ts +0 -51
  83. package/dist/vue/hooks/index.d.ts +0 -1
  84. package/dist/vue/hooks/use-selection.d.ts +0 -11
  85. package/dist/vue/index.cjs +0 -2
  86. package/dist/vue/index.cjs.map +0 -1
  87. package/dist/vue/index.d.ts +0 -5
  88. package/dist/vue/index.js +0 -311
  89. package/dist/vue/index.js.map +0 -1
  90. package/dist/vue/types.d.ts +0 -7
@@ -1,30 +0,0 @@
1
- import { Position, Rect, Size } from '@embedpdf/models';
2
- import { EmbedPdfPointerEvent, PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';
3
- export interface MarqueeSelectionHandlerOptions {
4
- /** The page size for clamping */
5
- pageSize: Size;
6
- /** Current scale factor for min drag threshold calculation */
7
- scale: number;
8
- /** Minimum drag distance in pixels before considering it a marquee (default: 5) */
9
- minDragPx?: number;
10
- /** Check if marquee selection is enabled for this mode */
11
- isEnabled: (modeId: string) => boolean;
12
- /** Returns whether text selection is currently active (skip marquee if so) */
13
- isTextSelecting?: () => boolean;
14
- /** Called when marquee selection begins */
15
- onBegin: (startPos: Position, modeId: string) => void;
16
- /** Called during drag with the current marquee rect */
17
- onChange: (rect: Rect, modeId: string) => void;
18
- /** Called when marquee selection completes (drag was large enough) */
19
- onEnd: (rect: Rect, modeId: string) => void;
20
- /** Called when marquee selection is cancelled (drag too small or cancelled) */
21
- onCancel: (modeId: string) => void;
22
- }
23
- /**
24
- * Creates a marquee selection handler that allows users to drag a selection rectangle.
25
- *
26
- * This handler is meant to be combined with the text selection handler. When text is hit,
27
- * the text selection handler sets its selecting state, and this handler checks via
28
- * `isTextSelecting` to avoid activating during text selection.
29
- */
30
- export declare function createMarqueeSelectionHandler(opts: MarqueeSelectionHandlerOptions): PointerEventHandlersWithLifecycle<EmbedPdfPointerEvent>;
@@ -1,52 +0,0 @@
1
- import { PdfPageGeometry } from '@embedpdf/models';
2
- import { EmbedPdfPointerEvent, PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';
3
- export interface TextSelectionHandlerOptions {
4
- /** Returns the page geometry, or undefined if not loaded yet */
5
- getGeometry: () => PdfPageGeometry | undefined;
6
- /** Check if selection is enabled for this mode */
7
- isEnabled: (modeId: string) => boolean;
8
- /** Called when drag-selection begins on a glyph */
9
- onBegin: (glyphIndex: number, modeId: string) => void;
10
- /** Called when drag-selection updates to a new glyph */
11
- onUpdate: (glyphIndex: number, modeId: string) => void;
12
- /** Called when drag-selection ends (pointer up) */
13
- onEnd: (modeId: string) => void;
14
- /** Called to clear the current selection */
15
- onClear: (modeId: string) => void;
16
- /** Returns whether text selection is currently in progress */
17
- isSelecting: () => boolean;
18
- /** Set or remove the text cursor */
19
- setCursor: (cursor: string | null) => void;
20
- /** Called when the user clicks directly on empty page space (target === currentTarget) */
21
- onEmptySpaceClick?: (modeId: string) => void;
22
- /** Called on double-click over a glyph; receives the char index */
23
- onWordSelect?: (glyphIndex: number, modeId: string) => void;
24
- /** Called on triple-click over a glyph; receives the char index */
25
- onLineSelect?: (glyphIndex: number, modeId: string) => void;
26
- /**
27
- * Signals whether the text handler has claimed a pointer-down (anchor set)
28
- * even before the drag threshold is met. Used to prevent the marquee handler
29
- * from activating concurrently.
30
- */
31
- setHasTextAnchor?: (active: boolean) => void;
32
- /**
33
- * Minimum drag distance (in page-coordinate units) before a pointer-down
34
- * starts an actual selection drag. Default: 3.
35
- */
36
- minDragDistance?: number;
37
- /** Tolerance factor passed through to glyphAt. Default: 0.9. */
38
- toleranceFactor?: number;
39
- }
40
- /**
41
- * Creates a text selection handler that manages pointer-based text selection,
42
- * double-click word selection, triple-click line selection, and a drag threshold.
43
- *
44
- * Behaviour modelled after Chromium's PDFiumEngine (pdfium-engine.cc):
45
- * - Single pointer-down records an anchor but does NOT begin selection until
46
- * the pointer has moved beyond `minDragDistance`.
47
- * - Double-click selects the word around the clicked glyph.
48
- * - Triple-click selects the full visual line.
49
- * - The marquee handler coordinates via `isTextSelecting` / `hasTextAnchor`
50
- * to avoid activating during text selection.
51
- */
52
- export declare function createTextSelectionHandler(opts: TextSelectionHandlerOptions): PointerEventHandlersWithLifecycle<EmbedPdfPointerEvent>;
@@ -1,9 +0,0 @@
1
- import { PluginPackage } from '@embedpdf/core';
2
- import { SelectionPluginConfig, SelectionState } from './types';
3
- import { SelectionPlugin } from './selection-plugin';
4
- import { SelectionAction } from './actions';
5
- export declare const SelectionPluginPackage: PluginPackage<SelectionPlugin, SelectionPluginConfig, SelectionState, SelectionAction>;
6
- export * from './selection-plugin';
7
- export * from './types';
8
- export * from './manifest';
9
- export * from './utils';
@@ -1,4 +0,0 @@
1
- import { PluginManifest } from '@embedpdf/core';
2
- import { SelectionPluginConfig } from './types';
3
- export declare const SELECTION_PLUGIN_ID = "selection";
4
- export declare const manifest: PluginManifest<SelectionPluginConfig>;
@@ -1,5 +0,0 @@
1
- import { SelectionDocumentState, SelectionState } from './types';
2
- import { SelectionAction } from './actions';
3
- export declare const initialSelectionDocumentState: SelectionDocumentState;
4
- export declare const initialState: SelectionState;
5
- export declare const selectionReducer: (state: SelectionState | undefined, action: SelectionAction) => SelectionState;
@@ -1,121 +0,0 @@
1
- import { BasePlugin, PluginRegistry } from '@embedpdf/core';
2
- import { SelectionAction } from './actions';
3
- import { SelectionCapability, SelectionPluginConfig, SelectionState, RegisterSelectionOnPageOptions, RegisterMarqueeOnPageOptions, SelectionMenuPlacement } from './types';
4
- export declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, SelectionCapability, SelectionState, SelectionAction> {
5
- static readonly id: "selection";
6
- /** Modes that should trigger text-selection logic, per document (mode -> config) */
7
- private enabledModesPerDoc;
8
- private selecting;
9
- private anchor;
10
- /** Whether the text handler has a pending anchor (before drag threshold is met) */
11
- private hasTextAnchor;
12
- /** Tracks the page a marquee drag started on, per document */
13
- private marqueePage;
14
- /** Page callbacks for rect updates, per document */
15
- private pageCallbacks;
16
- /** LRU access order for geometry cache, per document (oldest first) */
17
- private geoAccessOrder;
18
- private readonly menuPlacement$;
19
- private readonly selChange$;
20
- private readonly textRetrieved$;
21
- private readonly copyToClipboard$;
22
- private readonly beginSelection$;
23
- private readonly endSelection$;
24
- private readonly marqueeChange$;
25
- private readonly marqueeEnd$;
26
- private readonly emptySpaceClick$;
27
- private interactionManagerCapability;
28
- private viewportCapability;
29
- private scrollCapability;
30
- private readonly menuHeight;
31
- private readonly config;
32
- constructor(id: string, registry: PluginRegistry, config: SelectionPluginConfig);
33
- protected onDocumentLoadingStarted(documentId: string): void;
34
- protected onDocumentClosed(documentId: string): void;
35
- initialize(): Promise<void>;
36
- destroy(): Promise<void>;
37
- buildCapability(): SelectionCapability;
38
- private createSelectionScope;
39
- private getDocumentState;
40
- /**
41
- * Subscribe to menu placement changes for a specific document
42
- * @param documentId - The document ID to subscribe to
43
- * @param listener - Callback function that receives placement updates
44
- * @returns Unsubscribe function
45
- */
46
- onMenuPlacement(documentId: string, listener: (placement: SelectionMenuPlacement | null) => void): import('@embedpdf/core').Unsubscribe;
47
- /**
48
- * Register text selection on a page. Uses `registerAlways` so any plugin
49
- * can enable text selection for their mode via `enableForMode()`.
50
- */
51
- registerSelectionOnPage(opts: RegisterSelectionOnPageOptions): () => void;
52
- /**
53
- * Register marquee selection on a page. Uses `registerAlways` so any plugin
54
- * can enable marquee selection for their mode via `enableForMode({ enableMarquee: true })`.
55
- */
56
- registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions): () => void;
57
- /**
58
- * Helper to calculate viewport relative metrics for a page rect.
59
- * Returns null if the rect cannot be converted to viewport space.
60
- */
61
- private getPlacementMetrics;
62
- private emitMenuPlacement;
63
- private recalculateMenuPlacement;
64
- private notifyPage;
65
- private notifyAllPages;
66
- private getNewPageGeometryAndCache;
67
- private getOrLoadGeometry;
68
- private touchGeometry;
69
- private evictGeometryIfNeeded;
70
- private beginSelection;
71
- private endSelection;
72
- private clearSelection;
73
- /**
74
- * Programmatically apply (or restore) a text selection without going through
75
- * the pointer drag flow. Useful for restoring a previously persisted selection
76
- * or driving selection from code (e.g. search results).
77
- *
78
- * Geometry for every page spanned by the range is loaded on demand (the data
79
- * comes from the WASM engine), so the returned task settles only once the
80
- * selection rects have actually been computed.
81
- *
82
- * Passing `null` is equivalent to calling {@link clearSelection}.
83
- *
84
- * @returns a task that resolves once the selection has been applied.
85
- */
86
- private applySelection;
87
- /**
88
- * Validate the structure and page bounds of a programmatic selection range.
89
- * Returns a rejection reason when the input is invalid, or null when it is
90
- * structurally sound. Glyph-index bounds are enforced separately, after the
91
- * page geometry has loaded (see {@link clampRangeToGeometry}).
92
- */
93
- private validateRange;
94
- /**
95
- * Clamp the glyph indices of a (normalized) range to the number of glyphs
96
- * available on the corresponding pages. Returns null when none of the
97
- * spanned pages have any text geometry to select.
98
- */
99
- private clampRangeToGeometry;
100
- /** Order a range so that `start` never comes after `end`. */
101
- private normalizeRange;
102
- private selectWord;
103
- private selectLine;
104
- /**
105
- * Set a selection range without going through the drag begin/update/end flow.
106
- * Used by double-click (word) and triple-click (line) selection.
107
- */
108
- private applyInstantSelection;
109
- private updateSelection;
110
- private updateRectsAndSlices;
111
- private getSelectedText;
112
- private copyToClipboard;
113
- private beginMarquee;
114
- private updateMarquee;
115
- private endMarquee;
116
- private cancelMarquee;
117
- /** @deprecated — shim for backward compat; delegates to pointerMode config */
118
- private setMarqueeEnabled;
119
- /** @deprecated — shim for backward compat; reads pointerMode config */
120
- private isMarqueeEnabled;
121
- }
@@ -1,14 +0,0 @@
1
- import { Rect } from '@embedpdf/models';
2
- import { FormattedSelection, SelectionDocumentState } from './types';
3
- export declare function selectRectsForPage(state: SelectionDocumentState, page: number): Rect[];
4
- export declare function selectBoundingRectForPage(state: SelectionDocumentState, page: number): Rect | null;
5
- export declare function selectRectsAndBoundingRectForPage(state: SelectionDocumentState, page: number): {
6
- rects: Rect[];
7
- boundingRect: Rect | null;
8
- };
9
- export declare function selectBoundingRectsForAllPages(state: SelectionDocumentState): {
10
- page: number;
11
- rect: Rect;
12
- }[];
13
- export declare function getFormattedSelectionForPage(state: SelectionDocumentState, page: number): FormattedSelection | null;
14
- export declare function getFormattedSelection(state: SelectionDocumentState): FormattedSelection[];
@@ -1,268 +0,0 @@
1
- import { BasePluginConfig, EventHook } from '@embedpdf/core';
2
- import { PdfPageGeometry, PdfTask, Rect } from '@embedpdf/models';
3
- export interface MarqueeSelectionConfig {
4
- /** Minimum drag distance in pixels before considering it a marquee */
5
- minDragPx?: number;
6
- /** Whether marquee selection is enabled (default: true) */
7
- enabled?: boolean;
8
- }
9
- export interface SelectionPluginConfig extends BasePluginConfig {
10
- /**
11
- * The approximate height of the selection menu in pixels.
12
- * Used to determine whether to show the menu above or below the selection.
13
- * @default 40
14
- */
15
- menuHeight?: number;
16
- /**
17
- * Configuration for marquee selection behavior.
18
- */
19
- marquee?: MarqueeSelectionConfig;
20
- /**
21
- * Tolerance factor for hit-testing glyphs. Multiplied by average glyph
22
- * height to derive the tolerance radius. Set to 0 to require exact hits.
23
- * @default 1.5
24
- */
25
- toleranceFactor?: number;
26
- /**
27
- * Minimum drag distance (in page-coordinate units) the pointer must move
28
- * before a drag-selection starts. Prevents accidental selection on simple clicks.
29
- * @default 3
30
- */
31
- minSelectionDragDistance?: number;
32
- /**
33
- * Maximum number of pages whose geometry data is kept in memory per document.
34
- * Oldest unused pages are evicted when this limit is exceeded.
35
- * @default 50
36
- */
37
- maxCachedGeometries?: number;
38
- }
39
- export interface SelectionMenuPlacement {
40
- pageIndex: number;
41
- rect: Rect;
42
- spaceAbove: number;
43
- spaceBelow: number;
44
- suggestTop: boolean;
45
- isVisible: boolean;
46
- }
47
- export interface GlyphPointer {
48
- page: number;
49
- index: number;
50
- }
51
- export interface SelectionRangeX {
52
- start: GlyphPointer;
53
- end: GlyphPointer;
54
- }
55
- export interface SelectionDocumentState {
56
- /** page → geometry cache */
57
- geometry: Record<number, PdfPageGeometry>;
58
- /** current selection or null */
59
- rects: Record<number, Rect[]>;
60
- selection: SelectionRangeX | null;
61
- slices: Record<number, {
62
- start: number;
63
- count: number;
64
- }>;
65
- active: boolean;
66
- selecting: boolean;
67
- }
68
- export interface SelectionState {
69
- documents: Record<string, SelectionDocumentState>;
70
- }
71
- export interface FormattedSelection {
72
- pageIndex: number;
73
- rect: Rect;
74
- segmentRects: Rect[];
75
- }
76
- export interface SelectionRectsCallback {
77
- rects: Rect[];
78
- boundingRect: Rect | null;
79
- }
80
- export interface RegisterSelectionOnPageOptions {
81
- documentId: string;
82
- pageIndex: number;
83
- onRectsChange: (data: SelectionRectsCallback) => void;
84
- }
85
- export interface RegisterMarqueeOnPageOptions {
86
- documentId: string;
87
- pageIndex: number;
88
- /** The current scale factor (for marquee threshold calculation) */
89
- scale: number;
90
- /** Called when the marquee rect changes during drag, or null when cancelled/ended */
91
- onRectChange: (rect: Rect | null) => void;
92
- }
93
- export interface TextSelectionStyle {
94
- /** Background color for text selection highlights. Default: 'rgba(33,150,243)' */
95
- background?: string;
96
- }
97
- export interface MarqueeSelectionStyle {
98
- /** Fill/background color inside the marquee rectangle. Default: 'rgba(0,122,204,0.15)' */
99
- background?: string;
100
- /** Border color of the marquee rectangle. Default: 'rgba(0,122,204,0.8)' */
101
- borderColor?: string;
102
- /** Border style. Default: 'dashed' */
103
- borderStyle?: 'solid' | 'dashed' | 'dotted';
104
- }
105
- export interface SelectionMenuPlacementEvent {
106
- documentId: string;
107
- placement: SelectionMenuPlacement | null;
108
- }
109
- export interface SelectionChangeEvent {
110
- documentId: string;
111
- selection: SelectionRangeX | null;
112
- modeId: string;
113
- }
114
- export interface TextRetrievedEvent {
115
- documentId: string;
116
- text: string[];
117
- }
118
- export interface CopyToClipboardEvent {
119
- documentId: string;
120
- text: string;
121
- }
122
- export interface BeginSelectionEvent {
123
- documentId: string;
124
- page: number;
125
- index: number;
126
- modeId: string;
127
- }
128
- export interface EndSelectionEvent {
129
- documentId: string;
130
- modeId: string;
131
- }
132
- export interface MarqueeChangeEvent {
133
- documentId: string;
134
- pageIndex: number;
135
- rect: Rect | null;
136
- modeId: string;
137
- }
138
- export interface MarqueeEndEvent {
139
- documentId: string;
140
- pageIndex: number;
141
- rect: Rect;
142
- modeId: string;
143
- }
144
- export interface EmptySpaceClickEvent {
145
- documentId: string;
146
- pageIndex: number;
147
- modeId: string;
148
- }
149
- export interface EnableForModeOptions {
150
- /**
151
- * Whether to show selection rects in the SelectionLayer.
152
- * @deprecated Use `showSelectionRects` instead.
153
- * @default true
154
- */
155
- showRects?: boolean;
156
- /**
157
- * Enable text selection for this mode.
158
- * @default true
159
- */
160
- enableSelection?: boolean;
161
- /**
162
- * Whether to show text selection rects in the SelectionLayer.
163
- * When false, the selection logic is enabled but the rects are not
164
- * rendered (useful when a consuming plugin handles its own rendering).
165
- * Takes precedence over `showRects`.
166
- * @default true
167
- */
168
- showSelectionRects?: boolean;
169
- /**
170
- * Enable marquee selection for this mode.
171
- * @default false
172
- */
173
- enableMarquee?: boolean;
174
- /**
175
- * Whether to show the marquee rect in the MarqueeSelection component.
176
- * When false, the marquee logic runs but the rect is not rendered
177
- * (useful when a consuming plugin handles its own rendering).
178
- * @default true
179
- */
180
- showMarqueeRects?: boolean;
181
- }
182
- export interface MarqueeScopeEvent {
183
- pageIndex: number;
184
- rect: Rect | null;
185
- modeId: string;
186
- }
187
- export interface MarqueeEndScopeEvent {
188
- pageIndex: number;
189
- rect: Rect;
190
- modeId: string;
191
- }
192
- export interface EmptySpaceClickScopeEvent {
193
- pageIndex: number;
194
- modeId: string;
195
- }
196
- export interface SelectionScope {
197
- getFormattedSelection(): FormattedSelection[];
198
- getFormattedSelectionForPage(page: number): FormattedSelection | null;
199
- getHighlightRectsForPage(page: number): Rect[];
200
- getHighlightRects(): Record<number, Rect[]>;
201
- getBoundingRectForPage(page: number): Rect | null;
202
- getBoundingRects(): {
203
- page: number;
204
- rect: Rect;
205
- }[];
206
- getSelectedText(): PdfTask<string[]>;
207
- setSelection(range: SelectionRangeX | null): PdfTask<void>;
208
- clear(): void;
209
- copyToClipboard(): void;
210
- getState(): SelectionDocumentState;
211
- /**
212
- * @deprecated Use `enableForMode` with `enableMarquee` option on the capability instead.
213
- */
214
- setMarqueeEnabled(enabled: boolean): void;
215
- /**
216
- * @deprecated Use `enableForMode` / `isEnabledForMode` on the capability instead.
217
- */
218
- isMarqueeEnabled(): boolean;
219
- onSelectionChange: EventHook<SelectionRangeX | null>;
220
- onTextRetrieved: EventHook<string[]>;
221
- onCopyToClipboard: EventHook<string>;
222
- onBeginSelection: EventHook<{
223
- page: number;
224
- index: number;
225
- modeId: string;
226
- }>;
227
- onEndSelection: EventHook<{
228
- modeId: string;
229
- }>;
230
- onMarqueeChange: EventHook<MarqueeScopeEvent>;
231
- onMarqueeEnd: EventHook<MarqueeEndScopeEvent>;
232
- onEmptySpaceClick: EventHook<EmptySpaceClickScopeEvent>;
233
- }
234
- export interface SelectionCapability {
235
- getFormattedSelection(documentId?: string): FormattedSelection[];
236
- getFormattedSelectionForPage(page: number, documentId?: string): FormattedSelection | null;
237
- getHighlightRectsForPage(page: number, documentId?: string): Rect[];
238
- getHighlightRects(documentId?: string): Record<number, Rect[]>;
239
- getBoundingRectForPage(page: number, documentId?: string): Rect | null;
240
- getBoundingRects(documentId?: string): {
241
- page: number;
242
- rect: Rect;
243
- }[];
244
- getSelectedText(documentId?: string): PdfTask<string[]>;
245
- setSelection(range: SelectionRangeX | null, documentId?: string): PdfTask<void>;
246
- clear(documentId?: string): void;
247
- copyToClipboard(documentId?: string): void;
248
- getState(documentId?: string): SelectionDocumentState;
249
- enableForMode(modeId: string, options?: EnableForModeOptions, documentId?: string): void;
250
- isEnabledForMode(modeId: string, documentId?: string): boolean;
251
- /**
252
- * @deprecated Use `enableForMode` with `enableMarquee` option instead.
253
- */
254
- setMarqueeEnabled(enabled: boolean, documentId?: string): void;
255
- /**
256
- * @deprecated Use `enableForMode` / `isEnabledForMode` instead.
257
- */
258
- isMarqueeEnabled(documentId?: string): boolean;
259
- forDocument(documentId: string): SelectionScope;
260
- onSelectionChange: EventHook<SelectionChangeEvent>;
261
- onTextRetrieved: EventHook<TextRetrievedEvent>;
262
- onCopyToClipboard: EventHook<CopyToClipboardEvent>;
263
- onBeginSelection: EventHook<BeginSelectionEvent>;
264
- onEndSelection: EventHook<EndSelectionEvent>;
265
- onMarqueeChange: EventHook<MarqueeChangeEvent>;
266
- onMarqueeEnd: EventHook<MarqueeEndEvent>;
267
- onEmptySpaceClick: EventHook<EmptySpaceClickEvent>;
268
- }
@@ -1,108 +0,0 @@
1
- import { PdfPageGeometry, Position, Rect } from '@embedpdf/models';
2
- import { SelectionRangeX } from './types';
3
- /**
4
- * Hit-test helper using runs, with tolerance-based fallback.
5
- *
6
- * Adapted from PDFium's FPDFText_GetCharIndexAtPos / CPDF_TextPage::GetIndexAtPos:
7
- * 1. Exact match: return the glyph whose bounding box contains the point.
8
- * 2. Tolerance expansion: expand each glyph box by tolerance/2 on every side,
9
- * then pick the closest glyph by Manhattan distance.
10
- *
11
- * @param geo - page geometry
12
- * @param pt - point in page coordinates
13
- * @param toleranceFactor - multiplied by average glyph height to derive the
14
- * tolerance radius. 0 disables the fallback.
15
- * Default 1.5 (see Chromium's pdfium-page.cc kTolerance).
16
- * @returns glyph index, or -1 if nothing was hit
17
- */
18
- export declare function glyphAt(geo: PdfPageGeometry, pt: Position, toleranceFactor?: number): number;
19
- /**
20
- * Helper: min/max glyph indices on `page` for current sel
21
- * @param sel - selection range
22
- * @param geo - page geometry
23
- * @param page - page index
24
- * @returns { from: number; to: number } | null
25
- */
26
- export declare function sliceBounds(sel: SelectionRangeX | null, geo: PdfPageGeometry | undefined, page: number): {
27
- from: number;
28
- to: number;
29
- } | null;
30
- /**
31
- * Helper: build rects for a slice of the page
32
- * @param geo - page geometry
33
- * @param from - from index
34
- * @param to - to index
35
- * @param merge - whether to merge adjacent rects (default: true)
36
- * @returns rects
37
- */
38
- export declare function rectsWithinSlice(geo: PdfPageGeometry, from: number, to: number, merge?: boolean): Rect[];
39
- /**
40
- * ============================================================================
41
- * Rectangle Merging Algorithm
42
- * ============================================================================
43
- *
44
- * The following code is adapted from Chromium's PDF text selection implementation.
45
- *
46
- * Copyright 2010 The Chromium Authors
47
- * Use of this source code is governed by a BSD-style license that can be
48
- * found in the LICENSE file: https://source.chromium.org/chromium/chromium/src/+/main:LICENSE
49
- *
50
- * Original source:
51
- * https://source.chromium.org/chromium/chromium/src/+/main:pdf/pdfium/pdfium_range.cc
52
- *
53
- * Adapted for TypeScript and this project's Rect/geometry types.
54
- */
55
- /**
56
- * Text run info for rect merging (similar to Chromium's PdfRectTextRunInfo)
57
- */
58
- export interface TextRunInfo {
59
- rect: Rect;
60
- charCount: number;
61
- fontSize?: number;
62
- }
63
- /**
64
- * Helper functions for Rect operations
65
- */
66
- export declare function rectUnion(rect1: Rect, rect2: Rect): Rect;
67
- export declare function rectIntersect(rect1: Rect, rect2: Rect): Rect;
68
- export declare function rectIsEmpty(rect: Rect): boolean;
69
- /**
70
- * Returns a ratio between [0, 1] representing vertical overlap
71
- */
72
- export declare function getVerticalOverlap(rect1: Rect, rect2: Rect): number;
73
- /**
74
- * Returns true if there is sufficient horizontal and vertical overlap
75
- */
76
- export declare function shouldMergeHorizontalRects(textRun1: TextRunInfo, textRun2: TextRunInfo): boolean;
77
- /**
78
- * Merge adjacent rectangles based on proximity and overlap.
79
- *
80
- * Adapted from Chromium's MergeAdjacentRects (pdfium_range.cc):
81
- * - The merge DECISION uses the loose `rect` (via shouldMergeHorizontalRects).
82
- * - The OUTPUT rect always uses loose bounds.
83
- */
84
- export declare function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[];
85
- /**
86
- * Expand a character index to the word surrounding it.
87
- *
88
- * Walks backward and forward from `charIndex` within the page geometry
89
- * until a word-boundary glyph (space or empty) is encountered.
90
- *
91
- * @returns `{ from, to }` inclusive indices, or null if charIndex is invalid.
92
- */
93
- export declare function expandToWordBoundary(geo: PdfPageGeometry, charIndex: number): {
94
- from: number;
95
- to: number;
96
- } | null;
97
- /**
98
- * Expand a character index to the full visual line (row) it belongs to.
99
- *
100
- * Finds all runs whose vertical extent overlaps with the run containing `charIndex`,
101
- * then returns the first-to-last character span across those runs.
102
- *
103
- * @returns `{ from, to }` inclusive indices, or null if charIndex is invalid.
104
- */
105
- export declare function expandToLineBoundary(geo: PdfPageGeometry, charIndex: number): {
106
- from: number;
107
- to: number;
108
- } | null;
@@ -1,4 +0,0 @@
1
- export { Fragment } from 'preact';
2
- export { useEffect, useRef, useState, useCallback, useMemo } from 'preact/hooks';
3
- export type { ComponentChildren as ReactNode } from 'preact';
4
- export type HTMLAttributes<T = any> = import('preact').JSX.HTMLAttributes<T extends EventTarget ? T : never>;
@@ -1 +0,0 @@
1
- export * from '@embedpdf/core/preact';
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-selection"),o=require("preact/jsx-runtime"),i=require("preact"),n=require("preact/hooks"),r=require("@embedpdf/core/preact"),l=require("@embedpdf/utils/preact"),u=()=>r.useCapability(t.SelectionPlugin.id),s=()=>r.usePlugin(t.SelectionPlugin.id);function a({documentId:e,pageIndex:t,scale:i,rotation:u,background:a="rgba(33,150,243)",selectionMenu:d}){var c,g;const{plugin:p}=s(),x=r.useDocumentState(e),b=null==(g=null==(c=null==x?void 0:x.document)?void 0:c.pages)?void 0:g[t],[h,m]=n.useState([]),[f,y]=n.useState(null),[v,S]=n.useState(null);n.useEffect(()=>{if(p&&e)return p.registerSelectionOnPage({documentId:e,pageIndex:t,onRectsChange:({rects:e,boundingRect:t})=>{m(e),y(t)}})},[p,e,t]),n.useEffect(()=>{if(p&&e)return p.onMenuPlacement(e,e=>{S(e)})},[p,e]);const I=n.useMemo(()=>void 0!==i?i:(null==x?void 0:x.scale)??1,[i,null==x?void 0:x.scale]),P=n.useMemo(()=>{if(void 0!==u)return u;return(((null==b?void 0:b.rotation)??0)+((null==x?void 0:x.rotation)??0))%4},[u,null==b?void 0:b.rotation,null==x?void 0:x.rotation]),k=d&&v&&v.pageIndex===t&&v.isVisible;return f?o.jsxs(o.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:f.origin.x*I,top:f.origin.y*I,width:f.size.width*I,height:f.size.height*I,mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"},children:h.map((e,t)=>o.jsx("div",{style:{position:"absolute",left:(e.origin.x-f.origin.x)*I,top:(e.origin.y-f.origin.y)*I,width:e.size.width*I,height:e.size.height*I,background:a}},t))}),k&&o.jsx(l.CounterRotate,{rect:{origin:{x:v.rect.origin.x*I,y:v.rect.origin.y*I},size:{width:v.rect.size.width*I,height:v.rect.size.height*I}},rotation:P,children:e=>d({...e,context:{type:"selection",pageIndex:t},selected:!0,placement:v})})]}):null}const d=({documentId:e,pageIndex:t,scale:i,className:l,background:u,borderColor:a,borderStyle:d="dashed",stroke:c,fill:g})=>{const{plugin:p}=s(),x=r.useDocumentState(e),[b,h]=n.useState(null),m=a??c??"rgba(0,122,204,0.8)",f=u??g??"rgba(0,122,204,0.15)",y=n.useMemo(()=>void 0!==i?i:(null==x?void 0:x.scale)??1,[i,null==x?void 0:x.scale]);return n.useEffect(()=>{if(p&&e)return p.registerMarqueeOnPage({documentId:e,pageIndex:t,scale:y,onRectChange:h})},[p,e,t,y]),b?o.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:b.origin.x*y,top:b.origin.y*y,width:b.size.width*y,height:b.size.height*y,border:`1px ${d} ${m}`,background:f,boxSizing:"border-box",zIndex:1e3},className:l}):null};function c(){const{provides:e}=u();return n.useEffect(()=>{if(e)return e.onCopyToClipboard(({text:e})=>{navigator.clipboard.writeText(e)})},[e]),null}const g=e.createPluginPackage(t.SelectionPluginPackage).addUtility(c).build();exports.CopyToClipboard=c,exports.MarqueeSelection=d,exports.SelectionLayer=function({documentId:e,pageIndex:t,scale:n,rotation:r,background:l,textStyle:u,marqueeStyle:s,marqueeClassName:c,selectionMenu:g}){return o.jsxs(i.Fragment,{children:[o.jsx(a,{documentId:e,pageIndex:t,scale:n,rotation:r,background:(null==u?void 0:u.background)??l,selectionMenu:g}),o.jsx(d,{documentId:e,pageIndex:t,scale:n,background:null==s?void 0:s.background,borderColor:null==s?void 0:s.borderColor,borderStyle:null==s?void 0:s.borderStyle,className:c})]})},exports.SelectionPluginPackage=g,exports.TextSelection=a,exports.useSelectionCapability=u,exports.useSelectionPlugin=s,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
- //# sourceMappingURL=index.cjs.map