@embedpdf/plugin-selection 1.0.6 → 1.0.8
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 +46 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +52 -2
- package/dist/index.js.map +1 -1
- package/dist/preact/index.cjs +63 -16
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.d.cts +4 -2
- package/dist/preact/index.d.ts +4 -2
- package/dist/preact/index.js +68 -18
- package/dist/preact/index.js.map +1 -1
- package/dist/react/index.cjs +63 -16
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +4 -2
- package/dist/react/index.d.ts +4 -2
- package/dist/react/index.js +68 -18
- package/dist/react/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -99,6 +99,30 @@ function selectBoundingRectsForAllPages(state) {
|
|
|
99
99
|
}
|
|
100
100
|
return out;
|
|
101
101
|
}
|
|
102
|
+
function getFormattedSelectionForPage(state, page) {
|
|
103
|
+
const segmentRects = state.rects[page] || [];
|
|
104
|
+
if (segmentRects.length === 0) return null;
|
|
105
|
+
const boundingRect2 = selectBoundingRectForPage(state, page);
|
|
106
|
+
if (!boundingRect2) return null;
|
|
107
|
+
return { pageIndex: page, rect: boundingRect2, segmentRects };
|
|
108
|
+
}
|
|
109
|
+
function getFormattedSelection(state) {
|
|
110
|
+
const result = [];
|
|
111
|
+
const pages = Object.keys(state.rects).map(Number);
|
|
112
|
+
for (const pageIndex of pages) {
|
|
113
|
+
const segmentRects = state.rects[pageIndex] || [];
|
|
114
|
+
if (segmentRects.length === 0) continue;
|
|
115
|
+
const boundingRect2 = selectBoundingRectForPage(state, pageIndex);
|
|
116
|
+
if (boundingRect2) {
|
|
117
|
+
result.push({
|
|
118
|
+
pageIndex,
|
|
119
|
+
rect: boundingRect2,
|
|
120
|
+
segmentRects
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
102
126
|
|
|
103
127
|
// src/lib/utils.ts
|
|
104
128
|
function glyphAt(geo, pt) {
|
|
@@ -236,10 +260,15 @@ var SelectionPlugin = class extends import_core.BasePlugin {
|
|
|
236
260
|
constructor(id, registry, engine) {
|
|
237
261
|
super(id, registry);
|
|
238
262
|
this.engine = engine;
|
|
263
|
+
/** Modes that should trigger text-selection logic */
|
|
264
|
+
this.enabledModes = /* @__PURE__ */ new Set(["default"]);
|
|
239
265
|
/* interactive state */
|
|
240
266
|
this.selecting = false;
|
|
241
267
|
this.selChange$ = (0, import_core.createBehaviorEmitter)();
|
|
242
268
|
this.textRetrieved$ = (0, import_core.createBehaviorEmitter)();
|
|
269
|
+
this.copyToClipboard$ = (0, import_core.createEmitter)();
|
|
270
|
+
this.beginSelection$ = (0, import_core.createEmitter)();
|
|
271
|
+
this.endSelection$ = (0, import_core.createEmitter)();
|
|
243
272
|
this.coreStore.onAction(import_core.SET_DOCUMENT, (_action, state) => {
|
|
244
273
|
this.dispatch(reset());
|
|
245
274
|
this.doc = state.core.document ?? void 0;
|
|
@@ -255,6 +284,8 @@ var SelectionPlugin = class extends import_core.BasePlugin {
|
|
|
255
284
|
buildCapability() {
|
|
256
285
|
return {
|
|
257
286
|
getGeometry: (p) => this.getOrLoadGeometry(p),
|
|
287
|
+
getFormattedSelection: () => getFormattedSelection(this.state),
|
|
288
|
+
getFormattedSelectionForPage: (p) => getFormattedSelectionForPage(this.state, p),
|
|
258
289
|
getHighlightRectsForPage: (p) => selectRectsForPage(this.state, p),
|
|
259
290
|
getHighlightRects: () => this.state.rects,
|
|
260
291
|
getBoundingRectForPage: (p) => selectBoundingRectForPage(this.state, p),
|
|
@@ -263,9 +294,15 @@ var SelectionPlugin = class extends import_core.BasePlugin {
|
|
|
263
294
|
update: (p, i) => this.updateSelection(p, i),
|
|
264
295
|
end: () => this.endSelection(),
|
|
265
296
|
clear: () => this.clearSelection(),
|
|
297
|
+
onCopyToClipboard: this.copyToClipboard$.on,
|
|
266
298
|
onSelectionChange: this.selChange$.on,
|
|
267
299
|
onTextRetrieved: this.textRetrieved$.on,
|
|
268
|
-
|
|
300
|
+
onBeginSelection: this.beginSelection$.on,
|
|
301
|
+
onEndSelection: this.endSelection$.on,
|
|
302
|
+
getSelectedText: () => this.getSelectedText(),
|
|
303
|
+
copyToClipboard: () => this.copyToClipboard(),
|
|
304
|
+
enableForMode: (id) => this.enabledModes.add(id),
|
|
305
|
+
isEnabledForMode: (id) => this.enabledModes.has(id)
|
|
269
306
|
};
|
|
270
307
|
}
|
|
271
308
|
/* ── geometry cache ───────────────────────────────────── */
|
|
@@ -286,11 +323,13 @@ var SelectionPlugin = class extends import_core.BasePlugin {
|
|
|
286
323
|
this.selecting = true;
|
|
287
324
|
this.anchor = { page, index };
|
|
288
325
|
this.dispatch(startSelection());
|
|
326
|
+
this.beginSelection$.emit({ page, index });
|
|
289
327
|
}
|
|
290
328
|
endSelection() {
|
|
291
329
|
this.selecting = false;
|
|
292
330
|
this.anchor = void 0;
|
|
293
331
|
this.dispatch(endSelection());
|
|
332
|
+
this.endSelection$.emit();
|
|
294
333
|
}
|
|
295
334
|
clearSelection() {
|
|
296
335
|
this.selecting = false;
|
|
@@ -342,6 +381,12 @@ var SelectionPlugin = class extends import_core.BasePlugin {
|
|
|
342
381
|
}, import_models2.ignore);
|
|
343
382
|
return task;
|
|
344
383
|
}
|
|
384
|
+
copyToClipboard() {
|
|
385
|
+
const text = this.getSelectedText();
|
|
386
|
+
text.wait((text2) => {
|
|
387
|
+
this.copyToClipboard$.emit(text2.join("\n"));
|
|
388
|
+
}, import_models2.ignore);
|
|
389
|
+
}
|
|
345
390
|
};
|
|
346
391
|
SelectionPlugin.id = "selection";
|
|
347
392
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../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":["export * from './lib';\n","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 { BasePlugin, PluginRegistry, SET_DOCUMENT, createBehaviorEmitter } from '@embedpdf/core';\nimport {\n PdfEngine,\n PdfDocumentObject,\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 private doc?: PdfDocumentObject;\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\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, state) => {\n this.dispatch(reset());\n this.doc = state.core.document ?? undefined;\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 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\n onSelectionChange: this.selChange$.on,\n onTextRetrieved: this.textRetrieved$.on,\n getSelectedText: () => this.getSelectedText(),\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.doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Doc Not Found' });\n const page = this.doc.pages.find((p) => p.index === pageIdx)!;\n\n const task = this.engine.getPageGeometry(this.doc!, 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 }\n\n private endSelection() {\n this.selecting = false;\n this.anchor = undefined;\n this.dispatch(endSelection());\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.doc || !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.doc!, 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","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 { 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 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","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":["import_models"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../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":["export * from './lib';\n","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 PdfDocumentObject,\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 private doc?: PdfDocumentObject;\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, state) => {\n this.dispatch(reset());\n this.doc = state.core.document ?? undefined;\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 };\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.doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Doc Not Found' });\n const page = this.doc.pages.find((p) => p.index === pageIdx)!;\n\n const task = this.engine.getPageGeometry(this.doc!, 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.doc || !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.doc!, 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":["import_models","boundingRect","text"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -24,8 +24,15 @@ interface SelectionState {
|
|
|
24
24
|
active: boolean;
|
|
25
25
|
selecting: boolean;
|
|
26
26
|
}
|
|
27
|
+
interface FormattedSelection {
|
|
28
|
+
pageIndex: number;
|
|
29
|
+
rect: Rect;
|
|
30
|
+
segmentRects: Rect[];
|
|
31
|
+
}
|
|
27
32
|
interface SelectionCapability {
|
|
28
33
|
getGeometry(page: number): PdfTask<PdfPageGeometry>;
|
|
34
|
+
getFormattedSelection(): FormattedSelection[];
|
|
35
|
+
getFormattedSelectionForPage(page: number): FormattedSelection | null;
|
|
29
36
|
getHighlightRectsForPage(page: number): Rect[];
|
|
30
37
|
getHighlightRects(): Record<number, Rect[]>;
|
|
31
38
|
getBoundingRectForPage(page: number): Rect | null;
|
|
@@ -34,12 +41,24 @@ interface SelectionCapability {
|
|
|
34
41
|
rect: Rect;
|
|
35
42
|
}[];
|
|
36
43
|
getSelectedText(): PdfTask<string[]>;
|
|
44
|
+
copyToClipboard(): void;
|
|
37
45
|
begin(page: number, glyphIdx: number): void;
|
|
38
46
|
update(page: number, glyphIdx: number): void;
|
|
39
47
|
end(): void;
|
|
40
48
|
clear(): void;
|
|
41
49
|
onSelectionChange: EventHook<SelectionRangeX | null>;
|
|
42
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;
|
|
43
62
|
}
|
|
44
63
|
|
|
45
64
|
declare const CACHE_PAGE_GEOMETRY = "CACHE_PAGE_GEOMETRY";
|
|
@@ -90,10 +109,15 @@ declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, Selectio
|
|
|
90
109
|
private engine;
|
|
91
110
|
static readonly id: "selection";
|
|
92
111
|
private doc?;
|
|
112
|
+
/** Modes that should trigger text-selection logic */
|
|
113
|
+
private enabledModes;
|
|
93
114
|
private selecting;
|
|
94
115
|
private anchor?;
|
|
95
116
|
private readonly selChange$;
|
|
96
117
|
private readonly textRetrieved$;
|
|
118
|
+
private readonly copyToClipboard$;
|
|
119
|
+
private readonly beginSelection$;
|
|
120
|
+
private readonly endSelection$;
|
|
97
121
|
constructor(id: string, registry: PluginRegistry, engine: PdfEngine);
|
|
98
122
|
initialize(): Promise<void>;
|
|
99
123
|
destroy(): Promise<void>;
|
|
@@ -105,6 +129,7 @@ declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, Selectio
|
|
|
105
129
|
private updateSelection;
|
|
106
130
|
private updateRectsAndSlices;
|
|
107
131
|
private getSelectedText;
|
|
132
|
+
private copyToClipboard;
|
|
108
133
|
}
|
|
109
134
|
|
|
110
135
|
declare const SELECTION_PLUGIN_ID = "selection";
|
|
@@ -184,4 +209,4 @@ declare function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[];
|
|
|
184
209
|
|
|
185
210
|
declare const SelectionPluginPackage: PluginPackage<SelectionPlugin, SelectionPluginConfig, SelectionState, SelectionAction>;
|
|
186
211
|
|
|
187
|
-
export { 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 };
|
|
212
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -24,8 +24,15 @@ interface SelectionState {
|
|
|
24
24
|
active: boolean;
|
|
25
25
|
selecting: boolean;
|
|
26
26
|
}
|
|
27
|
+
interface FormattedSelection {
|
|
28
|
+
pageIndex: number;
|
|
29
|
+
rect: Rect;
|
|
30
|
+
segmentRects: Rect[];
|
|
31
|
+
}
|
|
27
32
|
interface SelectionCapability {
|
|
28
33
|
getGeometry(page: number): PdfTask<PdfPageGeometry>;
|
|
34
|
+
getFormattedSelection(): FormattedSelection[];
|
|
35
|
+
getFormattedSelectionForPage(page: number): FormattedSelection | null;
|
|
29
36
|
getHighlightRectsForPage(page: number): Rect[];
|
|
30
37
|
getHighlightRects(): Record<number, Rect[]>;
|
|
31
38
|
getBoundingRectForPage(page: number): Rect | null;
|
|
@@ -34,12 +41,24 @@ interface SelectionCapability {
|
|
|
34
41
|
rect: Rect;
|
|
35
42
|
}[];
|
|
36
43
|
getSelectedText(): PdfTask<string[]>;
|
|
44
|
+
copyToClipboard(): void;
|
|
37
45
|
begin(page: number, glyphIdx: number): void;
|
|
38
46
|
update(page: number, glyphIdx: number): void;
|
|
39
47
|
end(): void;
|
|
40
48
|
clear(): void;
|
|
41
49
|
onSelectionChange: EventHook<SelectionRangeX | null>;
|
|
42
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;
|
|
43
62
|
}
|
|
44
63
|
|
|
45
64
|
declare const CACHE_PAGE_GEOMETRY = "CACHE_PAGE_GEOMETRY";
|
|
@@ -90,10 +109,15 @@ declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, Selectio
|
|
|
90
109
|
private engine;
|
|
91
110
|
static readonly id: "selection";
|
|
92
111
|
private doc?;
|
|
112
|
+
/** Modes that should trigger text-selection logic */
|
|
113
|
+
private enabledModes;
|
|
93
114
|
private selecting;
|
|
94
115
|
private anchor?;
|
|
95
116
|
private readonly selChange$;
|
|
96
117
|
private readonly textRetrieved$;
|
|
118
|
+
private readonly copyToClipboard$;
|
|
119
|
+
private readonly beginSelection$;
|
|
120
|
+
private readonly endSelection$;
|
|
97
121
|
constructor(id: string, registry: PluginRegistry, engine: PdfEngine);
|
|
98
122
|
initialize(): Promise<void>;
|
|
99
123
|
destroy(): Promise<void>;
|
|
@@ -105,6 +129,7 @@ declare class SelectionPlugin extends BasePlugin<SelectionPluginConfig, Selectio
|
|
|
105
129
|
private updateSelection;
|
|
106
130
|
private updateRectsAndSlices;
|
|
107
131
|
private getSelectedText;
|
|
132
|
+
private copyToClipboard;
|
|
108
133
|
}
|
|
109
134
|
|
|
110
135
|
declare const SELECTION_PLUGIN_ID = "selection";
|
|
@@ -184,4 +209,4 @@ declare function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[];
|
|
|
184
209
|
|
|
185
210
|
declare const SelectionPluginPackage: PluginPackage<SelectionPlugin, SelectionPluginConfig, SelectionState, SelectionAction>;
|
|
186
211
|
|
|
187
|
-
export { 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 };
|
|
212
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,12 @@ var manifest = {
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
// src/lib/selection-plugin.ts
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
BasePlugin,
|
|
18
|
+
SET_DOCUMENT,
|
|
19
|
+
createBehaviorEmitter,
|
|
20
|
+
createEmitter
|
|
21
|
+
} from "@embedpdf/core";
|
|
17
22
|
import {
|
|
18
23
|
PdfTaskHelper,
|
|
19
24
|
PdfErrorCode,
|
|
@@ -65,6 +70,30 @@ function selectBoundingRectsForAllPages(state) {
|
|
|
65
70
|
}
|
|
66
71
|
return out;
|
|
67
72
|
}
|
|
73
|
+
function getFormattedSelectionForPage(state, page) {
|
|
74
|
+
const segmentRects = state.rects[page] || [];
|
|
75
|
+
if (segmentRects.length === 0) return null;
|
|
76
|
+
const boundingRect2 = selectBoundingRectForPage(state, page);
|
|
77
|
+
if (!boundingRect2) return null;
|
|
78
|
+
return { pageIndex: page, rect: boundingRect2, segmentRects };
|
|
79
|
+
}
|
|
80
|
+
function getFormattedSelection(state) {
|
|
81
|
+
const result = [];
|
|
82
|
+
const pages = Object.keys(state.rects).map(Number);
|
|
83
|
+
for (const pageIndex of pages) {
|
|
84
|
+
const segmentRects = state.rects[pageIndex] || [];
|
|
85
|
+
if (segmentRects.length === 0) continue;
|
|
86
|
+
const boundingRect2 = selectBoundingRectForPage(state, pageIndex);
|
|
87
|
+
if (boundingRect2) {
|
|
88
|
+
result.push({
|
|
89
|
+
pageIndex,
|
|
90
|
+
rect: boundingRect2,
|
|
91
|
+
segmentRects
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
68
97
|
|
|
69
98
|
// src/lib/utils.ts
|
|
70
99
|
function glyphAt(geo, pt) {
|
|
@@ -202,10 +231,15 @@ var SelectionPlugin = class extends BasePlugin {
|
|
|
202
231
|
constructor(id, registry, engine) {
|
|
203
232
|
super(id, registry);
|
|
204
233
|
this.engine = engine;
|
|
234
|
+
/** Modes that should trigger text-selection logic */
|
|
235
|
+
this.enabledModes = /* @__PURE__ */ new Set(["default"]);
|
|
205
236
|
/* interactive state */
|
|
206
237
|
this.selecting = false;
|
|
207
238
|
this.selChange$ = createBehaviorEmitter();
|
|
208
239
|
this.textRetrieved$ = createBehaviorEmitter();
|
|
240
|
+
this.copyToClipboard$ = createEmitter();
|
|
241
|
+
this.beginSelection$ = createEmitter();
|
|
242
|
+
this.endSelection$ = createEmitter();
|
|
209
243
|
this.coreStore.onAction(SET_DOCUMENT, (_action, state) => {
|
|
210
244
|
this.dispatch(reset());
|
|
211
245
|
this.doc = state.core.document ?? void 0;
|
|
@@ -221,6 +255,8 @@ var SelectionPlugin = class extends BasePlugin {
|
|
|
221
255
|
buildCapability() {
|
|
222
256
|
return {
|
|
223
257
|
getGeometry: (p) => this.getOrLoadGeometry(p),
|
|
258
|
+
getFormattedSelection: () => getFormattedSelection(this.state),
|
|
259
|
+
getFormattedSelectionForPage: (p) => getFormattedSelectionForPage(this.state, p),
|
|
224
260
|
getHighlightRectsForPage: (p) => selectRectsForPage(this.state, p),
|
|
225
261
|
getHighlightRects: () => this.state.rects,
|
|
226
262
|
getBoundingRectForPage: (p) => selectBoundingRectForPage(this.state, p),
|
|
@@ -229,9 +265,15 @@ var SelectionPlugin = class extends BasePlugin {
|
|
|
229
265
|
update: (p, i) => this.updateSelection(p, i),
|
|
230
266
|
end: () => this.endSelection(),
|
|
231
267
|
clear: () => this.clearSelection(),
|
|
268
|
+
onCopyToClipboard: this.copyToClipboard$.on,
|
|
232
269
|
onSelectionChange: this.selChange$.on,
|
|
233
270
|
onTextRetrieved: this.textRetrieved$.on,
|
|
234
|
-
|
|
271
|
+
onBeginSelection: this.beginSelection$.on,
|
|
272
|
+
onEndSelection: this.endSelection$.on,
|
|
273
|
+
getSelectedText: () => this.getSelectedText(),
|
|
274
|
+
copyToClipboard: () => this.copyToClipboard(),
|
|
275
|
+
enableForMode: (id) => this.enabledModes.add(id),
|
|
276
|
+
isEnabledForMode: (id) => this.enabledModes.has(id)
|
|
235
277
|
};
|
|
236
278
|
}
|
|
237
279
|
/* ── geometry cache ───────────────────────────────────── */
|
|
@@ -252,11 +294,13 @@ var SelectionPlugin = class extends BasePlugin {
|
|
|
252
294
|
this.selecting = true;
|
|
253
295
|
this.anchor = { page, index };
|
|
254
296
|
this.dispatch(startSelection());
|
|
297
|
+
this.beginSelection$.emit({ page, index });
|
|
255
298
|
}
|
|
256
299
|
endSelection() {
|
|
257
300
|
this.selecting = false;
|
|
258
301
|
this.anchor = void 0;
|
|
259
302
|
this.dispatch(endSelection());
|
|
303
|
+
this.endSelection$.emit();
|
|
260
304
|
}
|
|
261
305
|
clearSelection() {
|
|
262
306
|
this.selecting = false;
|
|
@@ -308,6 +352,12 @@ var SelectionPlugin = class extends BasePlugin {
|
|
|
308
352
|
}, ignore);
|
|
309
353
|
return task;
|
|
310
354
|
}
|
|
355
|
+
copyToClipboard() {
|
|
356
|
+
const text = this.getSelectedText();
|
|
357
|
+
text.wait((text2) => {
|
|
358
|
+
this.copyToClipboard$.emit(text2.join("\n"));
|
|
359
|
+
}, ignore);
|
|
360
|
+
}
|
|
311
361
|
};
|
|
312
362
|
SelectionPlugin.id = "selection";
|
|
313
363
|
|