@embedpdf/plugin-selection 1.0.10 → 1.0.12
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.
- package/dist/index.cjs +2 -450
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -213
- package/dist/index.js +27 -53
- package/dist/index.js.map +1 -1
- package/dist/lib/actions.d.ts +57 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/manifest.d.ts +4 -0
- package/dist/lib/reducer.d.ts +4 -0
- package/dist/lib/selection-plugin.d.ts +29 -0
- package/dist/lib/selectors.d.ts +14 -0
- package/dist/lib/types.d.ts +63 -0
- package/dist/lib/utils.d.ts +70 -0
- package/dist/preact/adapter.d.ts +4 -0
- package/dist/preact/core.d.ts +1 -0
- package/dist/preact/index.cjs +2 -169
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.d.ts +1 -25
- package/dist/preact/index.js +15 -24
- package/dist/preact/index.js.map +1 -1
- package/dist/preact/interaction-manager.d.ts +1 -0
- package/dist/react/adapter.d.ts +2 -0
- package/dist/react/core.d.ts +1 -0
- package/dist/react/index.cjs +2 -169
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +1 -25
- package/dist/react/index.js +14 -24
- package/dist/react/index.js.map +1 -1
- package/dist/react/interaction-manager.d.ts +1 -0
- package/dist/shared-preact/components/copy-to-clipboard.d.ts +1 -0
- package/dist/shared-preact/components/index.d.ts +2 -0
- package/dist/shared-preact/components/selection-layer.d.ts +7 -0
- package/dist/shared-preact/hooks/index.d.ts +1 -0
- package/dist/shared-preact/hooks/use-selection.d.ts +11 -0
- package/dist/shared-preact/index.d.ts +2 -0
- package/dist/shared-react/components/copy-to-clipboard.d.ts +1 -0
- package/dist/shared-react/components/index.d.ts +2 -0
- package/dist/shared-react/components/selection-layer.d.ts +7 -0
- package/dist/shared-react/hooks/index.d.ts +1 -0
- package/dist/shared-react/hooks/use-selection.d.ts +11 -0
- package/dist/shared-react/index.d.ts +2 -0
- package/dist/vue/components/copy-to-clipboard.vue.d.ts +2 -0
- package/dist/vue/components/index.d.ts +2 -0
- package/dist/vue/components/selection-layer.vue.d.ts +9 -0
- package/dist/vue/hooks/index.d.ts +1 -0
- package/dist/vue/hooks/use-selection.d.ts +11 -0
- package/dist/vue/index.cjs +2 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.ts +2 -0
- package/dist/vue/index.js +145 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +23 -14
- package/dist/index.d.cts +0 -213
- package/dist/preact/index.d.cts +0 -25
- package/dist/react/index.d.cts +0 -25
package/dist/index.d.ts
CHANGED
|
@@ -1,213 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { PdfTask, PdfPageGeometry, Rect, PdfEngine } from '@embedpdf/models';
|
|
3
|
-
|
|
4
|
-
interface SelectionPluginConfig extends BasePluginConfig {
|
|
5
|
-
}
|
|
6
|
-
interface GlyphPointer {
|
|
7
|
-
page: number;
|
|
8
|
-
index: number;
|
|
9
|
-
}
|
|
10
|
-
interface SelectionRangeX {
|
|
11
|
-
start: GlyphPointer;
|
|
12
|
-
end: GlyphPointer;
|
|
13
|
-
}
|
|
14
|
-
interface SelectionState {
|
|
15
|
-
/** page → geometry cache */
|
|
16
|
-
geometry: Record<number, PdfPageGeometry>;
|
|
17
|
-
/** current selection or null */
|
|
18
|
-
rects: Record<number, Rect[]>;
|
|
19
|
-
selection: SelectionRangeX | null;
|
|
20
|
-
slices: Record<number, {
|
|
21
|
-
start: number;
|
|
22
|
-
count: number;
|
|
23
|
-
}>;
|
|
24
|
-
active: boolean;
|
|
25
|
-
selecting: boolean;
|
|
26
|
-
}
|
|
27
|
-
interface FormattedSelection {
|
|
28
|
-
pageIndex: number;
|
|
29
|
-
rect: Rect;
|
|
30
|
-
segmentRects: Rect[];
|
|
31
|
-
}
|
|
32
|
-
interface SelectionCapability {
|
|
33
|
-
getGeometry(page: number): PdfTask<PdfPageGeometry>;
|
|
34
|
-
getFormattedSelection(): FormattedSelection[];
|
|
35
|
-
getFormattedSelectionForPage(page: number): FormattedSelection | null;
|
|
36
|
-
getHighlightRectsForPage(page: number): Rect[];
|
|
37
|
-
getHighlightRects(): Record<number, Rect[]>;
|
|
38
|
-
getBoundingRectForPage(page: number): Rect | null;
|
|
39
|
-
getBoundingRects(): {
|
|
40
|
-
page: number;
|
|
41
|
-
rect: Rect;
|
|
42
|
-
}[];
|
|
43
|
-
getSelectedText(): PdfTask<string[]>;
|
|
44
|
-
copyToClipboard(): void;
|
|
45
|
-
begin(page: number, glyphIdx: number): void;
|
|
46
|
-
update(page: number, glyphIdx: number): void;
|
|
47
|
-
end(): void;
|
|
48
|
-
clear(): void;
|
|
49
|
-
onSelectionChange: EventHook<SelectionRangeX | null>;
|
|
50
|
-
onTextRetrieved: EventHook<string[]>;
|
|
51
|
-
onCopyToClipboard: EventHook<string>;
|
|
52
|
-
onBeginSelection: EventHook<{
|
|
53
|
-
page: number;
|
|
54
|
-
index: number;
|
|
55
|
-
}>;
|
|
56
|
-
onEndSelection: EventHook<void>;
|
|
57
|
-
/** Tell the selection plugin that text selection should stay
|
|
58
|
-
enabled while <modeId> is active. */
|
|
59
|
-
enableForMode(modeId: string): void;
|
|
60
|
-
/** Quick check used by SelectionLayer during pointer events. */
|
|
61
|
-
isEnabledForMode(modeId: string): boolean;
|
|
62
|
-
/** Get the current state of the selection plugin. */
|
|
63
|
-
getState(): SelectionState;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
declare const CACHE_PAGE_GEOMETRY = "CACHE_PAGE_GEOMETRY";
|
|
67
|
-
declare const SET_SELECTION = "SET_SELECTION";
|
|
68
|
-
declare const START_SELECTION = "START_SELECTION";
|
|
69
|
-
declare const END_SELECTION = "END_SELECTION";
|
|
70
|
-
declare const CLEAR_SELECTION = "CLEAR_SELECTION";
|
|
71
|
-
declare const SET_RECTS = "SET_RECTS";
|
|
72
|
-
declare const SET_SLICES = "SET_SLICES";
|
|
73
|
-
declare const RESET = "RESET";
|
|
74
|
-
interface CachePageGeometryAction extends Action {
|
|
75
|
-
type: typeof CACHE_PAGE_GEOMETRY;
|
|
76
|
-
payload: {
|
|
77
|
-
page: number;
|
|
78
|
-
geo: PdfPageGeometry;
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
interface SetSelectionAction extends Action {
|
|
82
|
-
type: typeof SET_SELECTION;
|
|
83
|
-
payload: SelectionRangeX | null;
|
|
84
|
-
}
|
|
85
|
-
interface StartSelectionAction extends Action {
|
|
86
|
-
type: typeof START_SELECTION;
|
|
87
|
-
}
|
|
88
|
-
interface EndSelectionAction extends Action {
|
|
89
|
-
type: typeof END_SELECTION;
|
|
90
|
-
}
|
|
91
|
-
interface ClearSelectionAction extends Action {
|
|
92
|
-
type: typeof CLEAR_SELECTION;
|
|
93
|
-
}
|
|
94
|
-
interface SetRectsAction extends Action {
|
|
95
|
-
type: typeof SET_RECTS;
|
|
96
|
-
payload: Record<number, Rect[]>;
|
|
97
|
-
}
|
|
98
|
-
interface SetSlicesAction extends Action {
|
|
99
|
-
type: typeof SET_SLICES;
|
|
100
|
-
payload: Record<number, {
|
|
101
|
-
start: number;
|
|
102
|
-
count: number;
|
|
103
|
-
}>;
|
|
104
|
-
}
|
|
105
|
-
interface ResetAction extends Action {
|
|
106
|
-
type: typeof RESET;
|
|
107
|
-
}
|
|
108
|
-
type SelectionAction = CachePageGeometryAction | SetSelectionAction | StartSelectionAction | EndSelectionAction | ClearSelectionAction | SetRectsAction | SetSlicesAction | ResetAction;
|
|
109
|
-
|
|
110
|
-
declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, SelectionCapability, SelectionState, SelectionAction> {
|
|
111
|
-
private engine;
|
|
112
|
-
static readonly id: "selection";
|
|
113
|
-
/** Modes that should trigger text-selection logic */
|
|
114
|
-
private enabledModes;
|
|
115
|
-
private selecting;
|
|
116
|
-
private anchor?;
|
|
117
|
-
private readonly selChange$;
|
|
118
|
-
private readonly textRetrieved$;
|
|
119
|
-
private readonly copyToClipboard$;
|
|
120
|
-
private readonly beginSelection$;
|
|
121
|
-
private readonly endSelection$;
|
|
122
|
-
constructor(id: string, registry: PluginRegistry, engine: PdfEngine);
|
|
123
|
-
initialize(): Promise<void>;
|
|
124
|
-
destroy(): Promise<void>;
|
|
125
|
-
buildCapability(): SelectionCapability;
|
|
126
|
-
private getOrLoadGeometry;
|
|
127
|
-
private beginSelection;
|
|
128
|
-
private endSelection;
|
|
129
|
-
private clearSelection;
|
|
130
|
-
private updateSelection;
|
|
131
|
-
private updateRectsAndSlices;
|
|
132
|
-
private getSelectedText;
|
|
133
|
-
private copyToClipboard;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
declare const SELECTION_PLUGIN_ID = "selection";
|
|
137
|
-
declare const manifest: PluginManifest<SelectionPluginConfig>;
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Hit-test helper using runs
|
|
141
|
-
* @param geo - page geometry
|
|
142
|
-
* @param pt - point
|
|
143
|
-
* @returns glyph index
|
|
144
|
-
*/
|
|
145
|
-
declare function glyphAt(geo: PdfPageGeometry, pt: {
|
|
146
|
-
x: number;
|
|
147
|
-
y: number;
|
|
148
|
-
}): number;
|
|
149
|
-
/**
|
|
150
|
-
* Helper: min/max glyph indices on `page` for current sel
|
|
151
|
-
* @param sel - selection range
|
|
152
|
-
* @param geo - page geometry
|
|
153
|
-
* @param page - page index
|
|
154
|
-
* @returns { from: number; to: number } | null
|
|
155
|
-
*/
|
|
156
|
-
declare function sliceBounds(sel: SelectionRangeX | null, geo: PdfPageGeometry | undefined, page: number): {
|
|
157
|
-
from: number;
|
|
158
|
-
to: number;
|
|
159
|
-
} | null;
|
|
160
|
-
/**
|
|
161
|
-
* Helper: build rects for a slice of the page
|
|
162
|
-
* @param geo - page geometry
|
|
163
|
-
* @param from - from index
|
|
164
|
-
* @param to - to index
|
|
165
|
-
* @param merge - whether to merge adjacent rects (default: true)
|
|
166
|
-
* @returns rects
|
|
167
|
-
*/
|
|
168
|
-
declare function rectsWithinSlice(geo: PdfPageGeometry, from: number, to: number, merge?: boolean): Rect[];
|
|
169
|
-
/**
|
|
170
|
-
* ============================================================================
|
|
171
|
-
* Rectangle Merging Algorithm
|
|
172
|
-
* ============================================================================
|
|
173
|
-
*
|
|
174
|
-
* The following code is adapted from Chromium's PDF text selection implementation.
|
|
175
|
-
*
|
|
176
|
-
* Copyright 2010 The Chromium Authors
|
|
177
|
-
* Use of this source code is governed by a BSD-style license that can be
|
|
178
|
-
* found in the LICENSE file: https://source.chromium.org/chromium/chromium/src/+/main:LICENSE
|
|
179
|
-
*
|
|
180
|
-
* Original source:
|
|
181
|
-
* https://source.chromium.org/chromium/chromium/src/+/main:pdf/pdfium/pdfium_range.cc
|
|
182
|
-
*
|
|
183
|
-
* Adapted for TypeScript and this project's Rect/geometry types.
|
|
184
|
-
*/
|
|
185
|
-
/**
|
|
186
|
-
* Text run info for rect merging (similar to Chromium's ScreenRectTextRunInfo)
|
|
187
|
-
*/
|
|
188
|
-
interface TextRunInfo {
|
|
189
|
-
rect: Rect;
|
|
190
|
-
charCount: number;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Helper functions for Rect operations
|
|
194
|
-
*/
|
|
195
|
-
declare function rectUnion(rect1: Rect, rect2: Rect): Rect;
|
|
196
|
-
declare function rectIntersect(rect1: Rect, rect2: Rect): Rect;
|
|
197
|
-
declare function rectIsEmpty(rect: Rect): boolean;
|
|
198
|
-
/**
|
|
199
|
-
* Returns a ratio between [0, 1] representing vertical overlap
|
|
200
|
-
*/
|
|
201
|
-
declare function getVerticalOverlap(rect1: Rect, rect2: Rect): number;
|
|
202
|
-
/**
|
|
203
|
-
* Returns true if there is sufficient horizontal and vertical overlap
|
|
204
|
-
*/
|
|
205
|
-
declare function shouldMergeHorizontalRects(textRun1: TextRunInfo, textRun2: TextRunInfo): boolean;
|
|
206
|
-
/**
|
|
207
|
-
* Merge adjacent rectangles based on proximity and overlap (similar to Chromium's algorithm)
|
|
208
|
-
*/
|
|
209
|
-
declare function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[];
|
|
210
|
-
|
|
211
|
-
declare const SelectionPluginPackage: PluginPackage<SelectionPlugin, SelectionPluginConfig, SelectionState, SelectionAction>;
|
|
212
|
-
|
|
213
|
-
export { type FormattedSelection, type GlyphPointer, SELECTION_PLUGIN_ID, type SelectionCapability, SelectionPlugin, type SelectionPluginConfig, SelectionPluginPackage, type SelectionRangeX, type SelectionState, type TextRunInfo, getVerticalOverlap, glyphAt, manifest, mergeAdjacentRects, rectIntersect, rectIsEmpty, rectUnion, rectsWithinSlice, shouldMergeHorizontalRects, sliceBounds };
|
|
1
|
+
export * from './lib';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { BasePlugin, createBehaviorEmitter, createEmitter, SET_DOCUMENT } from "@embedpdf/core";
|
|
2
|
+
import { boundingRect, PdfTaskHelper, PdfErrorCode, ignore } from "@embedpdf/models";
|
|
3
|
+
const SELECTION_PLUGIN_ID = "selection";
|
|
4
|
+
const manifest = {
|
|
4
5
|
id: SELECTION_PLUGIN_ID,
|
|
5
6
|
name: "Selection Plugin",
|
|
6
7
|
version: "1.0.0",
|
|
@@ -11,49 +12,31 @@ var manifest = {
|
|
|
11
12
|
enabled: true
|
|
12
13
|
}
|
|
13
14
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
PdfTaskHelper,
|
|
24
|
-
PdfErrorCode,
|
|
25
|
-
ignore
|
|
26
|
-
} from "@embedpdf/models";
|
|
27
|
-
|
|
28
|
-
// src/lib/actions.ts
|
|
29
|
-
var CACHE_PAGE_GEOMETRY = "CACHE_PAGE_GEOMETRY";
|
|
30
|
-
var SET_SELECTION = "SET_SELECTION";
|
|
31
|
-
var START_SELECTION = "START_SELECTION";
|
|
32
|
-
var END_SELECTION = "END_SELECTION";
|
|
33
|
-
var CLEAR_SELECTION = "CLEAR_SELECTION";
|
|
34
|
-
var SET_RECTS = "SET_RECTS";
|
|
35
|
-
var SET_SLICES = "SET_SLICES";
|
|
36
|
-
var RESET = "RESET";
|
|
37
|
-
var cachePageGeometry = (page, geo) => ({
|
|
15
|
+
const CACHE_PAGE_GEOMETRY = "CACHE_PAGE_GEOMETRY";
|
|
16
|
+
const SET_SELECTION = "SET_SELECTION";
|
|
17
|
+
const START_SELECTION = "START_SELECTION";
|
|
18
|
+
const END_SELECTION = "END_SELECTION";
|
|
19
|
+
const CLEAR_SELECTION = "CLEAR_SELECTION";
|
|
20
|
+
const SET_RECTS = "SET_RECTS";
|
|
21
|
+
const SET_SLICES = "SET_SLICES";
|
|
22
|
+
const RESET = "RESET";
|
|
23
|
+
const cachePageGeometry = (page, geo) => ({
|
|
38
24
|
type: CACHE_PAGE_GEOMETRY,
|
|
39
25
|
payload: { page, geo }
|
|
40
26
|
});
|
|
41
|
-
|
|
27
|
+
const setSelection = (sel) => ({
|
|
42
28
|
type: SET_SELECTION,
|
|
43
29
|
payload: sel
|
|
44
30
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
const startSelection = () => ({ type: START_SELECTION });
|
|
32
|
+
const endSelection = () => ({ type: END_SELECTION });
|
|
33
|
+
const clearSelection = () => ({ type: CLEAR_SELECTION });
|
|
34
|
+
const setRects = (allRects) => ({
|
|
49
35
|
type: SET_RECTS,
|
|
50
36
|
payload: allRects
|
|
51
37
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// src/lib/selectors.ts
|
|
56
|
-
import { boundingRect } from "@embedpdf/models";
|
|
38
|
+
const setSlices = (slices) => ({ type: SET_SLICES, payload: slices });
|
|
39
|
+
const reset = () => ({ type: RESET });
|
|
57
40
|
function selectRectsForPage(state, page) {
|
|
58
41
|
return state.rects[page] ?? [];
|
|
59
42
|
}
|
|
@@ -94,8 +77,6 @@ function getFormattedSelection(state) {
|
|
|
94
77
|
}
|
|
95
78
|
return result;
|
|
96
79
|
}
|
|
97
|
-
|
|
98
|
-
// src/lib/utils.ts
|
|
99
80
|
function glyphAt(geo, pt) {
|
|
100
81
|
for (const run of geo.runs) {
|
|
101
82
|
const inRun = pt.y >= run.rect.y && pt.y <= run.rect.y + run.rect.height && pt.x >= run.rect.x && pt.x <= run.rect.x + run.rect.width;
|
|
@@ -225,15 +206,11 @@ function mergeAdjacentRects(textRuns) {
|
|
|
225
206
|
}
|
|
226
207
|
return results;
|
|
227
208
|
}
|
|
228
|
-
|
|
229
|
-
// src/lib/selection-plugin.ts
|
|
230
|
-
var SelectionPlugin = class extends BasePlugin {
|
|
209
|
+
const _SelectionPlugin = class _SelectionPlugin extends BasePlugin {
|
|
231
210
|
constructor(id, registry, engine) {
|
|
232
211
|
super(id, registry);
|
|
233
212
|
this.engine = engine;
|
|
234
|
-
/** Modes that should trigger text-selection logic */
|
|
235
213
|
this.enabledModes = /* @__PURE__ */ new Set(["default"]);
|
|
236
|
-
/* interactive state */
|
|
237
214
|
this.selecting = false;
|
|
238
215
|
this.selChange$ = createBehaviorEmitter();
|
|
239
216
|
this.textRetrieved$ = createBehaviorEmitter();
|
|
@@ -359,10 +336,9 @@ var SelectionPlugin = class extends BasePlugin {
|
|
|
359
336
|
}, ignore);
|
|
360
337
|
}
|
|
361
338
|
};
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
var initialState = {
|
|
339
|
+
_SelectionPlugin.id = "selection";
|
|
340
|
+
let SelectionPlugin = _SelectionPlugin;
|
|
341
|
+
const initialState = {
|
|
366
342
|
geometry: {},
|
|
367
343
|
rects: {},
|
|
368
344
|
slices: {},
|
|
@@ -370,7 +346,7 @@ var initialState = {
|
|
|
370
346
|
active: false,
|
|
371
347
|
selecting: false
|
|
372
348
|
};
|
|
373
|
-
|
|
349
|
+
const selectionReducer = (state = initialState, action) => {
|
|
374
350
|
switch (action.type) {
|
|
375
351
|
case CACHE_PAGE_GEOMETRY: {
|
|
376
352
|
const { page, geo } = action.payload;
|
|
@@ -394,9 +370,7 @@ var selectionReducer = (state = initialState, action) => {
|
|
|
394
370
|
return state;
|
|
395
371
|
}
|
|
396
372
|
};
|
|
397
|
-
|
|
398
|
-
// src/lib/index.ts
|
|
399
|
-
var SelectionPluginPackage = {
|
|
373
|
+
const SelectionPluginPackage = {
|
|
400
374
|
manifest,
|
|
401
375
|
create: (registry, engine) => new SelectionPlugin(SELECTION_PLUGIN_ID, registry, engine),
|
|
402
376
|
reducer: selectionReducer,
|
|
@@ -417,4 +391,4 @@ export {
|
|
|
417
391
|
shouldMergeHorizontalRects,
|
|
418
392
|
sliceBounds
|
|
419
393
|
};
|
|
420
|
-
//# sourceMappingURL=index.js.map
|
|
394
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/manifest.ts","../src/lib/selection-plugin.ts","../src/lib/actions.ts","../src/lib/selectors.ts","../src/lib/utils.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\nimport { SelectionPluginConfig } from './types';\n\nexport const SELECTION_PLUGIN_ID = 'selection';\n\nexport const manifest: PluginManifest<SelectionPluginConfig> = {\n id: SELECTION_PLUGIN_ID,\n name: 'Selection Plugin',\n version: '1.0.0',\n provides: ['selection'],\n requires: ['interaction-manager'],\n optional: [],\n defaultConfig: {\n enabled: true,\n },\n};\n","import {\n BasePlugin,\n PluginRegistry,\n SET_DOCUMENT,\n createBehaviorEmitter,\n createEmitter,\n} from '@embedpdf/core';\nimport {\n PdfEngine,\n PdfPageGeometry,\n Rect,\n PdfTask,\n PdfTaskHelper,\n PdfErrorCode,\n ignore,\n PageTextSlice,\n} from '@embedpdf/models';\n\nimport {\n cachePageGeometry,\n setSelection,\n SelectionAction,\n endSelection,\n startSelection,\n clearSelection,\n reset,\n setRects,\n setSlices,\n} from './actions';\nimport * as selector from './selectors';\nimport {\n SelectionCapability,\n SelectionPluginConfig,\n SelectionRangeX,\n SelectionState,\n} from './types';\nimport { sliceBounds, rectsWithinSlice } from './utils';\n\nexport class SelectionPlugin extends BasePlugin<\n SelectionPluginConfig,\n SelectionCapability,\n SelectionState,\n SelectionAction\n> {\n static readonly id = 'selection' as const;\n\n /** Modes that should trigger text-selection logic */\n private enabledModes = new Set<string>(['default']);\n\n /* interactive state */\n private selecting = false;\n private anchor?: { page: number; index: number };\n\n private readonly selChange$ = createBehaviorEmitter<SelectionState['selection']>();\n private readonly textRetrieved$ = createBehaviorEmitter<string[]>();\n private readonly copyToClipboard$ = createEmitter<string>();\n private readonly beginSelection$ = createEmitter<{ page: number; index: number }>();\n private readonly endSelection$ = createEmitter<void>();\n\n constructor(\n id: string,\n registry: PluginRegistry,\n private engine: PdfEngine,\n ) {\n super(id, registry);\n\n this.coreStore.onAction(SET_DOCUMENT, (_action) => {\n this.dispatch(reset());\n });\n }\n\n /* ── life-cycle ────────────────────────────────────────── */\n async initialize() {}\n async destroy() {\n this.selChange$.clear();\n }\n\n /* ── capability exposed to UI / other plugins ─────────── */\n buildCapability(): SelectionCapability {\n return {\n getGeometry: (p) => this.getOrLoadGeometry(p),\n getFormattedSelection: () => selector.getFormattedSelection(this.state),\n getFormattedSelectionForPage: (p) => selector.getFormattedSelectionForPage(this.state, p),\n getHighlightRectsForPage: (p) => selector.selectRectsForPage(this.state, p),\n getHighlightRects: () => this.state.rects,\n getBoundingRectForPage: (p) => selector.selectBoundingRectForPage(this.state, p),\n getBoundingRects: () => selector.selectBoundingRectsForAllPages(this.state),\n begin: (p, i) => this.beginSelection(p, i),\n update: (p, i) => this.updateSelection(p, i),\n end: () => this.endSelection(),\n clear: () => this.clearSelection(),\n onCopyToClipboard: this.copyToClipboard$.on,\n onSelectionChange: this.selChange$.on,\n onTextRetrieved: this.textRetrieved$.on,\n onBeginSelection: this.beginSelection$.on,\n onEndSelection: this.endSelection$.on,\n getSelectedText: () => this.getSelectedText(),\n copyToClipboard: () => this.copyToClipboard(),\n enableForMode: (id: string) => this.enabledModes.add(id),\n isEnabledForMode: (id: string) => this.enabledModes.has(id),\n getState: () => this.state,\n };\n }\n\n /* ── geometry cache ───────────────────────────────────── */\n private getOrLoadGeometry(pageIdx: number): PdfTask<PdfPageGeometry> {\n const cached = this.state.geometry[pageIdx];\n if (cached) return PdfTaskHelper.resolve(cached);\n\n if (!this.coreState.core.document)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Doc Not Found' });\n const page = this.coreState.core.document.pages.find((p) => p.index === pageIdx)!;\n\n const task = this.engine.getPageGeometry(this.coreState.core.document, page);\n\n task.wait((geo) => {\n this.dispatch(cachePageGeometry(pageIdx, geo));\n }, ignore);\n\n return task;\n }\n\n /* ── selection state updates ───────────────────────────── */\n private beginSelection(page: number, index: number) {\n this.selecting = true;\n this.anchor = { page, index };\n this.dispatch(startSelection());\n this.beginSelection$.emit({ page, index });\n }\n\n private endSelection() {\n this.selecting = false;\n this.anchor = undefined;\n this.dispatch(endSelection());\n this.endSelection$.emit();\n }\n\n private clearSelection() {\n this.selecting = false;\n this.anchor = undefined;\n this.dispatch(clearSelection());\n this.selChange$.emit(null);\n }\n\n private updateSelection(page: number, index: number) {\n if (!this.selecting || !this.anchor) return;\n\n const a = this.anchor;\n const forward = page > a.page || (page === a.page && index >= a.index);\n\n const start = forward ? a : { page, index };\n const end = forward ? { page, index } : a;\n\n const range = { start, end };\n this.dispatch(setSelection(range));\n this.updateRectsAndSlices(range);\n this.selChange$.emit(range);\n }\n\n private updateRectsAndSlices(range: SelectionRangeX) {\n const allRects: Record<number, Rect[]> = {};\n const allSlices: Record<number, { start: number; count: number }> = {};\n\n for (let p = range.start.page; p <= range.end.page; p++) {\n const geo = this.state.geometry[p];\n const sb = sliceBounds(range, geo, p);\n if (!sb) continue;\n\n allRects[p] = rectsWithinSlice(geo!, sb.from, sb.to);\n allSlices[p] = { start: sb.from, count: sb.to - sb.from + 1 };\n }\n\n this.dispatch(setRects(allRects));\n this.dispatch(setSlices(allSlices));\n }\n\n private getSelectedText(): PdfTask<string[]> {\n if (!this.coreState.core.document || !this.state.selection) {\n return PdfTaskHelper.reject({\n code: PdfErrorCode.NotFound,\n message: 'Doc Not Found or No Selection',\n });\n }\n\n const sel = this.state.selection;\n const req: PageTextSlice[] = [];\n\n for (let p = sel.start.page; p <= sel.end.page; p++) {\n const s = this.state.slices[p];\n if (s) req.push({ pageIndex: p, charIndex: s.start, charCount: s.count });\n }\n\n if (req.length === 0) return PdfTaskHelper.resolve([] as string[]);\n\n const task = this.engine.getTextSlices(this.coreState.core.document, req);\n\n // Emit the text when it's retrieved\n task.wait((text) => {\n this.textRetrieved$.emit(text);\n }, ignore);\n\n return task;\n }\n\n private copyToClipboard() {\n const text = this.getSelectedText();\n text.wait((text) => {\n this.copyToClipboard$.emit(text.join('\\n'));\n }, ignore);\n }\n}\n","import { Action } from '@embedpdf/core';\nimport { PdfPageGeometry, Rect } from '@embedpdf/models';\nimport { SelectionRangeX } from './types';\n\nexport const CACHE_PAGE_GEOMETRY = 'CACHE_PAGE_GEOMETRY';\nexport const SET_SELECTION = 'SET_SELECTION';\nexport const START_SELECTION = 'START_SELECTION';\nexport const END_SELECTION = 'END_SELECTION';\nexport const CLEAR_SELECTION = 'CLEAR_SELECTION';\nexport const SET_RECTS = 'SET_RECTS';\nexport const SET_SLICES = 'SET_SLICES';\nexport const RESET = 'RESET';\n\nexport interface CachePageGeometryAction extends Action {\n type: typeof CACHE_PAGE_GEOMETRY;\n payload: { page: number; geo: PdfPageGeometry };\n}\nexport interface SetSelectionAction extends Action {\n type: typeof SET_SELECTION;\n payload: SelectionRangeX | null;\n}\n\nexport interface StartSelectionAction extends Action {\n type: typeof START_SELECTION;\n}\n\nexport interface EndSelectionAction extends Action {\n type: typeof END_SELECTION;\n}\n\nexport interface ClearSelectionAction extends Action {\n type: typeof CLEAR_SELECTION;\n}\n\nexport interface SetRectsAction extends Action {\n type: typeof SET_RECTS;\n payload: Record<number, Rect[]>;\n}\n\nexport interface SetSlicesAction extends Action {\n type: typeof SET_SLICES;\n payload: Record<number, { start: number; count: number }>;\n}\n\nexport interface ResetAction extends Action {\n type: typeof RESET;\n}\n\nexport type SelectionAction =\n | CachePageGeometryAction\n | SetSelectionAction\n | StartSelectionAction\n | EndSelectionAction\n | ClearSelectionAction\n | SetRectsAction\n | SetSlicesAction\n | ResetAction;\n\nexport const cachePageGeometry = (page: number, geo: PdfPageGeometry): CachePageGeometryAction => ({\n type: CACHE_PAGE_GEOMETRY,\n payload: { page, geo },\n});\n\nexport const setSelection = (sel: SelectionRangeX): SetSelectionAction => ({\n type: SET_SELECTION,\n payload: sel,\n});\n\nexport const startSelection = (): StartSelectionAction => ({ type: START_SELECTION });\n\nexport const endSelection = (): EndSelectionAction => ({ type: END_SELECTION });\n\nexport const clearSelection = (): ClearSelectionAction => ({ type: CLEAR_SELECTION });\n\nexport const setRects = (allRects: Record<number, Rect[]>): SetRectsAction => ({\n type: SET_RECTS,\n payload: allRects,\n});\n\nexport const setSlices = (\n slices: Record<number, { start: number; count: number }>,\n): SetSlicesAction => ({ type: SET_SLICES, payload: slices });\n\nexport const reset = (): ResetAction => ({ type: RESET });\n","import { Rect, boundingRect } from '@embedpdf/models';\nimport { FormattedSelection, SelectionState } from './types';\n\nexport function selectRectsForPage(state: SelectionState, page: number) {\n return state.rects[page] ?? [];\n}\n\nexport function selectBoundingRectForPage(state: SelectionState, page: number) {\n return boundingRect(selectRectsForPage(state, page));\n}\n\nexport function selectRectsAndBoundingRectForPage(state: SelectionState, page: number) {\n return {\n rects: selectRectsForPage(state, page),\n boundingRect: selectBoundingRectForPage(state, page),\n };\n}\n\nexport function selectBoundingRectsForAllPages(state: SelectionState) {\n const out: { page: number; rect: Rect }[] = [];\n const rectMap = state.rects;\n\n for (const key in rectMap) {\n const page = Number(key);\n const bRect = boundingRect(rectMap[page]);\n if (bRect) out.push({ page, rect: bRect });\n }\n return out;\n}\n\nexport function getFormattedSelectionForPage(\n state: SelectionState,\n page: number,\n): FormattedSelection | null {\n const segmentRects = state.rects[page] || [];\n if (segmentRects.length === 0) return null;\n const boundingRect = selectBoundingRectForPage(state, page);\n if (!boundingRect) return null;\n return { pageIndex: page, rect: boundingRect, segmentRects };\n}\n\nexport function getFormattedSelection(state: SelectionState) {\n const result: FormattedSelection[] = [];\n\n // Get all pages that have rects\n const pages = Object.keys(state.rects).map(Number);\n\n for (const pageIndex of pages) {\n const segmentRects = state.rects[pageIndex] || [];\n\n if (segmentRects.length === 0) continue;\n\n // Calculate bounding rect for this page\n const boundingRect = selectBoundingRectForPage(state, pageIndex);\n\n if (boundingRect) {\n result.push({\n pageIndex,\n rect: boundingRect,\n segmentRects,\n });\n }\n }\n\n return result;\n}\n","import { PdfPageGeometry, Rect } from '@embedpdf/models';\nimport { SelectionRangeX } from './types';\n\n/**\n * Hit-test helper using runs\n * @param geo - page geometry\n * @param pt - point\n * @returns glyph index\n */\nexport function glyphAt(geo: PdfPageGeometry, pt: { x: number; y: number }) {\n for (const run of geo.runs) {\n const inRun =\n pt.y >= run.rect.y &&\n pt.y <= run.rect.y + run.rect.height &&\n pt.x >= run.rect.x &&\n pt.x <= run.rect.x + run.rect.width;\n\n if (!inRun) continue;\n\n // Simply check if the point is within any glyph's bounding box\n const rel = run.glyphs.findIndex(\n (g) => pt.x >= g.x && pt.x <= g.x + g.width && pt.y >= g.y && pt.y <= g.y + g.height,\n );\n\n if (rel !== -1) {\n return run.charStart + rel;\n }\n }\n return -1;\n}\n\n/**\n * Helper: min/max glyph indices on `page` for current sel\n * @param sel - selection range\n * @param geo - page geometry\n * @param page - page index\n * @returns { from: number; to: number } | null\n */\nexport function sliceBounds(\n sel: SelectionRangeX | null,\n geo: PdfPageGeometry | undefined,\n page: number,\n): { from: number; to: number } | null {\n if (!sel || !geo) return null;\n if (page < sel.start.page || page > sel.end.page) return null;\n\n const from = page === sel.start.page ? sel.start.index : 0;\n\n const lastRun = geo.runs[geo.runs.length - 1];\n const lastCharOnPage = lastRun.charStart + lastRun.glyphs.length - 1;\n\n const to = page === sel.end.page ? sel.end.index : lastCharOnPage;\n\n return { from, to };\n}\n\n/**\n * Helper: build rects for a slice of the page\n * @param geo - page geometry\n * @param from - from index\n * @param to - to index\n * @param merge - whether to merge adjacent rects (default: true)\n * @returns rects\n */\nexport function rectsWithinSlice(\n geo: PdfPageGeometry,\n from: number,\n to: number,\n merge: boolean = true,\n): Rect[] {\n const textRuns: TextRunInfo[] = [];\n\n for (const run of geo.runs) {\n const runStart = run.charStart;\n const runEnd = runStart + run.glyphs.length - 1;\n if (runEnd < from || runStart > to) continue;\n\n const sIdx = Math.max(from, runStart) - runStart;\n const eIdx = Math.min(to, runEnd) - runStart;\n\n let minX = Infinity,\n maxX = -Infinity;\n let minY = Infinity,\n maxY = -Infinity;\n let charCount = 0;\n\n for (let i = sIdx; i <= eIdx; i++) {\n const g = run.glyphs[i];\n if (g.flags === 2) continue; // empty glyph\n\n minX = Math.min(minX, g.x);\n maxX = Math.max(maxX, g.x + g.width);\n minY = Math.min(minY, g.y);\n maxY = Math.max(maxY, g.y + g.height);\n charCount++;\n }\n\n if (minX !== Infinity && charCount > 0) {\n textRuns.push({\n rect: {\n origin: { x: minX, y: minY },\n size: { width: maxX - minX, height: maxY - minY },\n },\n charCount,\n });\n }\n }\n\n // If merge is false, just return the individual rects\n if (!merge) {\n return textRuns.map((run) => run.rect);\n }\n\n // Otherwise merge adjacent rects\n return mergeAdjacentRects(textRuns);\n}\n\n/**\n * ============================================================================\n * Rectangle Merging Algorithm\n * ============================================================================\n *\n * The following code is adapted from Chromium's PDF text selection implementation.\n *\n * Copyright 2010 The Chromium Authors\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file: https://source.chromium.org/chromium/chromium/src/+/main:LICENSE\n *\n * Original source:\n * https://source.chromium.org/chromium/chromium/src/+/main:pdf/pdfium/pdfium_range.cc\n *\n * Adapted for TypeScript and this project's Rect/geometry types.\n */\n\n/**\n * Text run info for rect merging (similar to Chromium's ScreenRectTextRunInfo)\n */\nexport interface TextRunInfo {\n rect: Rect;\n charCount: number;\n}\n\n/**\n * Helper functions for Rect operations\n */\nexport function rectUnion(rect1: Rect, rect2: Rect): Rect {\n const left = Math.min(rect1.origin.x, rect2.origin.x);\n const top = Math.min(rect1.origin.y, rect2.origin.y);\n const right = Math.max(rect1.origin.x + rect1.size.width, rect2.origin.x + rect2.size.width);\n const bottom = Math.max(rect1.origin.y + rect1.size.height, rect2.origin.y + rect2.size.height);\n\n return {\n origin: { x: left, y: top },\n size: { width: right - left, height: bottom - top },\n };\n}\n\nexport function rectIntersect(rect1: Rect, rect2: Rect): Rect {\n const left = Math.max(rect1.origin.x, rect2.origin.x);\n const top = Math.max(rect1.origin.y, rect2.origin.y);\n const right = Math.min(rect1.origin.x + rect1.size.width, rect2.origin.x + rect2.size.width);\n const bottom = Math.min(rect1.origin.y + rect1.size.height, rect2.origin.y + rect2.size.height);\n\n const width = Math.max(0, right - left);\n const height = Math.max(0, bottom - top);\n\n return {\n origin: { x: left, y: top },\n size: { width, height },\n };\n}\n\nexport function rectIsEmpty(rect: Rect): boolean {\n return rect.size.width <= 0 || rect.size.height <= 0;\n}\n\n/**\n * Returns a ratio between [0, 1] representing vertical overlap\n */\nexport function getVerticalOverlap(rect1: Rect, rect2: Rect): number {\n if (rectIsEmpty(rect1) || rectIsEmpty(rect2)) return 0;\n\n const unionRect = rectUnion(rect1, rect2);\n\n if (unionRect.size.height === rect1.size.height || unionRect.size.height === rect2.size.height) {\n return 1.0;\n }\n\n const intersectRect = rectIntersect(rect1, rect2);\n return intersectRect.size.height / unionRect.size.height;\n}\n\n/**\n * Returns true if there is sufficient horizontal and vertical overlap\n */\nexport function shouldMergeHorizontalRects(textRun1: TextRunInfo, textRun2: TextRunInfo): boolean {\n const VERTICAL_OVERLAP_THRESHOLD = 0.8;\n const rect1 = textRun1.rect;\n const rect2 = textRun2.rect;\n\n if (getVerticalOverlap(rect1, rect2) < VERTICAL_OVERLAP_THRESHOLD) {\n return false;\n }\n\n const HORIZONTAL_WIDTH_FACTOR = 1.0;\n const averageWidth1 = (HORIZONTAL_WIDTH_FACTOR * rect1.size.width) / textRun1.charCount;\n const averageWidth2 = (HORIZONTAL_WIDTH_FACTOR * rect2.size.width) / textRun2.charCount;\n\n const rect1Left = rect1.origin.x - averageWidth1;\n const rect1Right = rect1.origin.x + rect1.size.width + averageWidth1;\n const rect2Left = rect2.origin.x - averageWidth2;\n const rect2Right = rect2.origin.x + rect2.size.width + averageWidth2;\n\n return rect1Left < rect2Right && rect1Right > rect2Left;\n}\n\n/**\n * Merge adjacent rectangles based on proximity and overlap (similar to Chromium's algorithm)\n */\nexport function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[] {\n const results: Rect[] = [];\n let previousTextRun: TextRunInfo | null = null;\n let currentRect: Rect | null = null;\n\n for (const textRun of textRuns) {\n if (previousTextRun && currentRect) {\n if (shouldMergeHorizontalRects(previousTextRun, textRun)) {\n currentRect = rectUnion(currentRect, textRun.rect);\n } else {\n results.push(currentRect);\n currentRect = textRun.rect;\n }\n } else {\n currentRect = textRun.rect;\n }\n previousTextRun = textRun;\n }\n\n if (currentRect && !rectIsEmpty(currentRect)) {\n results.push(currentRect);\n }\n\n return results;\n}\n","import { SelectionState } from './types';\nimport {\n SelectionAction,\n CACHE_PAGE_GEOMETRY,\n SET_SELECTION,\n START_SELECTION,\n END_SELECTION,\n CLEAR_SELECTION,\n RESET,\n SET_SLICES,\n SET_RECTS,\n} from './actions';\n\nexport const initialState: SelectionState = {\n geometry: {},\n rects: {},\n slices: {},\n selection: null,\n active: false,\n selecting: false,\n};\n\nexport const selectionReducer = (state = initialState, action: SelectionAction): SelectionState => {\n switch (action.type) {\n case CACHE_PAGE_GEOMETRY: {\n const { page, geo } = action.payload;\n return { ...state, geometry: { ...state.geometry, [page]: geo } };\n }\n case SET_SELECTION:\n return { ...state, selection: action.payload, active: true };\n case START_SELECTION:\n return { ...state, selecting: true, selection: null, rects: {} };\n case END_SELECTION:\n return { ...state, selecting: false };\n case CLEAR_SELECTION:\n return { ...state, selecting: false, selection: null, rects: {}, active: false };\n case SET_RECTS:\n return { ...state, rects: action.payload };\n case SET_SLICES:\n return { ...state, slices: action.payload };\n case RESET:\n return initialState;\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { manifest, SELECTION_PLUGIN_ID } from './manifest';\nimport { SelectionPluginConfig, SelectionState } from './types';\n\nimport { SelectionPlugin } from './selection-plugin';\nimport { SelectionAction } from './actions';\nimport { selectionReducer, initialState } from './reducer';\n\nexport const SelectionPluginPackage: PluginPackage<\n SelectionPlugin,\n SelectionPluginConfig,\n SelectionState,\n SelectionAction\n> = {\n manifest,\n create: (registry, engine) => new SelectionPlugin(SELECTION_PLUGIN_ID, registry, engine),\n reducer: selectionReducer,\n initialState,\n};\n\nexport * from './selection-plugin';\nexport * from './types';\nexport * from './manifest';\nexport * from './utils';\n"],"mappings":"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","names":["boundingRect","text"]}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/selectors.ts","../src/lib/utils.ts","../src/lib/selection-plugin.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\nimport { SelectionPluginConfig } from './types';\n\nexport const SELECTION_PLUGIN_ID = 'selection';\n\nexport const manifest: PluginManifest<SelectionPluginConfig> = {\n id: SELECTION_PLUGIN_ID,\n name: 'Selection Plugin',\n version: '1.0.0',\n provides: ['selection'],\n requires: ['interaction-manager'],\n optional: [],\n defaultConfig: {\n enabled: true,\n },\n};\n","import { Action } from '@embedpdf/core';\nimport { PdfPageGeometry, Rect } from '@embedpdf/models';\nimport { SelectionRangeX } from './types';\n\nexport const CACHE_PAGE_GEOMETRY = 'CACHE_PAGE_GEOMETRY';\nexport const SET_SELECTION = 'SET_SELECTION';\nexport const START_SELECTION = 'START_SELECTION';\nexport const END_SELECTION = 'END_SELECTION';\nexport const CLEAR_SELECTION = 'CLEAR_SELECTION';\nexport const SET_RECTS = 'SET_RECTS';\nexport const SET_SLICES = 'SET_SLICES';\nexport const RESET = 'RESET';\n\nexport interface CachePageGeometryAction extends Action {\n type: typeof CACHE_PAGE_GEOMETRY;\n payload: { page: number; geo: PdfPageGeometry };\n}\nexport interface SetSelectionAction extends Action {\n type: typeof SET_SELECTION;\n payload: SelectionRangeX | null;\n}\n\nexport interface StartSelectionAction extends Action {\n type: typeof START_SELECTION;\n}\n\nexport interface EndSelectionAction extends Action {\n type: typeof END_SELECTION;\n}\n\nexport interface ClearSelectionAction extends Action {\n type: typeof CLEAR_SELECTION;\n}\n\nexport interface SetRectsAction extends Action {\n type: typeof SET_RECTS;\n payload: Record<number, Rect[]>;\n}\n\nexport interface SetSlicesAction extends Action {\n type: typeof SET_SLICES;\n payload: Record<number, { start: number; count: number }>;\n}\n\nexport interface ResetAction extends Action {\n type: typeof RESET;\n}\n\nexport type SelectionAction =\n | CachePageGeometryAction\n | SetSelectionAction\n | StartSelectionAction\n | EndSelectionAction\n | ClearSelectionAction\n | SetRectsAction\n | SetSlicesAction\n | ResetAction;\n\nexport const cachePageGeometry = (page: number, geo: PdfPageGeometry): CachePageGeometryAction => ({\n type: CACHE_PAGE_GEOMETRY,\n payload: { page, geo },\n});\n\nexport const setSelection = (sel: SelectionRangeX): SetSelectionAction => ({\n type: SET_SELECTION,\n payload: sel,\n});\n\nexport const startSelection = (): StartSelectionAction => ({ type: START_SELECTION });\n\nexport const endSelection = (): EndSelectionAction => ({ type: END_SELECTION });\n\nexport const clearSelection = (): ClearSelectionAction => ({ type: CLEAR_SELECTION });\n\nexport const setRects = (allRects: Record<number, Rect[]>): SetRectsAction => ({\n type: SET_RECTS,\n payload: allRects,\n});\n\nexport const setSlices = (\n slices: Record<number, { start: number; count: number }>,\n): SetSlicesAction => ({ type: SET_SLICES, payload: slices });\n\nexport const reset = (): ResetAction => ({ type: RESET });\n","import { Rect, boundingRect } from '@embedpdf/models';\nimport { FormattedSelection, SelectionState } from './types';\n\nexport function selectRectsForPage(state: SelectionState, page: number) {\n return state.rects[page] ?? [];\n}\n\nexport function selectBoundingRectForPage(state: SelectionState, page: number) {\n return boundingRect(selectRectsForPage(state, page));\n}\n\nexport function selectRectsAndBoundingRectForPage(state: SelectionState, page: number) {\n return {\n rects: selectRectsForPage(state, page),\n boundingRect: selectBoundingRectForPage(state, page),\n };\n}\n\nexport function selectBoundingRectsForAllPages(state: SelectionState) {\n const out: { page: number; rect: Rect }[] = [];\n const rectMap = state.rects;\n\n for (const key in rectMap) {\n const page = Number(key);\n const bRect = boundingRect(rectMap[page]);\n if (bRect) out.push({ page, rect: bRect });\n }\n return out;\n}\n\nexport function getFormattedSelectionForPage(\n state: SelectionState,\n page: number,\n): FormattedSelection | null {\n const segmentRects = state.rects[page] || [];\n if (segmentRects.length === 0) return null;\n const boundingRect = selectBoundingRectForPage(state, page);\n if (!boundingRect) return null;\n return { pageIndex: page, rect: boundingRect, segmentRects };\n}\n\nexport function getFormattedSelection(state: SelectionState) {\n const result: FormattedSelection[] = [];\n\n // Get all pages that have rects\n const pages = Object.keys(state.rects).map(Number);\n\n for (const pageIndex of pages) {\n const segmentRects = state.rects[pageIndex] || [];\n\n if (segmentRects.length === 0) continue;\n\n // Calculate bounding rect for this page\n const boundingRect = selectBoundingRectForPage(state, pageIndex);\n\n if (boundingRect) {\n result.push({\n pageIndex,\n rect: boundingRect,\n segmentRects,\n });\n }\n }\n\n return result;\n}\n","import { PdfPageGeometry, Position, Rect } from '@embedpdf/models';\nimport { SelectionRangeX } from './types';\n\n/**\n * Hit-test helper using runs\n * @param geo - page geometry\n * @param pt - point\n * @returns glyph index\n */\nexport function glyphAt(geo: PdfPageGeometry, pt: Position) {\n for (const run of geo.runs) {\n const inRun =\n pt.y >= run.rect.y &&\n pt.y <= run.rect.y + run.rect.height &&\n pt.x >= run.rect.x &&\n pt.x <= run.rect.x + run.rect.width;\n\n if (!inRun) continue;\n\n // Simply check if the point is within any glyph's bounding box\n const rel = run.glyphs.findIndex(\n (g) => pt.x >= g.x && pt.x <= g.x + g.width && pt.y >= g.y && pt.y <= g.y + g.height,\n );\n\n if (rel !== -1) {\n return run.charStart + rel;\n }\n }\n return -1;\n}\n\n/**\n * Helper: min/max glyph indices on `page` for current sel\n * @param sel - selection range\n * @param geo - page geometry\n * @param page - page index\n * @returns { from: number; to: number } | null\n */\nexport function sliceBounds(\n sel: SelectionRangeX | null,\n geo: PdfPageGeometry | undefined,\n page: number,\n): { from: number; to: number } | null {\n if (!sel || !geo) return null;\n if (page < sel.start.page || page > sel.end.page) return null;\n\n const from = page === sel.start.page ? sel.start.index : 0;\n\n const lastRun = geo.runs[geo.runs.length - 1];\n const lastCharOnPage = lastRun.charStart + lastRun.glyphs.length - 1;\n\n const to = page === sel.end.page ? sel.end.index : lastCharOnPage;\n\n return { from, to };\n}\n\n/**\n * Helper: build rects for a slice of the page\n * @param geo - page geometry\n * @param from - from index\n * @param to - to index\n * @param merge - whether to merge adjacent rects (default: true)\n * @returns rects\n */\nexport function rectsWithinSlice(\n geo: PdfPageGeometry,\n from: number,\n to: number,\n merge: boolean = true,\n): Rect[] {\n const textRuns: TextRunInfo[] = [];\n\n for (const run of geo.runs) {\n const runStart = run.charStart;\n const runEnd = runStart + run.glyphs.length - 1;\n if (runEnd < from || runStart > to) continue;\n\n const sIdx = Math.max(from, runStart) - runStart;\n const eIdx = Math.min(to, runEnd) - runStart;\n\n let minX = Infinity,\n maxX = -Infinity;\n let minY = Infinity,\n maxY = -Infinity;\n let charCount = 0;\n\n for (let i = sIdx; i <= eIdx; i++) {\n const g = run.glyphs[i];\n if (g.flags === 2) continue; // empty glyph\n\n minX = Math.min(minX, g.x);\n maxX = Math.max(maxX, g.x + g.width);\n minY = Math.min(minY, g.y);\n maxY = Math.max(maxY, g.y + g.height);\n charCount++;\n }\n\n if (minX !== Infinity && charCount > 0) {\n textRuns.push({\n rect: {\n origin: { x: minX, y: minY },\n size: { width: maxX - minX, height: maxY - minY },\n },\n charCount,\n });\n }\n }\n\n // If merge is false, just return the individual rects\n if (!merge) {\n return textRuns.map((run) => run.rect);\n }\n\n // Otherwise merge adjacent rects\n return mergeAdjacentRects(textRuns);\n}\n\n/**\n * ============================================================================\n * Rectangle Merging Algorithm\n * ============================================================================\n *\n * The following code is adapted from Chromium's PDF text selection implementation.\n *\n * Copyright 2010 The Chromium Authors\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file: https://source.chromium.org/chromium/chromium/src/+/main:LICENSE\n *\n * Original source:\n * https://source.chromium.org/chromium/chromium/src/+/main:pdf/pdfium/pdfium_range.cc\n *\n * Adapted for TypeScript and this project's Rect/geometry types.\n */\n\n/**\n * Text run info for rect merging (similar to Chromium's ScreenRectTextRunInfo)\n */\nexport interface TextRunInfo {\n rect: Rect;\n charCount: number;\n}\n\n/**\n * Helper functions for Rect operations\n */\nexport function rectUnion(rect1: Rect, rect2: Rect): Rect {\n const left = Math.min(rect1.origin.x, rect2.origin.x);\n const top = Math.min(rect1.origin.y, rect2.origin.y);\n const right = Math.max(rect1.origin.x + rect1.size.width, rect2.origin.x + rect2.size.width);\n const bottom = Math.max(rect1.origin.y + rect1.size.height, rect2.origin.y + rect2.size.height);\n\n return {\n origin: { x: left, y: top },\n size: { width: right - left, height: bottom - top },\n };\n}\n\nexport function rectIntersect(rect1: Rect, rect2: Rect): Rect {\n const left = Math.max(rect1.origin.x, rect2.origin.x);\n const top = Math.max(rect1.origin.y, rect2.origin.y);\n const right = Math.min(rect1.origin.x + rect1.size.width, rect2.origin.x + rect2.size.width);\n const bottom = Math.min(rect1.origin.y + rect1.size.height, rect2.origin.y + rect2.size.height);\n\n const width = Math.max(0, right - left);\n const height = Math.max(0, bottom - top);\n\n return {\n origin: { x: left, y: top },\n size: { width, height },\n };\n}\n\nexport function rectIsEmpty(rect: Rect): boolean {\n return rect.size.width <= 0 || rect.size.height <= 0;\n}\n\n/**\n * Returns a ratio between [0, 1] representing vertical overlap\n */\nexport function getVerticalOverlap(rect1: Rect, rect2: Rect): number {\n if (rectIsEmpty(rect1) || rectIsEmpty(rect2)) return 0;\n\n const unionRect = rectUnion(rect1, rect2);\n\n if (unionRect.size.height === rect1.size.height || unionRect.size.height === rect2.size.height) {\n return 1.0;\n }\n\n const intersectRect = rectIntersect(rect1, rect2);\n return intersectRect.size.height / unionRect.size.height;\n}\n\n/**\n * Returns true if there is sufficient horizontal and vertical overlap\n */\nexport function shouldMergeHorizontalRects(textRun1: TextRunInfo, textRun2: TextRunInfo): boolean {\n const VERTICAL_OVERLAP_THRESHOLD = 0.8;\n const rect1 = textRun1.rect;\n const rect2 = textRun2.rect;\n\n if (getVerticalOverlap(rect1, rect2) < VERTICAL_OVERLAP_THRESHOLD) {\n return false;\n }\n\n const HORIZONTAL_WIDTH_FACTOR = 1.0;\n const averageWidth1 = (HORIZONTAL_WIDTH_FACTOR * rect1.size.width) / textRun1.charCount;\n const averageWidth2 = (HORIZONTAL_WIDTH_FACTOR * rect2.size.width) / textRun2.charCount;\n\n const rect1Left = rect1.origin.x - averageWidth1;\n const rect1Right = rect1.origin.x + rect1.size.width + averageWidth1;\n const rect2Left = rect2.origin.x - averageWidth2;\n const rect2Right = rect2.origin.x + rect2.size.width + averageWidth2;\n\n return rect1Left < rect2Right && rect1Right > rect2Left;\n}\n\n/**\n * Merge adjacent rectangles based on proximity and overlap (similar to Chromium's algorithm)\n */\nexport function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[] {\n const results: Rect[] = [];\n let previousTextRun: TextRunInfo | null = null;\n let currentRect: Rect | null = null;\n\n for (const textRun of textRuns) {\n if (previousTextRun && currentRect) {\n if (shouldMergeHorizontalRects(previousTextRun, textRun)) {\n currentRect = rectUnion(currentRect, textRun.rect);\n } else {\n results.push(currentRect);\n currentRect = textRun.rect;\n }\n } else {\n currentRect = textRun.rect;\n }\n previousTextRun = textRun;\n }\n\n if (currentRect && !rectIsEmpty(currentRect)) {\n results.push(currentRect);\n }\n\n return results;\n}\n","import {\n BasePlugin,\n PluginRegistry,\n SET_DOCUMENT,\n createBehaviorEmitter,\n createEmitter,\n} from '@embedpdf/core';\nimport {\n PdfEngine,\n PdfPageGeometry,\n Rect,\n PdfTask,\n PdfTaskHelper,\n PdfErrorCode,\n ignore,\n PageTextSlice,\n} from '@embedpdf/models';\n\nimport {\n cachePageGeometry,\n setSelection,\n SelectionAction,\n endSelection,\n startSelection,\n clearSelection,\n reset,\n setRects,\n setSlices,\n} from './actions';\nimport * as selector from './selectors';\nimport {\n SelectionCapability,\n SelectionPluginConfig,\n SelectionRangeX,\n SelectionState,\n} from './types';\nimport { sliceBounds, rectsWithinSlice } from './utils';\n\nexport class SelectionPlugin extends BasePlugin<\n SelectionPluginConfig,\n SelectionCapability,\n SelectionState,\n SelectionAction\n> {\n static readonly id = 'selection' as const;\n\n /** Modes that should trigger text-selection logic */\n private enabledModes = new Set<string>(['default']);\n\n /* interactive state */\n private selecting = false;\n private anchor?: { page: number; index: number };\n\n private readonly selChange$ = createBehaviorEmitter<SelectionState['selection']>();\n private readonly textRetrieved$ = createBehaviorEmitter<string[]>();\n private readonly copyToClipboard$ = createEmitter<string>();\n private readonly beginSelection$ = createEmitter<{ page: number; index: number }>();\n private readonly endSelection$ = createEmitter<void>();\n\n constructor(\n id: string,\n registry: PluginRegistry,\n private engine: PdfEngine,\n ) {\n super(id, registry);\n\n this.coreStore.onAction(SET_DOCUMENT, (_action) => {\n this.dispatch(reset());\n });\n }\n\n /* ── life-cycle ────────────────────────────────────────── */\n async initialize() {}\n async destroy() {\n this.selChange$.clear();\n }\n\n /* ── capability exposed to UI / other plugins ─────────── */\n buildCapability(): SelectionCapability {\n return {\n getGeometry: (p) => this.getOrLoadGeometry(p),\n getFormattedSelection: () => selector.getFormattedSelection(this.state),\n getFormattedSelectionForPage: (p) => selector.getFormattedSelectionForPage(this.state, p),\n getHighlightRectsForPage: (p) => selector.selectRectsForPage(this.state, p),\n getHighlightRects: () => this.state.rects,\n getBoundingRectForPage: (p) => selector.selectBoundingRectForPage(this.state, p),\n getBoundingRects: () => selector.selectBoundingRectsForAllPages(this.state),\n begin: (p, i) => this.beginSelection(p, i),\n update: (p, i) => this.updateSelection(p, i),\n end: () => this.endSelection(),\n clear: () => this.clearSelection(),\n onCopyToClipboard: this.copyToClipboard$.on,\n onSelectionChange: this.selChange$.on,\n onTextRetrieved: this.textRetrieved$.on,\n onBeginSelection: this.beginSelection$.on,\n onEndSelection: this.endSelection$.on,\n getSelectedText: () => this.getSelectedText(),\n copyToClipboard: () => this.copyToClipboard(),\n enableForMode: (id: string) => this.enabledModes.add(id),\n isEnabledForMode: (id: string) => this.enabledModes.has(id),\n getState: () => this.state,\n };\n }\n\n /* ── geometry cache ───────────────────────────────────── */\n private getOrLoadGeometry(pageIdx: number): PdfTask<PdfPageGeometry> {\n const cached = this.state.geometry[pageIdx];\n if (cached) return PdfTaskHelper.resolve(cached);\n\n if (!this.coreState.core.document)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Doc Not Found' });\n const page = this.coreState.core.document.pages.find((p) => p.index === pageIdx)!;\n\n const task = this.engine.getPageGeometry(this.coreState.core.document, page);\n\n task.wait((geo) => {\n this.dispatch(cachePageGeometry(pageIdx, geo));\n }, ignore);\n\n return task;\n }\n\n /* ── selection state updates ───────────────────────────── */\n private beginSelection(page: number, index: number) {\n this.selecting = true;\n this.anchor = { page, index };\n this.dispatch(startSelection());\n this.beginSelection$.emit({ page, index });\n }\n\n private endSelection() {\n this.selecting = false;\n this.anchor = undefined;\n this.dispatch(endSelection());\n this.endSelection$.emit();\n }\n\n private clearSelection() {\n this.selecting = false;\n this.anchor = undefined;\n this.dispatch(clearSelection());\n this.selChange$.emit(null);\n }\n\n private updateSelection(page: number, index: number) {\n if (!this.selecting || !this.anchor) return;\n\n const a = this.anchor;\n const forward = page > a.page || (page === a.page && index >= a.index);\n\n const start = forward ? a : { page, index };\n const end = forward ? { page, index } : a;\n\n const range = { start, end };\n this.dispatch(setSelection(range));\n this.updateRectsAndSlices(range);\n this.selChange$.emit(range);\n }\n\n private updateRectsAndSlices(range: SelectionRangeX) {\n const allRects: Record<number, Rect[]> = {};\n const allSlices: Record<number, { start: number; count: number }> = {};\n\n for (let p = range.start.page; p <= range.end.page; p++) {\n const geo = this.state.geometry[p];\n const sb = sliceBounds(range, geo, p);\n if (!sb) continue;\n\n allRects[p] = rectsWithinSlice(geo!, sb.from, sb.to);\n allSlices[p] = { start: sb.from, count: sb.to - sb.from + 1 };\n }\n\n this.dispatch(setRects(allRects));\n this.dispatch(setSlices(allSlices));\n }\n\n private getSelectedText(): PdfTask<string[]> {\n if (!this.coreState.core.document || !this.state.selection) {\n return PdfTaskHelper.reject({\n code: PdfErrorCode.NotFound,\n message: 'Doc Not Found or No Selection',\n });\n }\n\n const sel = this.state.selection;\n const req: PageTextSlice[] = [];\n\n for (let p = sel.start.page; p <= sel.end.page; p++) {\n const s = this.state.slices[p];\n if (s) req.push({ pageIndex: p, charIndex: s.start, charCount: s.count });\n }\n\n if (req.length === 0) return PdfTaskHelper.resolve([] as string[]);\n\n const task = this.engine.getTextSlices(this.coreState.core.document, req);\n\n // Emit the text when it's retrieved\n task.wait((text) => {\n this.textRetrieved$.emit(text);\n }, ignore);\n\n return task;\n }\n\n private copyToClipboard() {\n const text = this.getSelectedText();\n text.wait((text) => {\n this.copyToClipboard$.emit(text.join('\\n'));\n }, ignore);\n }\n}\n","import { SelectionState } from './types';\nimport {\n SelectionAction,\n CACHE_PAGE_GEOMETRY,\n SET_SELECTION,\n START_SELECTION,\n END_SELECTION,\n CLEAR_SELECTION,\n RESET,\n SET_SLICES,\n SET_RECTS,\n} from './actions';\n\nexport const initialState: SelectionState = {\n geometry: {},\n rects: {},\n slices: {},\n selection: null,\n active: false,\n selecting: false,\n};\n\nexport const selectionReducer = (state = initialState, action: SelectionAction): SelectionState => {\n switch (action.type) {\n case CACHE_PAGE_GEOMETRY: {\n const { page, geo } = action.payload;\n return { ...state, geometry: { ...state.geometry, [page]: geo } };\n }\n case SET_SELECTION:\n return { ...state, selection: action.payload, active: true };\n case START_SELECTION:\n return { ...state, selecting: true, selection: null, rects: {} };\n case END_SELECTION:\n return { ...state, selecting: false };\n case CLEAR_SELECTION:\n return { ...state, selecting: false, selection: null, rects: {}, active: false };\n case SET_RECTS:\n return { ...state, rects: action.payload };\n case SET_SLICES:\n return { ...state, slices: action.payload };\n case RESET:\n return initialState;\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { manifest, SELECTION_PLUGIN_ID } from './manifest';\nimport { SelectionPluginConfig, SelectionState } from './types';\n\nimport { SelectionPlugin } from './selection-plugin';\nimport { SelectionAction } from './actions';\nimport { selectionReducer, initialState } from './reducer';\n\nexport const SelectionPluginPackage: PluginPackage<\n SelectionPlugin,\n SelectionPluginConfig,\n SelectionState,\n SelectionAction\n> = {\n manifest,\n create: (registry, engine) => new SelectionPlugin(SELECTION_PLUGIN_ID, registry, engine),\n reducer: selectionReducer,\n initialState,\n};\n\nexport * from './selection-plugin';\nexport * from './types';\nexport * from './manifest';\nexport * from './utils';\n"],"names":["boundingRect","selector.getFormattedSelection","selector.getFormattedSelectionForPage","selector.selectRectsForPage","selector.selectBoundingRectForPage","selector.selectBoundingRectsForAllPages","text"],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Action } from '@embedpdf/core';
|
|
2
|
+
import { PdfPageGeometry, Rect } from '@embedpdf/models';
|
|
3
|
+
import { SelectionRangeX } from './types';
|
|
4
|
+
export declare const CACHE_PAGE_GEOMETRY = "CACHE_PAGE_GEOMETRY";
|
|
5
|
+
export declare const SET_SELECTION = "SET_SELECTION";
|
|
6
|
+
export declare const START_SELECTION = "START_SELECTION";
|
|
7
|
+
export declare const END_SELECTION = "END_SELECTION";
|
|
8
|
+
export declare const CLEAR_SELECTION = "CLEAR_SELECTION";
|
|
9
|
+
export declare const SET_RECTS = "SET_RECTS";
|
|
10
|
+
export declare const SET_SLICES = "SET_SLICES";
|
|
11
|
+
export declare const RESET = "RESET";
|
|
12
|
+
export interface CachePageGeometryAction extends Action {
|
|
13
|
+
type: typeof CACHE_PAGE_GEOMETRY;
|
|
14
|
+
payload: {
|
|
15
|
+
page: number;
|
|
16
|
+
geo: PdfPageGeometry;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface SetSelectionAction extends Action {
|
|
20
|
+
type: typeof SET_SELECTION;
|
|
21
|
+
payload: SelectionRangeX | null;
|
|
22
|
+
}
|
|
23
|
+
export interface StartSelectionAction extends Action {
|
|
24
|
+
type: typeof START_SELECTION;
|
|
25
|
+
}
|
|
26
|
+
export interface EndSelectionAction extends Action {
|
|
27
|
+
type: typeof END_SELECTION;
|
|
28
|
+
}
|
|
29
|
+
export interface ClearSelectionAction extends Action {
|
|
30
|
+
type: typeof CLEAR_SELECTION;
|
|
31
|
+
}
|
|
32
|
+
export interface SetRectsAction extends Action {
|
|
33
|
+
type: typeof SET_RECTS;
|
|
34
|
+
payload: Record<number, Rect[]>;
|
|
35
|
+
}
|
|
36
|
+
export interface SetSlicesAction extends Action {
|
|
37
|
+
type: typeof SET_SLICES;
|
|
38
|
+
payload: Record<number, {
|
|
39
|
+
start: number;
|
|
40
|
+
count: number;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface ResetAction extends Action {
|
|
44
|
+
type: typeof RESET;
|
|
45
|
+
}
|
|
46
|
+
export type SelectionAction = CachePageGeometryAction | SetSelectionAction | StartSelectionAction | EndSelectionAction | ClearSelectionAction | SetRectsAction | SetSlicesAction | ResetAction;
|
|
47
|
+
export declare const cachePageGeometry: (page: number, geo: PdfPageGeometry) => CachePageGeometryAction;
|
|
48
|
+
export declare const setSelection: (sel: SelectionRangeX) => SetSelectionAction;
|
|
49
|
+
export declare const startSelection: () => StartSelectionAction;
|
|
50
|
+
export declare const endSelection: () => EndSelectionAction;
|
|
51
|
+
export declare const clearSelection: () => ClearSelectionAction;
|
|
52
|
+
export declare const setRects: (allRects: Record<number, Rect[]>) => SetRectsAction;
|
|
53
|
+
export declare const setSlices: (slices: Record<number, {
|
|
54
|
+
start: number;
|
|
55
|
+
count: number;
|
|
56
|
+
}>) => SetSlicesAction;
|
|
57
|
+
export declare const reset: () => ResetAction;
|
|
@@ -0,0 +1,9 @@
|
|
|
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';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BasePlugin, PluginRegistry } from '@embedpdf/core';
|
|
2
|
+
import { PdfEngine } from '@embedpdf/models';
|
|
3
|
+
import { SelectionAction } from './actions';
|
|
4
|
+
import { SelectionCapability, SelectionPluginConfig, SelectionState } from './types';
|
|
5
|
+
export declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, SelectionCapability, SelectionState, SelectionAction> {
|
|
6
|
+
private engine;
|
|
7
|
+
static readonly id: "selection";
|
|
8
|
+
/** Modes that should trigger text-selection logic */
|
|
9
|
+
private enabledModes;
|
|
10
|
+
private selecting;
|
|
11
|
+
private anchor?;
|
|
12
|
+
private readonly selChange$;
|
|
13
|
+
private readonly textRetrieved$;
|
|
14
|
+
private readonly copyToClipboard$;
|
|
15
|
+
private readonly beginSelection$;
|
|
16
|
+
private readonly endSelection$;
|
|
17
|
+
constructor(id: string, registry: PluginRegistry, engine: PdfEngine);
|
|
18
|
+
initialize(): Promise<void>;
|
|
19
|
+
destroy(): Promise<void>;
|
|
20
|
+
buildCapability(): SelectionCapability;
|
|
21
|
+
private getOrLoadGeometry;
|
|
22
|
+
private beginSelection;
|
|
23
|
+
private endSelection;
|
|
24
|
+
private clearSelection;
|
|
25
|
+
private updateSelection;
|
|
26
|
+
private updateRectsAndSlices;
|
|
27
|
+
private getSelectedText;
|
|
28
|
+
private copyToClipboard;
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Rect } from '@embedpdf/models';
|
|
2
|
+
import { FormattedSelection, SelectionState } from './types';
|
|
3
|
+
export declare function selectRectsForPage(state: SelectionState, page: number): Rect[];
|
|
4
|
+
export declare function selectBoundingRectForPage(state: SelectionState, page: number): Rect | null;
|
|
5
|
+
export declare function selectRectsAndBoundingRectForPage(state: SelectionState, page: number): {
|
|
6
|
+
rects: Rect[];
|
|
7
|
+
boundingRect: Rect | null;
|
|
8
|
+
};
|
|
9
|
+
export declare function selectBoundingRectsForAllPages(state: SelectionState): {
|
|
10
|
+
page: number;
|
|
11
|
+
rect: Rect;
|
|
12
|
+
}[];
|
|
13
|
+
export declare function getFormattedSelectionForPage(state: SelectionState, page: number): FormattedSelection | null;
|
|
14
|
+
export declare function getFormattedSelection(state: SelectionState): FormattedSelection[];
|