@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.
Files changed (55) hide show
  1. package/dist/index.cjs +2 -450
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +1 -213
  4. package/dist/index.js +27 -53
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/actions.d.ts +57 -0
  7. package/dist/lib/index.d.ts +9 -0
  8. package/dist/lib/manifest.d.ts +4 -0
  9. package/dist/lib/reducer.d.ts +4 -0
  10. package/dist/lib/selection-plugin.d.ts +29 -0
  11. package/dist/lib/selectors.d.ts +14 -0
  12. package/dist/lib/types.d.ts +63 -0
  13. package/dist/lib/utils.d.ts +70 -0
  14. package/dist/preact/adapter.d.ts +4 -0
  15. package/dist/preact/core.d.ts +1 -0
  16. package/dist/preact/index.cjs +2 -169
  17. package/dist/preact/index.cjs.map +1 -1
  18. package/dist/preact/index.d.ts +1 -25
  19. package/dist/preact/index.js +15 -24
  20. package/dist/preact/index.js.map +1 -1
  21. package/dist/preact/interaction-manager.d.ts +1 -0
  22. package/dist/react/adapter.d.ts +2 -0
  23. package/dist/react/core.d.ts +1 -0
  24. package/dist/react/index.cjs +2 -169
  25. package/dist/react/index.cjs.map +1 -1
  26. package/dist/react/index.d.ts +1 -25
  27. package/dist/react/index.js +14 -24
  28. package/dist/react/index.js.map +1 -1
  29. package/dist/react/interaction-manager.d.ts +1 -0
  30. package/dist/shared-preact/components/copy-to-clipboard.d.ts +1 -0
  31. package/dist/shared-preact/components/index.d.ts +2 -0
  32. package/dist/shared-preact/components/selection-layer.d.ts +7 -0
  33. package/dist/shared-preact/hooks/index.d.ts +1 -0
  34. package/dist/shared-preact/hooks/use-selection.d.ts +11 -0
  35. package/dist/shared-preact/index.d.ts +2 -0
  36. package/dist/shared-react/components/copy-to-clipboard.d.ts +1 -0
  37. package/dist/shared-react/components/index.d.ts +2 -0
  38. package/dist/shared-react/components/selection-layer.d.ts +7 -0
  39. package/dist/shared-react/hooks/index.d.ts +1 -0
  40. package/dist/shared-react/hooks/use-selection.d.ts +11 -0
  41. package/dist/shared-react/index.d.ts +2 -0
  42. package/dist/vue/components/copy-to-clipboard.vue.d.ts +2 -0
  43. package/dist/vue/components/index.d.ts +2 -0
  44. package/dist/vue/components/selection-layer.vue.d.ts +9 -0
  45. package/dist/vue/hooks/index.d.ts +1 -0
  46. package/dist/vue/hooks/use-selection.d.ts +11 -0
  47. package/dist/vue/index.cjs +2 -0
  48. package/dist/vue/index.cjs.map +1 -0
  49. package/dist/vue/index.d.ts +2 -0
  50. package/dist/vue/index.js +145 -0
  51. package/dist/vue/index.js.map +1 -0
  52. package/package.json +23 -14
  53. package/dist/index.d.cts +0 -213
  54. package/dist/preact/index.d.cts +0 -25
  55. package/dist/react/index.d.cts +0 -25
@@ -0,0 +1,63 @@
1
+ import { BasePluginConfig, EventHook } from '@embedpdf/core';
2
+ import { PdfPageGeometry, PdfTask, Rect } from '@embedpdf/models';
3
+ export interface SelectionPluginConfig extends BasePluginConfig {
4
+ }
5
+ export interface GlyphPointer {
6
+ page: number;
7
+ index: number;
8
+ }
9
+ export interface SelectionRangeX {
10
+ start: GlyphPointer;
11
+ end: GlyphPointer;
12
+ }
13
+ export interface SelectionState {
14
+ /** page → geometry cache */
15
+ geometry: Record<number, PdfPageGeometry>;
16
+ /** current selection or null */
17
+ rects: Record<number, Rect[]>;
18
+ selection: SelectionRangeX | null;
19
+ slices: Record<number, {
20
+ start: number;
21
+ count: number;
22
+ }>;
23
+ active: boolean;
24
+ selecting: boolean;
25
+ }
26
+ export interface FormattedSelection {
27
+ pageIndex: number;
28
+ rect: Rect;
29
+ segmentRects: Rect[];
30
+ }
31
+ export interface SelectionCapability {
32
+ getGeometry(page: number): PdfTask<PdfPageGeometry>;
33
+ getFormattedSelection(): FormattedSelection[];
34
+ getFormattedSelectionForPage(page: number): FormattedSelection | null;
35
+ getHighlightRectsForPage(page: number): Rect[];
36
+ getHighlightRects(): Record<number, Rect[]>;
37
+ getBoundingRectForPage(page: number): Rect | null;
38
+ getBoundingRects(): {
39
+ page: number;
40
+ rect: Rect;
41
+ }[];
42
+ getSelectedText(): PdfTask<string[]>;
43
+ copyToClipboard(): void;
44
+ begin(page: number, glyphIdx: number): void;
45
+ update(page: number, glyphIdx: number): void;
46
+ end(): void;
47
+ clear(): void;
48
+ onSelectionChange: EventHook<SelectionRangeX | null>;
49
+ onTextRetrieved: EventHook<string[]>;
50
+ onCopyToClipboard: EventHook<string>;
51
+ onBeginSelection: EventHook<{
52
+ page: number;
53
+ index: number;
54
+ }>;
55
+ onEndSelection: EventHook<void>;
56
+ /** Tell the selection plugin that text selection should stay
57
+ enabled while <modeId> is active. */
58
+ enableForMode(modeId: string): void;
59
+ /** Quick check used by SelectionLayer during pointer events. */
60
+ isEnabledForMode(modeId: string): boolean;
61
+ /** Get the current state of the selection plugin. */
62
+ getState(): SelectionState;
63
+ }
@@ -0,0 +1,70 @@
1
+ import { PdfPageGeometry, Position, Rect } from '@embedpdf/models';
2
+ import { SelectionRangeX } from './types';
3
+ /**
4
+ * Hit-test helper using runs
5
+ * @param geo - page geometry
6
+ * @param pt - point
7
+ * @returns glyph index
8
+ */
9
+ export declare function glyphAt(geo: PdfPageGeometry, pt: Position): number;
10
+ /**
11
+ * Helper: min/max glyph indices on `page` for current sel
12
+ * @param sel - selection range
13
+ * @param geo - page geometry
14
+ * @param page - page index
15
+ * @returns { from: number; to: number } | null
16
+ */
17
+ export declare function sliceBounds(sel: SelectionRangeX | null, geo: PdfPageGeometry | undefined, page: number): {
18
+ from: number;
19
+ to: number;
20
+ } | null;
21
+ /**
22
+ * Helper: build rects for a slice of the page
23
+ * @param geo - page geometry
24
+ * @param from - from index
25
+ * @param to - to index
26
+ * @param merge - whether to merge adjacent rects (default: true)
27
+ * @returns rects
28
+ */
29
+ export declare function rectsWithinSlice(geo: PdfPageGeometry, from: number, to: number, merge?: boolean): Rect[];
30
+ /**
31
+ * ============================================================================
32
+ * Rectangle Merging Algorithm
33
+ * ============================================================================
34
+ *
35
+ * The following code is adapted from Chromium's PDF text selection implementation.
36
+ *
37
+ * Copyright 2010 The Chromium Authors
38
+ * Use of this source code is governed by a BSD-style license that can be
39
+ * found in the LICENSE file: https://source.chromium.org/chromium/chromium/src/+/main:LICENSE
40
+ *
41
+ * Original source:
42
+ * https://source.chromium.org/chromium/chromium/src/+/main:pdf/pdfium/pdfium_range.cc
43
+ *
44
+ * Adapted for TypeScript and this project's Rect/geometry types.
45
+ */
46
+ /**
47
+ * Text run info for rect merging (similar to Chromium's ScreenRectTextRunInfo)
48
+ */
49
+ export interface TextRunInfo {
50
+ rect: Rect;
51
+ charCount: number;
52
+ }
53
+ /**
54
+ * Helper functions for Rect operations
55
+ */
56
+ export declare function rectUnion(rect1: Rect, rect2: Rect): Rect;
57
+ export declare function rectIntersect(rect1: Rect, rect2: Rect): Rect;
58
+ export declare function rectIsEmpty(rect: Rect): boolean;
59
+ /**
60
+ * Returns a ratio between [0, 1] representing vertical overlap
61
+ */
62
+ export declare function getVerticalOverlap(rect1: Rect, rect2: Rect): number;
63
+ /**
64
+ * Returns true if there is sufficient horizontal and vertical overlap
65
+ */
66
+ export declare function shouldMergeHorizontalRects(textRun1: TextRunInfo, textRun2: TextRunInfo): boolean;
67
+ /**
68
+ * Merge adjacent rectangles based on proximity and overlap (similar to Chromium's algorithm)
69
+ */
70
+ export declare function mergeAdjacentRects(textRuns: TextRunInfo[]): Rect[];
@@ -0,0 +1,4 @@
1
+ export { Fragment } from 'preact';
2
+ export { useEffect, useRef, useState, useCallback, useMemo } from 'preact/hooks';
3
+ export type { ComponentChildren as ReactNode } from 'preact';
4
+ export type HTMLAttributes<T = any> = import('preact').JSX.HTMLAttributes<T extends EventTarget ? T : never>;
@@ -0,0 +1 @@
1
+ export * from '@embedpdf/core/preact';
@@ -1,169 +1,2 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/preact/index.ts
21
- var preact_exports = {};
22
- __export(preact_exports, {
23
- CopyToClipboard: () => CopyToClipboard,
24
- SelectionLayer: () => SelectionLayer,
25
- useSelectionCapability: () => useSelectionCapability,
26
- useSelectionPlugin: () => useSelectionPlugin
27
- });
28
- module.exports = __toCommonJS(preact_exports);
29
-
30
- // src/preact/hooks/use-selection.ts
31
- var import_preact = require("@embedpdf/core/preact");
32
- var import_plugin_selection = require("@embedpdf/plugin-selection");
33
- var useSelectionCapability = () => (0, import_preact.useCapability)(import_plugin_selection.SelectionPlugin.id);
34
- var useSelectionPlugin = () => (0, import_preact.usePlugin)(import_plugin_selection.SelectionPlugin.id);
35
-
36
- // src/preact/components/selection-layer.tsx
37
- var import_hooks = require("preact/hooks");
38
- var import_models = require("@embedpdf/models");
39
- var import_preact2 = require("@embedpdf/plugin-interaction-manager/preact");
40
- var import_plugin_selection2 = require("@embedpdf/plugin-selection");
41
- var import_jsx_runtime = require("preact/jsx-runtime");
42
- function SelectionLayer({ pageIndex, scale, background = "rgba(33,150,243)" }) {
43
- const { provides: sel } = useSelectionCapability();
44
- const { provides: im } = (0, import_preact2.useInteractionManagerCapability)();
45
- const { register } = (0, import_preact2.usePointerHandlers)({ pageIndex });
46
- const [rects, setRects] = (0, import_hooks.useState)([]);
47
- const [boundingRect, setBoundingRect] = (0, import_hooks.useState)(null);
48
- const { setCursor, removeCursor } = (0, import_preact2.useCursor)();
49
- (0, import_hooks.useEffect)(() => {
50
- if (!sel) return;
51
- return sel.onSelectionChange(() => {
52
- const mode = im?.getActiveMode();
53
- if (mode === "default") {
54
- setRects(sel.getHighlightRectsForPage(pageIndex));
55
- setBoundingRect(sel.getBoundingRectForPage(pageIndex));
56
- } else {
57
- setRects([]);
58
- setBoundingRect(null);
59
- }
60
- });
61
- }, [sel, pageIndex]);
62
- let geoCache;
63
- const cachedGlyphAt = (0, import_hooks.useCallback)((pt) => {
64
- if (!geoCache) return -1;
65
- return (0, import_plugin_selection2.glyphAt)(geoCache, pt);
66
- }, []);
67
- (0, import_hooks.useEffect)(() => {
68
- if (!sel) return;
69
- const task = sel.getGeometry(pageIndex);
70
- task.wait((g) => geoCache = g, import_models.ignore);
71
- return () => {
72
- task.abort({
73
- code: import_models.PdfErrorCode.Cancelled,
74
- message: "Cancelled"
75
- });
76
- };
77
- }, [sel, pageIndex]);
78
- const handlers = (0, import_hooks.useMemo)(
79
- () => ({
80
- onPointerDown: (point, _evt, modeId) => {
81
- if (!sel) return;
82
- if (!sel.isEnabledForMode(modeId)) return;
83
- sel.clear();
84
- const task = sel.getGeometry(pageIndex);
85
- task.wait((geo) => {
86
- const g = (0, import_plugin_selection2.glyphAt)(geo, point);
87
- if (g !== -1) sel.begin(pageIndex, g);
88
- }, import_models.ignore);
89
- },
90
- onPointerMove: (point, _evt, modeId) => {
91
- if (!sel) return;
92
- if (!sel.isEnabledForMode(modeId)) return;
93
- const g = cachedGlyphAt(point);
94
- if (g !== -1) {
95
- setCursor("selection-text", "text", 10);
96
- } else {
97
- removeCursor("selection-text");
98
- }
99
- if (g !== -1) sel.update(pageIndex, g);
100
- },
101
- onPointerUp: (_point, _evt, modeId) => {
102
- if (!sel) return;
103
- if (!sel.isEnabledForMode(modeId)) return;
104
- sel.end();
105
- },
106
- onHandlerActiveEnd(modeId) {
107
- if (!sel) return;
108
- if (!sel.isEnabledForMode(modeId)) return;
109
- sel.clear();
110
- }
111
- }),
112
- [sel, pageIndex, cachedGlyphAt]
113
- );
114
- (0, import_hooks.useEffect)(() => {
115
- if (!register) return;
116
- return register(handlers);
117
- }, [register, handlers]);
118
- if (!boundingRect) return null;
119
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
120
- "div",
121
- {
122
- style: {
123
- position: "absolute",
124
- left: boundingRect.origin.x * scale,
125
- top: boundingRect.origin.y * scale,
126
- width: boundingRect.size.width * scale,
127
- height: boundingRect.size.height * scale,
128
- mixBlendMode: "multiply",
129
- isolation: "isolate"
130
- },
131
- children: rects.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
132
- "div",
133
- {
134
- style: {
135
- position: "absolute",
136
- left: (b.origin.x - boundingRect.origin.x) * scale,
137
- top: (b.origin.y - boundingRect.origin.y) * scale,
138
- width: b.size.width * scale,
139
- height: b.size.height * scale,
140
- background,
141
- pointerEvents: "none"
142
- }
143
- },
144
- i
145
- ))
146
- }
147
- );
148
- }
149
-
150
- // src/preact/components/copy-to-clipboard.tsx
151
- var import_hooks3 = require("preact/hooks");
152
- function CopyToClipboard() {
153
- const { provides: sel } = useSelectionCapability();
154
- (0, import_hooks3.useEffect)(() => {
155
- if (!sel) return;
156
- return sel.onCopyToClipboard((text) => {
157
- navigator.clipboard.writeText(text);
158
- });
159
- }, [sel]);
160
- return null;
161
- }
162
- // Annotate the CommonJS export names for ESM import in node:
163
- 0 && (module.exports = {
164
- CopyToClipboard,
165
- SelectionLayer,
166
- useSelectionCapability,
167
- useSelectionPlugin
168
- });
169
- //# sourceMappingURL=index.cjs.map
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-selection"),r=require("preact/jsx-runtime");require("preact");const i=require("preact/hooks"),n=require("@embedpdf/models"),o=require("@embedpdf/plugin-interaction-manager/preact"),s=()=>e.useCapability(t.SelectionPlugin.id);exports.CopyToClipboard=function(){const{provides:e}=s();return i.useEffect((()=>{if(e)return e.onCopyToClipboard((e=>{navigator.clipboard.writeText(e)}))}),[e]),null},exports.SelectionLayer=function({pageIndex:e,scale:l,background:u="rgba(33,150,243)"}){const{provides:a}=s(),{provides:d}=o.useInteractionManagerCapability(),{register:c}=o.usePointerHandlers({pageIndex:e}),[g,p]=i.useState([]),[f,b]=i.useState(null),{setCursor:h,removeCursor:x}=o.useCursor(),y=i.useRef(null);i.useEffect((()=>{if(a)return a.onSelectionChange((()=>{"default"===(null==d?void 0:d.getActiveMode())?(p(a.getHighlightRectsForPage(e)),b(a.getBoundingRectForPage(e))):(p([]),b(null))}))}),[a,e]);const m=i.useCallback((e=>{const r=y.current;return r?t.glyphAt(r,e):-1}),[]);i.useEffect((()=>{if(!a)return;const t=a.getGeometry(e);return t.wait((e=>y.current=e),n.ignore),()=>{t.abort({code:n.PdfErrorCode.Cancelled,message:"Cancelled"}),y.current=null}}),[a,e]);const C=i.useMemo((()=>({onPointerDown:(r,i,o)=>{if(!a)return;if(!a.isEnabledForMode(o))return;a.clear();a.getGeometry(e).wait((i=>{const n=t.glyphAt(i,r);-1!==n&&a.begin(e,n)}),n.ignore)},onPointerMove:(t,r,i)=>{if(!a)return;if(!a.isEnabledForMode(i))return;const n=m(t);-1!==n?h("selection-text","text",10):x("selection-text"),-1!==n&&a.update(e,n)},onPointerUp:(e,t,r)=>{a&&a.isEnabledForMode(r)&&a.end()},onHandlerActiveEnd(e){a&&a.isEnabledForMode(e)&&a.clear()}})),[a,e,m]);return i.useEffect((()=>{if(c)return c(C)}),[c,C]),f?r.jsx("div",{style:{position:"absolute",left:f.origin.x*l,top:f.origin.y*l,width:f.size.width*l,height:f.size.height*l,mixBlendMode:"multiply",isolation:"isolate"},children:g.map(((e,t)=>r.jsx("div",{style:{position:"absolute",left:(e.origin.x-f.origin.x)*l,top:(e.origin.y-f.origin.y)*l,width:e.size.width*l,height:e.size.height*l,background:u,pointerEvents:"none"}},t)))}):null},exports.useSelectionCapability=s,exports.useSelectionPlugin=()=>e.usePlugin(t.SelectionPlugin.id);
2
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/preact/index.ts","../../src/preact/hooks/use-selection.ts","../../src/preact/components/selection-layer.tsx","../../src/preact/components/copy-to-clipboard.tsx"],"sourcesContent":["export * from './hooks';\nexport * from './components';\n","import { useCapability, usePlugin } from '@embedpdf/core/preact';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","/** @jsxImportSource preact */\nimport { useCallback, useEffect, useMemo, useState } from 'preact/hooks';\nimport { ignore, PdfErrorCode, PdfPageGeometry, Rect } from '@embedpdf/models';\nimport {\n useCursor,\n useInteractionManagerCapability,\n usePointerHandlers,\n} from '@embedpdf/plugin-interaction-manager/preact';\nimport { PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';\nimport { glyphAt } from '@embedpdf/plugin-selection';\n\nimport { useSelectionCapability } from '../hooks';\n\ntype Props = {\n pageIndex: number;\n scale: number;\n background?: string;\n};\n\nexport function SelectionLayer({ pageIndex, scale, background = 'rgba(33,150,243)' }: Props) {\n const { provides: sel } = useSelectionCapability();\n const { provides: im } = useInteractionManagerCapability();\n const { register } = usePointerHandlers({ pageIndex });\n const [rects, setRects] = useState<Array<Rect>>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n const { setCursor, removeCursor } = useCursor();\n\n /* subscribe to rect updates */\n useEffect(() => {\n if (!sel) return;\n return sel.onSelectionChange(() => {\n const mode = im?.getActiveMode();\n if (mode === 'default') {\n setRects(sel.getHighlightRectsForPage(pageIndex));\n setBoundingRect(sel.getBoundingRectForPage(pageIndex));\n } else {\n setRects([]);\n setBoundingRect(null);\n }\n });\n }, [sel, pageIndex]);\n\n /* cheap glyphAt cache for the active page */\n let geoCache: PdfPageGeometry | undefined;\n const cachedGlyphAt = useCallback((pt: { x: number; y: number }) => {\n if (!geoCache) return -1;\n return glyphAt(geoCache, pt);\n }, []);\n\n // Initialize geometry cache\n useEffect(() => {\n if (!sel) return;\n const task = sel.getGeometry(pageIndex);\n task.wait((g) => (geoCache = g), ignore);\n\n return () => {\n task.abort({\n code: PdfErrorCode.Cancelled,\n message: 'Cancelled',\n });\n };\n }, [sel, pageIndex]);\n\n const handlers = useMemo(\n (): PointerEventHandlersWithLifecycle<PointerEvent> => ({\n onPointerDown: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n // clear the selection\n sel.clear();\n const task = sel.getGeometry(pageIndex);\n task.wait((geo) => {\n const g = glyphAt(geo, point);\n if (g !== -1) sel.begin(pageIndex, g);\n }, ignore);\n },\n onPointerMove: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n const g = cachedGlyphAt(point);\n if (g !== -1) {\n setCursor('selection-text', 'text', 10);\n } else {\n removeCursor('selection-text');\n }\n if (g !== -1) sel.update(pageIndex, g);\n },\n onPointerUp: (_point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n sel.end();\n },\n onHandlerActiveEnd(modeId) {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n\n sel.clear();\n },\n }),\n [sel, pageIndex, cachedGlyphAt],\n );\n\n useEffect(() => {\n if (!register) return;\n return register(handlers);\n }, [register, handlers]);\n\n if (!boundingRect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * scale,\n top: boundingRect.origin.y * scale,\n width: boundingRect.size.width * scale,\n height: boundingRect.size.height * scale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n }}\n >\n {rects.map((b, i) => (\n <div\n key={i}\n style={{\n position: 'absolute',\n left: (b.origin.x - boundingRect.origin.x) * scale,\n top: (b.origin.y - boundingRect.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background,\n pointerEvents: 'none',\n }}\n />\n ))}\n </div>\n );\n}\n","import { useEffect } from 'preact/hooks';\n\nimport { useSelectionCapability } from '../hooks';\n\nexport function CopyToClipboard() {\n const { provides: sel } = useSelectionCapability();\n\n useEffect(() => {\n if (!sel) return;\n return sel.onCopyToClipboard((text) => {\n navigator.clipboard.writeText(text);\n });\n }, [sel]);\n\n return null;\n}\n"],"mappings":"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","names":["import_preact","import_plugin_selection","import_hooks"]}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/copy-to-clipboard.tsx","../../src/shared/components/selection-layer.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","import { useEffect } from '@framework';\n\nimport { useSelectionCapability } from '../hooks';\n\nexport function CopyToClipboard() {\n const { provides: sel } = useSelectionCapability();\n\n useEffect(() => {\n if (!sel) return;\n return sel.onCopyToClipboard((text) => {\n navigator.clipboard.writeText(text);\n });\n }, [sel]);\n\n return null;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from '@framework';\nimport { ignore, PdfErrorCode, PdfPageGeometry, Position, Rect } from '@embedpdf/models';\nimport {\n useCursor,\n useInteractionManagerCapability,\n usePointerHandlers,\n} from '@embedpdf/plugin-interaction-manager/@framework';\nimport { PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';\nimport { glyphAt } from '@embedpdf/plugin-selection';\n\nimport { useSelectionCapability } from '../hooks';\n\ntype Props = {\n pageIndex: number;\n scale: number;\n background?: string;\n};\n\nexport function SelectionLayer({ pageIndex, scale, background = 'rgba(33,150,243)' }: Props) {\n const { provides: sel } = useSelectionCapability();\n const { provides: im } = useInteractionManagerCapability();\n const { register } = usePointerHandlers({ pageIndex });\n const [rects, setRects] = useState<Array<Rect>>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n const { setCursor, removeCursor } = useCursor();\n const geoCacheRef = useRef<PdfPageGeometry | null>(null);\n\n /* subscribe to rect updates */\n useEffect(() => {\n if (!sel) return;\n return sel.onSelectionChange(() => {\n const mode = im?.getActiveMode();\n if (mode === 'default') {\n setRects(sel.getHighlightRectsForPage(pageIndex));\n setBoundingRect(sel.getBoundingRectForPage(pageIndex));\n } else {\n setRects([]);\n setBoundingRect(null);\n }\n });\n }, [sel, pageIndex]);\n\n /* cheap glyphAt cache for the active page */\n const cachedGlyphAt = useCallback((pt: Position) => {\n const geo = geoCacheRef.current;\n return geo ? glyphAt(geo, pt) : -1;\n }, []);\n\n // Initialize geometry cache\n useEffect(() => {\n if (!sel) return;\n const task = sel.getGeometry(pageIndex);\n task.wait((g) => (geoCacheRef.current = g), ignore);\n\n return () => {\n task.abort({\n code: PdfErrorCode.Cancelled,\n message: 'Cancelled',\n });\n geoCacheRef.current = null;\n };\n }, [sel, pageIndex]);\n\n const handlers = useMemo(\n (): PointerEventHandlersWithLifecycle<PointerEvent> => ({\n onPointerDown: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n // clear the selection\n sel.clear();\n const task = sel.getGeometry(pageIndex);\n task.wait((geo) => {\n const g = glyphAt(geo, point);\n if (g !== -1) sel.begin(pageIndex, g);\n }, ignore);\n },\n onPointerMove: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n const g = cachedGlyphAt(point);\n if (g !== -1) {\n setCursor('selection-text', 'text', 10);\n } else {\n removeCursor('selection-text');\n }\n if (g !== -1) sel.update(pageIndex, g);\n },\n onPointerUp: (_point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n sel.end();\n },\n onHandlerActiveEnd(modeId) {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n\n sel.clear();\n },\n }),\n [sel, pageIndex, cachedGlyphAt],\n );\n\n useEffect(() => {\n if (!register) return;\n return register(handlers);\n }, [register, handlers]);\n\n if (!boundingRect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * scale,\n top: boundingRect.origin.y * scale,\n width: boundingRect.size.width * scale,\n height: boundingRect.size.height * scale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n }}\n >\n {rects.map((b, i) => (\n <div\n key={i}\n style={{\n position: 'absolute',\n left: (b.origin.x - boundingRect.origin.x) * scale,\n top: (b.origin.y - boundingRect.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background,\n pointerEvents: 'none',\n }}\n />\n ))}\n </div>\n );\n}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","provides","sel","useEffect","onCopyToClipboard","text","navigator","clipboard","writeText","pageIndex","scale","background","im","useInteractionManagerCapability","register","usePointerHandlers","rects","setRects","useState","boundingRect","setBoundingRect","setCursor","removeCursor","useCursor","geoCacheRef","useRef","onSelectionChange","getActiveMode","getHighlightRectsForPage","getBoundingRectForPage","cachedGlyphAt","useCallback","pt","geo","current","glyphAt","task","getGeometry","wait","g","ignore","abort","code","PdfErrorCode","Cancelled","message","handlers","useMemo","onPointerDown","point","_evt","modeId","isEnabledForMode","clear","begin","onPointerMove","update","onPointerUp","_point","end","onHandlerActiveEnd","jsxRuntime","jsx","style","position","left","origin","x","top","y","width","size","height","mixBlendMode","isolation","children","map","b","i","pointerEvents","usePlugin"],"mappings":"0UAGaA,EAAyB,IAAMC,gBAA+BC,EAAAA,gBAAgBC,4BCCpF,WACL,MAAQC,SAAUC,GAAQL,IASnB,OAPPM,EAAAA,WAAU,KACR,GAAKD,EACE,OAAAA,EAAIE,mBAAmBC,IAClBC,UAAAC,UAAUC,UAAUH,EAAI,GACnC,GACA,CAACH,IAEG,IACT,yBCGO,UAAwBO,UAAEA,EAAAC,MAAWA,EAAOC,WAAAA,EAAa,qBAC9D,MAAQV,SAAUC,GAAQL,KAClBI,SAAUW,GAAOC,qCACnBC,SAAEA,GAAaC,qBAAmB,CAAEN,eACnCO,EAAOC,GAAYC,EAAAA,SAAsB,KACzCC,EAAcC,GAAmBF,EAAAA,SAAsB,OACxDG,UAAEA,EAAAC,aAAWA,GAAiBC,cAC9BC,EAAcC,SAA+B,MAGnDtB,EAAAA,WAAU,KACR,GAAKD,EACE,OAAAA,EAAIwB,mBAAkB,KAEd,aADI,MAAJd,OAAI,EAAAA,EAAAe,kBAENV,EAAAf,EAAI0B,yBAAyBnB,IACtBW,EAAAlB,EAAI2B,uBAAuBpB,MAE3CQ,EAAS,IACTG,EAAgB,MAAI,GAEvB,GACA,CAAClB,EAAKO,IAGH,MAAAqB,EAAgBC,eAAaC,IACjC,MAAMC,EAAMT,EAAYU,QACxB,OAAOD,EAAME,EAAAA,QAAQF,EAAKD,IAAM,CAAA,GAC/B,IAGH7B,EAAAA,WAAU,KACR,IAAKD,EAAK,OACJ,MAAAkC,EAAOlC,EAAImC,YAAY5B,GAG7B,OAFA2B,EAAKE,MAAMC,GAAOf,EAAYU,QAAUK,GAAIC,UAErC,KACLJ,EAAKK,MAAM,CACTC,KAAMC,EAAaA,aAAAC,UACnBC,QAAS,cAEXrB,EAAYU,QAAU,IAAA,CACxB,GACC,CAAChC,EAAKO,IAET,MAAMqC,EAAWC,EAAAA,SACf,KAAwD,CACtDC,cAAe,CAACC,EAAOC,EAAMC,KAC3B,IAAKjD,EAAK,OACV,IAAKA,EAAIkD,iBAAiBD,GAAS,OAEnCjD,EAAImD,QACSnD,EAAImC,YAAY5B,GACxB6B,MAAML,IACH,MAAAM,EAAIJ,EAAAA,QAAQF,EAAKgB,IACb,IAANV,GAAcrC,EAAAoD,MAAM7C,EAAW8B,EAAC,GACnCC,SAAM,EAEXe,cAAe,CAACN,EAAOC,EAAMC,KAC3B,IAAKjD,EAAK,OACV,IAAKA,EAAIkD,iBAAiBD,GAAS,OAC7B,MAAAZ,EAAIT,EAAcmB,IACV,IAAVV,EACQlB,EAAA,iBAAkB,OAAQ,IAEpCC,EAAa,mBAEL,IAANiB,GAAcrC,EAAAsD,OAAO/C,EAAW8B,EAAC,EAEvCkB,YAAa,CAACC,EAAQR,EAAMC,KACrBjD,GACAA,EAAIkD,iBAAiBD,IAC1BjD,EAAIyD,KAAI,EAEV,kBAAAC,CAAmBT,GACZjD,GACAA,EAAIkD,iBAAiBD,IAE1BjD,EAAImD,OAAM,KAGd,CAACnD,EAAKO,EAAWqB,IAQf,OALJ3B,EAAAA,WAAU,KACR,GAAKW,EACL,OAAOA,EAASgC,EAAQ,GACvB,CAAChC,EAAUgC,IAET3B,EAGH0C,EAAAC,IAAC,MAAA,CACCC,MAAO,CACLC,SAAU,WACVC,KAAM9C,EAAa+C,OAAOC,EAAIzD,EAC9B0D,IAAKjD,EAAa+C,OAAOG,EAAI3D,EAC7B4D,MAAOnD,EAAaoD,KAAKD,MAAQ5D,EACjC8D,OAAQrD,EAAaoD,KAAKC,OAAS9D,EACnC+D,aAAc,WACdC,UAAW,WAGZC,SAAM3D,EAAA4D,KAAI,CAACC,EAAGC,IACbjB,EAAAC,IAAC,MAAA,CAECC,MAAO,CACLC,SAAU,WACVC,MAAOY,EAAEX,OAAOC,EAAIhD,EAAa+C,OAAOC,GAAKzD,EAC7C0D,KAAMS,EAAEX,OAAOG,EAAIlD,EAAa+C,OAAOG,GAAK3D,EAC5C4D,MAAOO,EAAEN,KAAKD,MAAQ5D,EACtB8D,OAAQK,EAAEN,KAAKC,OAAS9D,EACxBC,aACAoE,cAAe,SARZD,OAhBa,IA8B5B,8DFrIkC,IAAME,YAA2BjF,EAAAA,gBAAgBC"}
@@ -1,25 +1 @@
1
- import * as _embedpdf_plugin_selection from '@embedpdf/plugin-selection';
2
- import { SelectionPlugin } from '@embedpdf/plugin-selection';
3
- import * as preact from 'preact';
4
-
5
- declare const useSelectionCapability: () => {
6
- provides: Readonly<_embedpdf_plugin_selection.SelectionCapability> | null;
7
- isLoading: boolean;
8
- ready: Promise<void>;
9
- };
10
- declare const useSelectionPlugin: () => {
11
- plugin: SelectionPlugin | null;
12
- isLoading: boolean;
13
- ready: Promise<void>;
14
- };
15
-
16
- type Props = {
17
- pageIndex: number;
18
- scale: number;
19
- background?: string;
20
- };
21
- declare function SelectionLayer({ pageIndex, scale, background }: Props): preact.JSX.Element | null;
22
-
23
- declare function CopyToClipboard(): null;
24
-
25
- export { CopyToClipboard, SelectionLayer, useSelectionCapability, useSelectionPlugin };
1
+ export * from '../shared-preact';
@@ -1,19 +1,12 @@
1
- // src/preact/hooks/use-selection.ts
2
1
  import { useCapability, usePlugin } from "@embedpdf/core/preact";
3
- import { SelectionPlugin } from "@embedpdf/plugin-selection";
4
- var useSelectionCapability = () => useCapability(SelectionPlugin.id);
5
- var useSelectionPlugin = () => usePlugin(SelectionPlugin.id);
6
-
7
- // src/preact/components/selection-layer.tsx
8
- import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
9
- import { ignore, PdfErrorCode } from "@embedpdf/models";
10
- import {
11
- useCursor,
12
- useInteractionManagerCapability,
13
- usePointerHandlers
14
- } from "@embedpdf/plugin-interaction-manager/preact";
15
- import { glyphAt } from "@embedpdf/plugin-selection";
2
+ import { SelectionPlugin, glyphAt } from "@embedpdf/plugin-selection";
16
3
  import { jsx } from "preact/jsx-runtime";
4
+ import "preact";
5
+ import { useState, useRef, useEffect, useCallback, useMemo } from "preact/hooks";
6
+ import { ignore, PdfErrorCode } from "@embedpdf/models";
7
+ import { useInteractionManagerCapability, usePointerHandlers, useCursor } from "@embedpdf/plugin-interaction-manager/preact";
8
+ const useSelectionCapability = () => useCapability(SelectionPlugin.id);
9
+ const useSelectionPlugin = () => usePlugin(SelectionPlugin.id);
17
10
  function SelectionLayer({ pageIndex, scale, background = "rgba(33,150,243)" }) {
18
11
  const { provides: sel } = useSelectionCapability();
19
12
  const { provides: im } = useInteractionManagerCapability();
@@ -21,10 +14,11 @@ function SelectionLayer({ pageIndex, scale, background = "rgba(33,150,243)" }) {
21
14
  const [rects, setRects] = useState([]);
22
15
  const [boundingRect, setBoundingRect] = useState(null);
23
16
  const { setCursor, removeCursor } = useCursor();
17
+ const geoCacheRef = useRef(null);
24
18
  useEffect(() => {
25
19
  if (!sel) return;
26
20
  return sel.onSelectionChange(() => {
27
- const mode = im?.getActiveMode();
21
+ const mode = im == null ? void 0 : im.getActiveMode();
28
22
  if (mode === "default") {
29
23
  setRects(sel.getHighlightRectsForPage(pageIndex));
30
24
  setBoundingRect(sel.getBoundingRectForPage(pageIndex));
@@ -34,20 +28,20 @@ function SelectionLayer({ pageIndex, scale, background = "rgba(33,150,243)" }) {
34
28
  }
35
29
  });
36
30
  }, [sel, pageIndex]);
37
- let geoCache;
38
31
  const cachedGlyphAt = useCallback((pt) => {
39
- if (!geoCache) return -1;
40
- return glyphAt(geoCache, pt);
32
+ const geo = geoCacheRef.current;
33
+ return geo ? glyphAt(geo, pt) : -1;
41
34
  }, []);
42
35
  useEffect(() => {
43
36
  if (!sel) return;
44
37
  const task = sel.getGeometry(pageIndex);
45
- task.wait((g) => geoCache = g, ignore);
38
+ task.wait((g) => geoCacheRef.current = g, ignore);
46
39
  return () => {
47
40
  task.abort({
48
41
  code: PdfErrorCode.Cancelled,
49
42
  message: "Cancelled"
50
43
  });
44
+ geoCacheRef.current = null;
51
45
  };
52
46
  }, [sel, pageIndex]);
53
47
  const handlers = useMemo(
@@ -121,12 +115,9 @@ function SelectionLayer({ pageIndex, scale, background = "rgba(33,150,243)" }) {
121
115
  }
122
116
  );
123
117
  }
124
-
125
- // src/preact/components/copy-to-clipboard.tsx
126
- import { useEffect as useEffect2 } from "preact/hooks";
127
118
  function CopyToClipboard() {
128
119
  const { provides: sel } = useSelectionCapability();
129
- useEffect2(() => {
120
+ useEffect(() => {
130
121
  if (!sel) return;
131
122
  return sel.onCopyToClipboard((text) => {
132
123
  navigator.clipboard.writeText(text);
@@ -140,4 +131,4 @@ export {
140
131
  useSelectionCapability,
141
132
  useSelectionPlugin
142
133
  };
143
- //# sourceMappingURL=index.js.map
134
+ //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/preact/hooks/use-selection.ts","../../src/preact/components/selection-layer.tsx","../../src/preact/components/copy-to-clipboard.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/preact';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","/** @jsxImportSource preact */\nimport { useCallback, useEffect, useMemo, useState } from 'preact/hooks';\nimport { ignore, PdfErrorCode, PdfPageGeometry, Rect } from '@embedpdf/models';\nimport {\n useCursor,\n useInteractionManagerCapability,\n usePointerHandlers,\n} from '@embedpdf/plugin-interaction-manager/preact';\nimport { PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';\nimport { glyphAt } from '@embedpdf/plugin-selection';\n\nimport { useSelectionCapability } from '../hooks';\n\ntype Props = {\n pageIndex: number;\n scale: number;\n background?: string;\n};\n\nexport function SelectionLayer({ pageIndex, scale, background = 'rgba(33,150,243)' }: Props) {\n const { provides: sel } = useSelectionCapability();\n const { provides: im } = useInteractionManagerCapability();\n const { register } = usePointerHandlers({ pageIndex });\n const [rects, setRects] = useState<Array<Rect>>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n const { setCursor, removeCursor } = useCursor();\n\n /* subscribe to rect updates */\n useEffect(() => {\n if (!sel) return;\n return sel.onSelectionChange(() => {\n const mode = im?.getActiveMode();\n if (mode === 'default') {\n setRects(sel.getHighlightRectsForPage(pageIndex));\n setBoundingRect(sel.getBoundingRectForPage(pageIndex));\n } else {\n setRects([]);\n setBoundingRect(null);\n }\n });\n }, [sel, pageIndex]);\n\n /* cheap glyphAt cache for the active page */\n let geoCache: PdfPageGeometry | undefined;\n const cachedGlyphAt = useCallback((pt: { x: number; y: number }) => {\n if (!geoCache) return -1;\n return glyphAt(geoCache, pt);\n }, []);\n\n // Initialize geometry cache\n useEffect(() => {\n if (!sel) return;\n const task = sel.getGeometry(pageIndex);\n task.wait((g) => (geoCache = g), ignore);\n\n return () => {\n task.abort({\n code: PdfErrorCode.Cancelled,\n message: 'Cancelled',\n });\n };\n }, [sel, pageIndex]);\n\n const handlers = useMemo(\n (): PointerEventHandlersWithLifecycle<PointerEvent> => ({\n onPointerDown: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n // clear the selection\n sel.clear();\n const task = sel.getGeometry(pageIndex);\n task.wait((geo) => {\n const g = glyphAt(geo, point);\n if (g !== -1) sel.begin(pageIndex, g);\n }, ignore);\n },\n onPointerMove: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n const g = cachedGlyphAt(point);\n if (g !== -1) {\n setCursor('selection-text', 'text', 10);\n } else {\n removeCursor('selection-text');\n }\n if (g !== -1) sel.update(pageIndex, g);\n },\n onPointerUp: (_point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n sel.end();\n },\n onHandlerActiveEnd(modeId) {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n\n sel.clear();\n },\n }),\n [sel, pageIndex, cachedGlyphAt],\n );\n\n useEffect(() => {\n if (!register) return;\n return register(handlers);\n }, [register, handlers]);\n\n if (!boundingRect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * scale,\n top: boundingRect.origin.y * scale,\n width: boundingRect.size.width * scale,\n height: boundingRect.size.height * scale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n }}\n >\n {rects.map((b, i) => (\n <div\n key={i}\n style={{\n position: 'absolute',\n left: (b.origin.x - boundingRect.origin.x) * scale,\n top: (b.origin.y - boundingRect.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background,\n pointerEvents: 'none',\n }}\n />\n ))}\n </div>\n );\n}\n","import { useEffect } from 'preact/hooks';\n\nimport { useSelectionCapability } from '../hooks';\n\nexport function CopyToClipboard() {\n const { provides: sel } = useSelectionCapability();\n\n useEffect(() => {\n if (!sel) return;\n return sel.onCopyToClipboard((text) => {\n navigator.clipboard.writeText(text);\n });\n }, [sel]);\n\n return null;\n}\n"],"mappings":"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","names":["useEffect","useEffect"]}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/selection-layer.tsx","../../src/shared/components/copy-to-clipboard.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","import { useCallback, useEffect, useMemo, useRef, useState } from '@framework';\nimport { ignore, PdfErrorCode, PdfPageGeometry, Position, Rect } from '@embedpdf/models';\nimport {\n useCursor,\n useInteractionManagerCapability,\n usePointerHandlers,\n} from '@embedpdf/plugin-interaction-manager/@framework';\nimport { PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';\nimport { glyphAt } from '@embedpdf/plugin-selection';\n\nimport { useSelectionCapability } from '../hooks';\n\ntype Props = {\n pageIndex: number;\n scale: number;\n background?: string;\n};\n\nexport function SelectionLayer({ pageIndex, scale, background = 'rgba(33,150,243)' }: Props) {\n const { provides: sel } = useSelectionCapability();\n const { provides: im } = useInteractionManagerCapability();\n const { register } = usePointerHandlers({ pageIndex });\n const [rects, setRects] = useState<Array<Rect>>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n const { setCursor, removeCursor } = useCursor();\n const geoCacheRef = useRef<PdfPageGeometry | null>(null);\n\n /* subscribe to rect updates */\n useEffect(() => {\n if (!sel) return;\n return sel.onSelectionChange(() => {\n const mode = im?.getActiveMode();\n if (mode === 'default') {\n setRects(sel.getHighlightRectsForPage(pageIndex));\n setBoundingRect(sel.getBoundingRectForPage(pageIndex));\n } else {\n setRects([]);\n setBoundingRect(null);\n }\n });\n }, [sel, pageIndex]);\n\n /* cheap glyphAt cache for the active page */\n const cachedGlyphAt = useCallback((pt: Position) => {\n const geo = geoCacheRef.current;\n return geo ? glyphAt(geo, pt) : -1;\n }, []);\n\n // Initialize geometry cache\n useEffect(() => {\n if (!sel) return;\n const task = sel.getGeometry(pageIndex);\n task.wait((g) => (geoCacheRef.current = g), ignore);\n\n return () => {\n task.abort({\n code: PdfErrorCode.Cancelled,\n message: 'Cancelled',\n });\n geoCacheRef.current = null;\n };\n }, [sel, pageIndex]);\n\n const handlers = useMemo(\n (): PointerEventHandlersWithLifecycle<PointerEvent> => ({\n onPointerDown: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n // clear the selection\n sel.clear();\n const task = sel.getGeometry(pageIndex);\n task.wait((geo) => {\n const g = glyphAt(geo, point);\n if (g !== -1) sel.begin(pageIndex, g);\n }, ignore);\n },\n onPointerMove: (point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n const g = cachedGlyphAt(point);\n if (g !== -1) {\n setCursor('selection-text', 'text', 10);\n } else {\n removeCursor('selection-text');\n }\n if (g !== -1) sel.update(pageIndex, g);\n },\n onPointerUp: (_point, _evt, modeId) => {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n sel.end();\n },\n onHandlerActiveEnd(modeId) {\n if (!sel) return;\n if (!sel.isEnabledForMode(modeId)) return;\n\n sel.clear();\n },\n }),\n [sel, pageIndex, cachedGlyphAt],\n );\n\n useEffect(() => {\n if (!register) return;\n return register(handlers);\n }, [register, handlers]);\n\n if (!boundingRect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * scale,\n top: boundingRect.origin.y * scale,\n width: boundingRect.size.width * scale,\n height: boundingRect.size.height * scale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n }}\n >\n {rects.map((b, i) => (\n <div\n key={i}\n style={{\n position: 'absolute',\n left: (b.origin.x - boundingRect.origin.x) * scale,\n top: (b.origin.y - boundingRect.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background,\n pointerEvents: 'none',\n }}\n />\n ))}\n </div>\n );\n}\n","import { useEffect } from '@framework';\n\nimport { useSelectionCapability } from '../hooks';\n\nexport function CopyToClipboard() {\n const { provides: sel } = useSelectionCapability();\n\n useEffect(() => {\n if (!sel) return;\n return sel.onCopyToClipboard((text) => {\n navigator.clipboard.writeText(text);\n });\n }, [sel]);\n\n return null;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export * from '@embedpdf/plugin-interaction-manager/preact';
@@ -0,0 +1,2 @@
1
+ export { Fragment, useEffect, useRef, useState, useCallback, useMemo } from 'react';
2
+ export type { ReactNode, HTMLAttributes, CSSProperties } from 'react';
@@ -0,0 +1 @@
1
+ export * from '@embedpdf/core/react';