@embedpdf/plugin-selection 2.5.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +159 -81
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/handlers/marquee-selection.handler.d.ts +9 -7
  6. package/dist/lib/handlers/text-selection.handler.d.ts +8 -6
  7. package/dist/lib/selection-plugin.d.ts +7 -4
  8. package/dist/lib/types.d.ts +71 -2
  9. package/dist/preact/index.cjs +1 -1
  10. package/dist/preact/index.cjs.map +1 -1
  11. package/dist/preact/index.js +59 -16
  12. package/dist/preact/index.js.map +1 -1
  13. package/dist/react/index.cjs +1 -1
  14. package/dist/react/index.cjs.map +1 -1
  15. package/dist/react/index.js +59 -16
  16. package/dist/react/index.js.map +1 -1
  17. package/dist/shared/components/index.d.ts +1 -0
  18. package/dist/shared/components/marquee-selection.d.ts +18 -5
  19. package/dist/shared/components/selection-layer.d.ts +18 -1
  20. package/dist/shared/components/text-selection.d.ts +21 -0
  21. package/dist/shared-preact/components/index.d.ts +1 -0
  22. package/dist/shared-preact/components/marquee-selection.d.ts +18 -5
  23. package/dist/shared-preact/components/selection-layer.d.ts +18 -1
  24. package/dist/shared-preact/components/text-selection.d.ts +21 -0
  25. package/dist/shared-react/components/index.d.ts +1 -0
  26. package/dist/shared-react/components/marquee-selection.d.ts +18 -5
  27. package/dist/shared-react/components/selection-layer.d.ts +18 -1
  28. package/dist/shared-react/components/text-selection.d.ts +21 -0
  29. package/dist/svelte/components/MarqueeSelection.svelte.d.ts +12 -2
  30. package/dist/svelte/components/SelectionLayer.svelte.d.ts +11 -1
  31. package/dist/svelte/components/TextSelection.svelte.d.ts +22 -0
  32. package/dist/svelte/components/index.d.ts +1 -0
  33. package/dist/svelte/index.cjs +1 -1
  34. package/dist/svelte/index.cjs.map +1 -1
  35. package/dist/svelte/index.js +93 -17
  36. package/dist/svelte/index.js.map +1 -1
  37. package/dist/vue/components/index.d.ts +1 -0
  38. package/dist/vue/components/marquee-selection.vue.d.ts +13 -4
  39. package/dist/vue/components/selection-layer.vue.d.ts +15 -5
  40. package/dist/vue/components/text-selection.vue.d.ts +51 -0
  41. package/dist/vue/index.cjs +1 -1
  42. package/dist/vue/index.cjs.map +1 -1
  43. package/dist/vue/index.js +89 -32
  44. package/dist/vue/index.js.map +1 -1
  45. package/package.json +9 -9
@@ -72,6 +72,18 @@ export interface RegisterMarqueeOnPageOptions {
72
72
  /** Called when the marquee rect changes during drag, or null when cancelled/ended */
73
73
  onRectChange: (rect: Rect | null) => void;
74
74
  }
75
+ export interface TextSelectionStyle {
76
+ /** Background color for text selection highlights. Default: 'rgba(33,150,243)' */
77
+ background?: string;
78
+ }
79
+ export interface MarqueeSelectionStyle {
80
+ /** Fill/background color inside the marquee rectangle. Default: 'rgba(0,122,204,0.15)' */
81
+ background?: string;
82
+ /** Border color of the marquee rectangle. Default: 'rgba(0,122,204,0.8)' */
83
+ borderColor?: string;
84
+ /** Border style. Default: 'dashed' */
85
+ borderStyle?: 'solid' | 'dashed' | 'dotted';
86
+ }
75
87
  export interface SelectionMenuPlacementEvent {
76
88
  documentId: string;
77
89
  placement: SelectionMenuPlacement | null;
@@ -79,6 +91,7 @@ export interface SelectionMenuPlacementEvent {
79
91
  export interface SelectionChangeEvent {
80
92
  documentId: string;
81
93
  selection: SelectionRangeX | null;
94
+ modeId: string;
82
95
  }
83
96
  export interface TextRetrievedEvent {
84
97
  documentId: string;
@@ -92,36 +105,75 @@ export interface BeginSelectionEvent {
92
105
  documentId: string;
93
106
  page: number;
94
107
  index: number;
108
+ modeId: string;
95
109
  }
96
110
  export interface EndSelectionEvent {
97
111
  documentId: string;
112
+ modeId: string;
98
113
  }
99
114
  export interface MarqueeChangeEvent {
100
115
  documentId: string;
101
116
  pageIndex: number;
102
117
  rect: Rect | null;
118
+ modeId: string;
103
119
  }
104
120
  export interface MarqueeEndEvent {
105
121
  documentId: string;
106
122
  pageIndex: number;
107
123
  rect: Rect;
124
+ modeId: string;
125
+ }
126
+ export interface EmptySpaceClickEvent {
127
+ documentId: string;
128
+ pageIndex: number;
129
+ modeId: string;
108
130
  }
109
131
  export interface EnableForModeOptions {
110
132
  /**
111
133
  * Whether to show selection rects in the SelectionLayer.
134
+ * @deprecated Use `showSelectionRects` instead.
135
+ * @default true
136
+ */
137
+ showRects?: boolean;
138
+ /**
139
+ * Enable text selection for this mode.
140
+ * @default true
141
+ */
142
+ enableSelection?: boolean;
143
+ /**
144
+ * Whether to show text selection rects in the SelectionLayer.
112
145
  * When false, the selection logic is enabled but the rects are not
113
146
  * rendered (useful when a consuming plugin handles its own rendering).
147
+ * Takes precedence over `showRects`.
114
148
  * @default true
115
149
  */
116
- showRects?: boolean;
150
+ showSelectionRects?: boolean;
151
+ /**
152
+ * Enable marquee selection for this mode.
153
+ * @default false
154
+ */
155
+ enableMarquee?: boolean;
156
+ /**
157
+ * Whether to show the marquee rect in the MarqueeSelection component.
158
+ * When false, the marquee logic runs but the rect is not rendered
159
+ * (useful when a consuming plugin handles its own rendering).
160
+ * @default true
161
+ */
162
+ showMarqueeRects?: boolean;
117
163
  }
118
164
  export interface MarqueeScopeEvent {
119
165
  pageIndex: number;
120
166
  rect: Rect | null;
167
+ modeId: string;
121
168
  }
122
169
  export interface MarqueeEndScopeEvent {
123
170
  pageIndex: number;
124
171
  rect: Rect;
172
+ modeId: string;
173
+ }
174
+ export interface EmptySpaceClickScopeEvent {
175
+ pageIndex: number;
176
+ modeId: string;
125
177
  }
126
178
  export interface SelectionScope {
127
179
  getFormattedSelection(): FormattedSelection[];
@@ -137,7 +189,13 @@ export interface SelectionScope {
137
189
  clear(): void;
138
190
  copyToClipboard(): void;
139
191
  getState(): SelectionDocumentState;
192
+ /**
193
+ * @deprecated Use `enableForMode` with `enableMarquee` option on the capability instead.
194
+ */
140
195
  setMarqueeEnabled(enabled: boolean): void;
196
+ /**
197
+ * @deprecated Use `enableForMode` / `isEnabledForMode` on the capability instead.
198
+ */
141
199
  isMarqueeEnabled(): boolean;
142
200
  onSelectionChange: EventHook<SelectionRangeX | null>;
143
201
  onTextRetrieved: EventHook<string[]>;
@@ -145,10 +203,14 @@ export interface SelectionScope {
145
203
  onBeginSelection: EventHook<{
146
204
  page: number;
147
205
  index: number;
206
+ modeId: string;
207
+ }>;
208
+ onEndSelection: EventHook<{
209
+ modeId: string;
148
210
  }>;
149
- onEndSelection: EventHook<void>;
150
211
  onMarqueeChange: EventHook<MarqueeScopeEvent>;
151
212
  onMarqueeEnd: EventHook<MarqueeEndScopeEvent>;
213
+ onEmptySpaceClick: EventHook<EmptySpaceClickScopeEvent>;
152
214
  }
153
215
  export interface SelectionCapability {
154
216
  getFormattedSelection(documentId?: string): FormattedSelection[];
@@ -166,7 +228,13 @@ export interface SelectionCapability {
166
228
  getState(documentId?: string): SelectionDocumentState;
167
229
  enableForMode(modeId: string, options?: EnableForModeOptions, documentId?: string): void;
168
230
  isEnabledForMode(modeId: string, documentId?: string): boolean;
231
+ /**
232
+ * @deprecated Use `enableForMode` with `enableMarquee` option instead.
233
+ */
169
234
  setMarqueeEnabled(enabled: boolean, documentId?: string): void;
235
+ /**
236
+ * @deprecated Use `enableForMode` / `isEnabledForMode` instead.
237
+ */
170
238
  isMarqueeEnabled(documentId?: string): boolean;
171
239
  forDocument(documentId: string): SelectionScope;
172
240
  onSelectionChange: EventHook<SelectionChangeEvent>;
@@ -176,4 +244,5 @@ export interface SelectionCapability {
176
244
  onEndSelection: EventHook<EndSelectionEvent>;
177
245
  onMarqueeChange: EventHook<MarqueeChangeEvent>;
178
246
  onMarqueeEnd: EventHook<MarqueeEndEvent>;
247
+ onEmptySpaceClick: EventHook<EmptySpaceClickEvent>;
179
248
  }
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-selection"),i=require("preact/jsx-runtime");require("preact");const o=require("preact/hooks"),n=require("@embedpdf/core/preact"),r=require("@embedpdf/utils/preact"),l=()=>n.useCapability(t.SelectionPlugin.id),s=()=>n.usePlugin(t.SelectionPlugin.id);function u(){const{provides:e}=l();return o.useEffect(()=>{if(e)return e.onCopyToClipboard(({text:e})=>{navigator.clipboard.writeText(e)})},[e]),null}const a=e.createPluginPackage(t.SelectionPluginPackage).addUtility(u).build();exports.CopyToClipboard=u,exports.MarqueeSelection=({documentId:e,pageIndex:t,scale:r,className:l,stroke:u="rgba(0,122,204,0.8)",fill:a="rgba(0,122,204,0.15)"})=>{const{plugin:c}=s(),d=n.useDocumentState(e),[g,p]=o.useState(null),x=o.useMemo(()=>void 0!==r?r:(null==d?void 0:d.scale)??1,[r,null==d?void 0:d.scale]);return o.useEffect(()=>{if(c&&e)return c.registerMarqueeOnPage({documentId:e,pageIndex:t,scale:x,onRectChange:p})},[c,e,t,x]),g?i.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:g.origin.x*x,top:g.origin.y*x,width:g.size.width*x,height:g.size.height*x,border:`1px dashed ${u}`,background:a,boxSizing:"border-box",zIndex:1e3},className:l}):null},exports.SelectionLayer=function({documentId:e,pageIndex:t,scale:l,rotation:u,background:a="rgba(33,150,243)",selectionMenu:c}){var d,g;const{plugin:p}=s(),x=n.useDocumentState(e),h=null==(g=null==(d=null==x?void 0:x.document)?void 0:d.pages)?void 0:g[t],[b,f]=o.useState([]),[m,v]=o.useState(null),[y,S]=o.useState(null);o.useEffect(()=>{if(p&&e)return p.registerSelectionOnPage({documentId:e,pageIndex:t,onRectsChange:({rects:e,boundingRect:t})=>{f(e),v(t)}})},[p,e,t]),o.useEffect(()=>{if(p&&e)return p.onMenuPlacement(e,e=>{S(e)})},[p,e]);const P=o.useMemo(()=>void 0!==l?l:(null==x?void 0:x.scale)??1,[l,null==x?void 0:x.scale]),z=o.useMemo(()=>{if(void 0!==u)return u;return(((null==h?void 0:h.rotation)??0)+((null==x?void 0:x.rotation)??0))%4},[u,null==h?void 0:h.rotation,null==x?void 0:x.rotation]),I=c&&y&&y.pageIndex===t&&y.isVisible;return m?i.jsxs(i.Fragment,{children:[i.jsx("div",{style:{position:"absolute",left:m.origin.x*P,top:m.origin.y*P,width:m.size.width*P,height:m.size.height*P,mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"},children:b.map((e,t)=>i.jsx("div",{style:{position:"absolute",left:(e.origin.x-m.origin.x)*P,top:(e.origin.y-m.origin.y)*P,width:e.size.width*P,height:e.size.height*P,background:a}},t))}),I&&i.jsx(r.CounterRotate,{rect:{origin:{x:y.rect.origin.x*P,y:y.rect.origin.y*P},size:{width:y.rect.size.width*P,height:y.rect.size.height*P}},rotation:z,children:e=>c({...e,context:{type:"selection",pageIndex:t},selected:!0,placement:y})})]}):null},exports.SelectionPluginPackage=a,exports.useSelectionCapability=l,exports.useSelectionPlugin=s,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-selection"),o=require("preact/jsx-runtime"),i=require("preact"),n=require("preact/hooks"),r=require("@embedpdf/core/preact"),l=require("@embedpdf/utils/preact"),u=()=>r.useCapability(t.SelectionPlugin.id),s=()=>r.usePlugin(t.SelectionPlugin.id);function a({documentId:e,pageIndex:t,scale:i,rotation:u,background:a="rgba(33,150,243)",selectionMenu:d}){var c,g;const{plugin:p}=s(),x=r.useDocumentState(e),b=null==(g=null==(c=null==x?void 0:x.document)?void 0:c.pages)?void 0:g[t],[h,m]=n.useState([]),[f,y]=n.useState(null),[v,S]=n.useState(null);n.useEffect(()=>{if(p&&e)return p.registerSelectionOnPage({documentId:e,pageIndex:t,onRectsChange:({rects:e,boundingRect:t})=>{m(e),y(t)}})},[p,e,t]),n.useEffect(()=>{if(p&&e)return p.onMenuPlacement(e,e=>{S(e)})},[p,e]);const I=n.useMemo(()=>void 0!==i?i:(null==x?void 0:x.scale)??1,[i,null==x?void 0:x.scale]),P=n.useMemo(()=>{if(void 0!==u)return u;return(((null==b?void 0:b.rotation)??0)+((null==x?void 0:x.rotation)??0))%4},[u,null==b?void 0:b.rotation,null==x?void 0:x.rotation]),k=d&&v&&v.pageIndex===t&&v.isVisible;return f?o.jsxs(o.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:f.origin.x*I,top:f.origin.y*I,width:f.size.width*I,height:f.size.height*I,mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"},children:h.map((e,t)=>o.jsx("div",{style:{position:"absolute",left:(e.origin.x-f.origin.x)*I,top:(e.origin.y-f.origin.y)*I,width:e.size.width*I,height:e.size.height*I,background:a}},t))}),k&&o.jsx(l.CounterRotate,{rect:{origin:{x:v.rect.origin.x*I,y:v.rect.origin.y*I},size:{width:v.rect.size.width*I,height:v.rect.size.height*I}},rotation:P,children:e=>d({...e,context:{type:"selection",pageIndex:t},selected:!0,placement:v})})]}):null}const d=({documentId:e,pageIndex:t,scale:i,className:l,background:u,borderColor:a,borderStyle:d="dashed",stroke:c,fill:g})=>{const{plugin:p}=s(),x=r.useDocumentState(e),[b,h]=n.useState(null),m=a??c??"rgba(0,122,204,0.8)",f=u??g??"rgba(0,122,204,0.15)",y=n.useMemo(()=>void 0!==i?i:(null==x?void 0:x.scale)??1,[i,null==x?void 0:x.scale]);return n.useEffect(()=>{if(p&&e)return p.registerMarqueeOnPage({documentId:e,pageIndex:t,scale:y,onRectChange:h})},[p,e,t,y]),b?o.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:b.origin.x*y,top:b.origin.y*y,width:b.size.width*y,height:b.size.height*y,border:`1px ${d} ${m}`,background:f,boxSizing:"border-box",zIndex:1e3},className:l}):null};function c(){const{provides:e}=u();return n.useEffect(()=>{if(e)return e.onCopyToClipboard(({text:e})=>{navigator.clipboard.writeText(e)})},[e]),null}const g=e.createPluginPackage(t.SelectionPluginPackage).addUtility(c).build();exports.CopyToClipboard=c,exports.MarqueeSelection=d,exports.SelectionLayer=function({documentId:e,pageIndex:t,scale:n,rotation:r,background:l,textStyle:u,marqueeStyle:s,marqueeClassName:c,selectionMenu:g}){return o.jsxs(i.Fragment,{children:[o.jsx(a,{documentId:e,pageIndex:t,scale:n,rotation:r,background:(null==u?void 0:u.background)??l,selectionMenu:g}),o.jsx(d,{documentId:e,pageIndex:t,scale:n,background:null==s?void 0:s.background,borderColor:null==s?void 0:s.borderColor,borderStyle:null==s?void 0:s.borderStyle,className:c})]})},exports.SelectionPluginPackage=g,exports.TextSelection=a,exports.useSelectionCapability=u,exports.useSelectionPlugin=s,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/copy-to-clipboard.tsx","../../src/shared/components/marquee-selection.tsx","../../src/shared/index.ts","../../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 { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useSelectionPlugin } from '../hooks';\n\ninterface MarqueeSelectionProps {\n /** Document ID */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page (optional, defaults to document scale) */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke colour (default: 'rgba(0,122,204,0.8)') */\n stroke?: string;\n /** Fill colour (default: 'rgba(0,122,204,0.15)') */\n fill?: string;\n}\n\n/**\n * MarqueeSelection renders a selection rectangle when the user drags to select items.\n * Place this component on each page where you want marquee selection to work.\n *\n * Other plugins (e.g., annotation, form) can subscribe to `onMarqueeEnd` to\n * determine which objects intersect with the marquee rect.\n */\nexport const MarqueeSelection = ({\n documentId,\n pageIndex,\n scale,\n className,\n stroke = 'rgba(0,122,204,0.8)',\n fill = 'rgba(0,122,204,0.15)',\n}: MarqueeSelectionProps) => {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n onRectChange: setRect,\n });\n }, [selPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px dashed ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n zIndex: 1000,\n }}\n className={className}\n />\n );\n};\n","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n","import { useEffect, useMemo, useState } from '@framework';\nimport { Rect, Rotation } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\n\ntype Props = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n background?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\nexport function SelectionLayer({\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n}: Props) {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const page = documentState?.document?.pages?.[pageIndex];\n const [rects, setRects] = useState<Rect[]>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Store the placement object from the plugin\n const [placement, setPlacement] = useState<SelectionMenuPlacement | null>(null);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects, boundingRect }) => {\n setRects(rects);\n setBoundingRect(boundingRect);\n },\n });\n }, [selPlugin, documentId, pageIndex]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n // Subscribe to menu placement changes for this specific document\n return selPlugin.onMenuPlacement(documentId, (newPlacement) => {\n // Optimization: We could filter here, but React state updates are cheap enough usually.\n // Ideally, check: if (newPlacement?.pageIndex === pageIndex)\n setPlacement(newPlacement);\n });\n }, [selPlugin, documentId]);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotationOverride !== undefined) return rotationOverride;\n // Combine page intrinsic rotation with document rotation\n const pageRotation = page?.rotation ?? 0;\n const docRotation = documentState?.rotation ?? 0;\n return ((pageRotation + docRotation) % 4) as Rotation;\n }, [rotationOverride, page?.rotation, documentState?.rotation]);\n\n const shouldRenderMenu =\n selectionMenu && placement && placement.pageIndex === pageIndex && placement.isVisible;\n\n if (!boundingRect) return null;\n\n return (\n <>\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * actualScale,\n top: boundingRect.origin.y * actualScale,\n width: boundingRect.size.width * actualScale,\n height: boundingRect.size.height * actualScale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\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) * actualScale,\n top: (b.origin.y - boundingRect.origin.y) * actualScale,\n width: b.size.width * actualScale,\n height: b.size.height * actualScale,\n background,\n }}\n />\n ))}\n </div>\n {shouldRenderMenu && (\n <CounterRotate\n rect={{\n origin: {\n x: placement.rect.origin.x * actualScale,\n y: placement.rect.origin.y * actualScale,\n },\n size: {\n width: placement.rect.size.width * actualScale,\n height: placement.rect.size.height * actualScale,\n },\n }}\n rotation={actualRotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'selection',\n pageIndex,\n },\n selected: true,\n placement,\n })\n }\n </CounterRotate>\n )}\n </>\n );\n}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","CopyToClipboard","provides","sel","useEffect","onCopyToClipboard","text","navigator","clipboard","writeText","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","build","documentId","pageIndex","scale","className","stroke","fill","plugin","selPlugin","documentState","useDocumentState","rect","setRect","useState","actualScale","useMemo","registerMarqueeOnPage","onRectChange","jsx","style","position","pointerEvents","left","origin","x","top","y","width","size","height","border","background","boxSizing","zIndex","scaleOverride","rotation","rotationOverride","selectionMenu","page","_b","_a","document","pages","rects","setRects","boundingRect","setBoundingRect","placement","setPlacement","registerSelectionOnPage","onRectsChange","onMenuPlacement","newPlacement","actualRotation","shouldRenderMenu","isVisible","jsxs","Fragment","children","mixBlendMode","isolation","map","b","i","CounterRotate","props","context","type","selected"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/text-selection.tsx","../../src/shared/components/marquee-selection.tsx","../../src/shared/components/copy-to-clipboard.tsx","../../src/shared/index.ts","../../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, useMemo, useState } from '@framework';\nimport { Rect, Rotation } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\n\ntype TextSelectionProps = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n /** Background color for text selection highlights. Default: 'rgba(33,150,243)' */\n background?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\n/**\n * TextSelection renders text selection highlight rects and the selection menu.\n * It registers the text selection handler on the page and subscribes to menu\n * placement changes.\n *\n * Use this component directly for advanced cases, or use `SelectionLayer`\n * which composes both `TextSelection` and `MarqueeSelection`.\n */\nexport function TextSelection({\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n}: TextSelectionProps) {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const page = documentState?.document?.pages?.[pageIndex];\n const [rects, setRects] = useState<Rect[]>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Store the placement object from the plugin\n const [placement, setPlacement] = useState<SelectionMenuPlacement | null>(null);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects, boundingRect }) => {\n setRects(rects);\n setBoundingRect(boundingRect);\n },\n });\n }, [selPlugin, documentId, pageIndex]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n // Subscribe to menu placement changes for this specific document\n return selPlugin.onMenuPlacement(documentId, (newPlacement) => {\n setPlacement(newPlacement);\n });\n }, [selPlugin, documentId]);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotationOverride !== undefined) return rotationOverride;\n // Combine page intrinsic rotation with document rotation\n const pageRotation = page?.rotation ?? 0;\n const docRotation = documentState?.rotation ?? 0;\n return ((pageRotation + docRotation) % 4) as Rotation;\n }, [rotationOverride, page?.rotation, documentState?.rotation]);\n\n const shouldRenderMenu =\n selectionMenu && placement && placement.pageIndex === pageIndex && placement.isVisible;\n\n if (!boundingRect) return null;\n\n return (\n <>\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * actualScale,\n top: boundingRect.origin.y * actualScale,\n width: boundingRect.size.width * actualScale,\n height: boundingRect.size.height * actualScale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\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) * actualScale,\n top: (b.origin.y - boundingRect.origin.y) * actualScale,\n width: b.size.width * actualScale,\n height: b.size.height * actualScale,\n background,\n }}\n />\n ))}\n </div>\n {shouldRenderMenu && (\n <CounterRotate\n rect={{\n origin: {\n x: placement.rect.origin.x * actualScale,\n y: placement.rect.origin.y * actualScale,\n },\n size: {\n width: placement.rect.size.width * actualScale,\n height: placement.rect.size.height * actualScale,\n },\n }}\n rotation={actualRotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'selection',\n pageIndex,\n },\n selected: true,\n placement,\n })\n }\n </CounterRotate>\n )}\n </>\n );\n}\n","import { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useSelectionPlugin } from '../hooks';\n\ninterface MarqueeSelectionProps {\n /** Document ID */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page (optional, defaults to document scale) */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Fill/background color inside the marquee rectangle. Default: 'rgba(0,122,204,0.15)' */\n background?: string;\n /** Border color of the marquee rectangle. Default: 'rgba(0,122,204,0.8)' */\n borderColor?: string;\n /** Border style. Default: 'dashed' */\n borderStyle?: 'solid' | 'dashed' | 'dotted';\n /**\n * @deprecated Use `borderColor` instead.\n */\n stroke?: string;\n /**\n * @deprecated Use `background` instead.\n */\n fill?: string;\n}\n\n/**\n * MarqueeSelection renders a selection rectangle when the user drags to select items.\n * It registers the marquee handler on the page.\n *\n * Other plugins (e.g., annotation, form, redaction) can subscribe to `onMarqueeEnd` to\n * determine which objects intersect with the marquee rect.\n *\n * Use this component directly for advanced cases, or use `SelectionLayer`\n * which composes both `TextSelection` and `MarqueeSelection`.\n */\nexport const MarqueeSelection = ({\n documentId,\n pageIndex,\n scale,\n className,\n background,\n borderColor,\n borderStyle = 'dashed',\n stroke,\n fill,\n}: MarqueeSelectionProps) => {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n // Resolve deprecated props: new CSS-standard props take precedence\n const resolvedBorderColor = borderColor ?? stroke ?? 'rgba(0,122,204,0.8)';\n const resolvedBackground = background ?? fill ?? 'rgba(0,122,204,0.15)';\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n onRectChange: setRect,\n });\n }, [selPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px ${borderStyle} ${resolvedBorderColor}`,\n background: resolvedBackground,\n boxSizing: 'border-box',\n zIndex: 1000,\n }}\n className={className}\n />\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","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n","import { Fragment } from '@framework';\nimport { Rotation } from '@embedpdf/models';\nimport { TextSelectionStyle, MarqueeSelectionStyle } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { TextSelection } from './text-selection';\nimport { MarqueeSelection } from './marquee-selection';\n\ntype Props = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n /**\n * @deprecated Use `textStyle.background` instead.\n */\n background?: string;\n /** Styling options for text selection highlights */\n textStyle?: TextSelectionStyle;\n /** Styling options for the marquee selection rectangle */\n marqueeStyle?: MarqueeSelectionStyle;\n /** Optional CSS class applied to the marquee rectangle */\n marqueeClassName?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\n/**\n * SelectionLayer is a convenience component that composes both text selection\n * and marquee selection on a single page.\n *\n * For advanced use cases, you can use `TextSelection` and `MarqueeSelection`\n * individually.\n */\nexport function SelectionLayer({\n documentId,\n pageIndex,\n scale,\n rotation,\n background,\n textStyle,\n marqueeStyle,\n marqueeClassName,\n selectionMenu,\n}: Props) {\n return (\n <Fragment>\n <TextSelection\n documentId={documentId}\n pageIndex={pageIndex}\n scale={scale}\n rotation={rotation}\n background={textStyle?.background ?? background}\n selectionMenu={selectionMenu}\n />\n <MarqueeSelection\n documentId={documentId}\n pageIndex={pageIndex}\n scale={scale}\n background={marqueeStyle?.background}\n borderColor={marqueeStyle?.borderColor}\n borderStyle={marqueeStyle?.borderStyle}\n className={marqueeClassName}\n />\n </Fragment>\n );\n}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","TextSelection","documentId","pageIndex","scale","scaleOverride","rotation","rotationOverride","background","selectionMenu","plugin","selPlugin","documentState","useDocumentState","page","_b","_a","document","pages","rects","setRects","useState","boundingRect","setBoundingRect","placement","setPlacement","useEffect","registerSelectionOnPage","onRectsChange","onMenuPlacement","newPlacement","actualScale","useMemo","actualRotation","shouldRenderMenu","isVisible","jsxs","Fragment","children","jsx","style","position","left","origin","x","top","y","width","size","height","mixBlendMode","isolation","pointerEvents","map","b","i","CounterRotate","rect","props","context","type","selected","MarqueeSelection","className","borderColor","borderStyle","stroke","fill","setRect","resolvedBorderColor","resolvedBackground","registerMarqueeOnPage","onRectChange","border","boxSizing","zIndex","CopyToClipboard","provides","sel","onCopyToClipboard","text","navigator","clipboard","writeText","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","build","textStyle","marqueeStyle","marqueeClassName"],"mappings":"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"}
@@ -2,13 +2,13 @@ import { createPluginPackage } from "@embedpdf/core";
2
2
  import { SelectionPlugin, SelectionPluginPackage as SelectionPluginPackage$1 } from "@embedpdf/plugin-selection";
3
3
  export * from "@embedpdf/plugin-selection";
4
4
  import { jsxs, Fragment, jsx } from "preact/jsx-runtime";
5
- import "preact";
5
+ import { Fragment as Fragment$1 } from "preact";
6
6
  import { useState, useEffect, useMemo } from "preact/hooks";
7
7
  import { useCapability, usePlugin, useDocumentState } from "@embedpdf/core/preact";
8
8
  import { CounterRotate } from "@embedpdf/utils/preact";
9
9
  const useSelectionCapability = () => useCapability(SelectionPlugin.id);
10
10
  const useSelectionPlugin = () => usePlugin(SelectionPlugin.id);
11
- function SelectionLayer({
11
+ function TextSelection({
12
12
  documentId,
13
13
  pageIndex,
14
14
  scale: scaleOverride,
@@ -109,27 +109,22 @@ function SelectionLayer({
109
109
  )
110
110
  ] });
111
111
  }
112
- function CopyToClipboard() {
113
- const { provides: sel } = useSelectionCapability();
114
- useEffect(() => {
115
- if (!sel) return;
116
- return sel.onCopyToClipboard(({ text }) => {
117
- navigator.clipboard.writeText(text);
118
- });
119
- }, [sel]);
120
- return null;
121
- }
122
112
  const MarqueeSelection = ({
123
113
  documentId,
124
114
  pageIndex,
125
115
  scale,
126
116
  className,
127
- stroke = "rgba(0,122,204,0.8)",
128
- fill = "rgba(0,122,204,0.15)"
117
+ background,
118
+ borderColor,
119
+ borderStyle = "dashed",
120
+ stroke,
121
+ fill
129
122
  }) => {
130
123
  const { plugin: selPlugin } = useSelectionPlugin();
131
124
  const documentState = useDocumentState(documentId);
132
125
  const [rect, setRect] = useState(null);
126
+ const resolvedBorderColor = borderColor ?? stroke ?? "rgba(0,122,204,0.8)";
127
+ const resolvedBackground = background ?? fill ?? "rgba(0,122,204,0.15)";
133
128
  const actualScale = useMemo(() => {
134
129
  if (scale !== void 0) return scale;
135
130
  return (documentState == null ? void 0 : documentState.scale) ?? 1;
@@ -154,8 +149,8 @@ const MarqueeSelection = ({
154
149
  top: rect.origin.y * actualScale,
155
150
  width: rect.size.width * actualScale,
156
151
  height: rect.size.height * actualScale,
157
- border: `1px dashed ${stroke}`,
158
- background: fill,
152
+ border: `1px ${borderStyle} ${resolvedBorderColor}`,
153
+ background: resolvedBackground,
159
154
  boxSizing: "border-box",
160
155
  zIndex: 1e3
161
156
  },
@@ -163,12 +158,60 @@ const MarqueeSelection = ({
163
158
  }
164
159
  );
165
160
  };
161
+ function SelectionLayer({
162
+ documentId,
163
+ pageIndex,
164
+ scale,
165
+ rotation,
166
+ background,
167
+ textStyle,
168
+ marqueeStyle,
169
+ marqueeClassName,
170
+ selectionMenu
171
+ }) {
172
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
173
+ /* @__PURE__ */ jsx(
174
+ TextSelection,
175
+ {
176
+ documentId,
177
+ pageIndex,
178
+ scale,
179
+ rotation,
180
+ background: (textStyle == null ? void 0 : textStyle.background) ?? background,
181
+ selectionMenu
182
+ }
183
+ ),
184
+ /* @__PURE__ */ jsx(
185
+ MarqueeSelection,
186
+ {
187
+ documentId,
188
+ pageIndex,
189
+ scale,
190
+ background: marqueeStyle == null ? void 0 : marqueeStyle.background,
191
+ borderColor: marqueeStyle == null ? void 0 : marqueeStyle.borderColor,
192
+ borderStyle: marqueeStyle == null ? void 0 : marqueeStyle.borderStyle,
193
+ className: marqueeClassName
194
+ }
195
+ )
196
+ ] });
197
+ }
198
+ function CopyToClipboard() {
199
+ const { provides: sel } = useSelectionCapability();
200
+ useEffect(() => {
201
+ if (!sel) return;
202
+ return sel.onCopyToClipboard(({ text }) => {
203
+ navigator.clipboard.writeText(text);
204
+ });
205
+ }, [sel]);
206
+ return null;
207
+ }
166
208
  const SelectionPluginPackage = createPluginPackage(SelectionPluginPackage$1).addUtility(CopyToClipboard).build();
167
209
  export {
168
210
  CopyToClipboard,
169
211
  MarqueeSelection,
170
212
  SelectionLayer,
171
213
  SelectionPluginPackage,
214
+ TextSelection,
172
215
  useSelectionCapability,
173
216
  useSelectionPlugin
174
217
  };
@@ -1 +1 @@
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","../../src/shared/components/marquee-selection.tsx","../../src/shared/index.ts"],"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, useMemo, useState } from '@framework';\nimport { Rect, Rotation } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\n\ntype Props = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n background?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\nexport function SelectionLayer({\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n}: Props) {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const page = documentState?.document?.pages?.[pageIndex];\n const [rects, setRects] = useState<Rect[]>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Store the placement object from the plugin\n const [placement, setPlacement] = useState<SelectionMenuPlacement | null>(null);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects, boundingRect }) => {\n setRects(rects);\n setBoundingRect(boundingRect);\n },\n });\n }, [selPlugin, documentId, pageIndex]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n // Subscribe to menu placement changes for this specific document\n return selPlugin.onMenuPlacement(documentId, (newPlacement) => {\n // Optimization: We could filter here, but React state updates are cheap enough usually.\n // Ideally, check: if (newPlacement?.pageIndex === pageIndex)\n setPlacement(newPlacement);\n });\n }, [selPlugin, documentId]);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotationOverride !== undefined) return rotationOverride;\n // Combine page intrinsic rotation with document rotation\n const pageRotation = page?.rotation ?? 0;\n const docRotation = documentState?.rotation ?? 0;\n return ((pageRotation + docRotation) % 4) as Rotation;\n }, [rotationOverride, page?.rotation, documentState?.rotation]);\n\n const shouldRenderMenu =\n selectionMenu && placement && placement.pageIndex === pageIndex && placement.isVisible;\n\n if (!boundingRect) return null;\n\n return (\n <>\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * actualScale,\n top: boundingRect.origin.y * actualScale,\n width: boundingRect.size.width * actualScale,\n height: boundingRect.size.height * actualScale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\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) * actualScale,\n top: (b.origin.y - boundingRect.origin.y) * actualScale,\n width: b.size.width * actualScale,\n height: b.size.height * actualScale,\n background,\n }}\n />\n ))}\n </div>\n {shouldRenderMenu && (\n <CounterRotate\n rect={{\n origin: {\n x: placement.rect.origin.x * actualScale,\n y: placement.rect.origin.y * actualScale,\n },\n size: {\n width: placement.rect.size.width * actualScale,\n height: placement.rect.size.height * actualScale,\n },\n }}\n rotation={actualRotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'selection',\n pageIndex,\n },\n selected: true,\n placement,\n })\n }\n </CounterRotate>\n )}\n </>\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","import { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useSelectionPlugin } from '../hooks';\n\ninterface MarqueeSelectionProps {\n /** Document ID */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page (optional, defaults to document scale) */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke colour (default: 'rgba(0,122,204,0.8)') */\n stroke?: string;\n /** Fill colour (default: 'rgba(0,122,204,0.15)') */\n fill?: string;\n}\n\n/**\n * MarqueeSelection renders a selection rectangle when the user drags to select items.\n * Place this component on each page where you want marquee selection to work.\n *\n * Other plugins (e.g., annotation, form) can subscribe to `onMarqueeEnd` to\n * determine which objects intersect with the marquee rect.\n */\nexport const MarqueeSelection = ({\n documentId,\n pageIndex,\n scale,\n className,\n stroke = 'rgba(0,122,204,0.8)',\n fill = 'rgba(0,122,204,0.15)',\n}: MarqueeSelectionProps) => {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n onRectChange: setRect,\n });\n }, [selPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px dashed ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n zIndex: 1000,\n }}\n className={className}\n />\n );\n};\n","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n"],"names":["rects","boundingRect","BaseSelectionPluginPackage"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/text-selection.tsx","../../src/shared/components/marquee-selection.tsx","../../src/shared/components/selection-layer.tsx","../../src/shared/components/copy-to-clipboard.tsx","../../src/shared/index.ts"],"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, useMemo, useState } from '@framework';\nimport { Rect, Rotation } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\n\ntype TextSelectionProps = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n /** Background color for text selection highlights. Default: 'rgba(33,150,243)' */\n background?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\n/**\n * TextSelection renders text selection highlight rects and the selection menu.\n * It registers the text selection handler on the page and subscribes to menu\n * placement changes.\n *\n * Use this component directly for advanced cases, or use `SelectionLayer`\n * which composes both `TextSelection` and `MarqueeSelection`.\n */\nexport function TextSelection({\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n}: TextSelectionProps) {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const page = documentState?.document?.pages?.[pageIndex];\n const [rects, setRects] = useState<Rect[]>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Store the placement object from the plugin\n const [placement, setPlacement] = useState<SelectionMenuPlacement | null>(null);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects, boundingRect }) => {\n setRects(rects);\n setBoundingRect(boundingRect);\n },\n });\n }, [selPlugin, documentId, pageIndex]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n // Subscribe to menu placement changes for this specific document\n return selPlugin.onMenuPlacement(documentId, (newPlacement) => {\n setPlacement(newPlacement);\n });\n }, [selPlugin, documentId]);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotationOverride !== undefined) return rotationOverride;\n // Combine page intrinsic rotation with document rotation\n const pageRotation = page?.rotation ?? 0;\n const docRotation = documentState?.rotation ?? 0;\n return ((pageRotation + docRotation) % 4) as Rotation;\n }, [rotationOverride, page?.rotation, documentState?.rotation]);\n\n const shouldRenderMenu =\n selectionMenu && placement && placement.pageIndex === pageIndex && placement.isVisible;\n\n if (!boundingRect) return null;\n\n return (\n <>\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * actualScale,\n top: boundingRect.origin.y * actualScale,\n width: boundingRect.size.width * actualScale,\n height: boundingRect.size.height * actualScale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\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) * actualScale,\n top: (b.origin.y - boundingRect.origin.y) * actualScale,\n width: b.size.width * actualScale,\n height: b.size.height * actualScale,\n background,\n }}\n />\n ))}\n </div>\n {shouldRenderMenu && (\n <CounterRotate\n rect={{\n origin: {\n x: placement.rect.origin.x * actualScale,\n y: placement.rect.origin.y * actualScale,\n },\n size: {\n width: placement.rect.size.width * actualScale,\n height: placement.rect.size.height * actualScale,\n },\n }}\n rotation={actualRotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'selection',\n pageIndex,\n },\n selected: true,\n placement,\n })\n }\n </CounterRotate>\n )}\n </>\n );\n}\n","import { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useSelectionPlugin } from '../hooks';\n\ninterface MarqueeSelectionProps {\n /** Document ID */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page (optional, defaults to document scale) */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Fill/background color inside the marquee rectangle. Default: 'rgba(0,122,204,0.15)' */\n background?: string;\n /** Border color of the marquee rectangle. Default: 'rgba(0,122,204,0.8)' */\n borderColor?: string;\n /** Border style. Default: 'dashed' */\n borderStyle?: 'solid' | 'dashed' | 'dotted';\n /**\n * @deprecated Use `borderColor` instead.\n */\n stroke?: string;\n /**\n * @deprecated Use `background` instead.\n */\n fill?: string;\n}\n\n/**\n * MarqueeSelection renders a selection rectangle when the user drags to select items.\n * It registers the marquee handler on the page.\n *\n * Other plugins (e.g., annotation, form, redaction) can subscribe to `onMarqueeEnd` to\n * determine which objects intersect with the marquee rect.\n *\n * Use this component directly for advanced cases, or use `SelectionLayer`\n * which composes both `TextSelection` and `MarqueeSelection`.\n */\nexport const MarqueeSelection = ({\n documentId,\n pageIndex,\n scale,\n className,\n background,\n borderColor,\n borderStyle = 'dashed',\n stroke,\n fill,\n}: MarqueeSelectionProps) => {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n // Resolve deprecated props: new CSS-standard props take precedence\n const resolvedBorderColor = borderColor ?? stroke ?? 'rgba(0,122,204,0.8)';\n const resolvedBackground = background ?? fill ?? 'rgba(0,122,204,0.15)';\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n onRectChange: setRect,\n });\n }, [selPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px ${borderStyle} ${resolvedBorderColor}`,\n background: resolvedBackground,\n boxSizing: 'border-box',\n zIndex: 1000,\n }}\n className={className}\n />\n );\n};\n","import { Fragment } from '@framework';\nimport { Rotation } from '@embedpdf/models';\nimport { TextSelectionStyle, MarqueeSelectionStyle } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { TextSelection } from './text-selection';\nimport { MarqueeSelection } from './marquee-selection';\n\ntype Props = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n /**\n * @deprecated Use `textStyle.background` instead.\n */\n background?: string;\n /** Styling options for text selection highlights */\n textStyle?: TextSelectionStyle;\n /** Styling options for the marquee selection rectangle */\n marqueeStyle?: MarqueeSelectionStyle;\n /** Optional CSS class applied to the marquee rectangle */\n marqueeClassName?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\n/**\n * SelectionLayer is a convenience component that composes both text selection\n * and marquee selection on a single page.\n *\n * For advanced use cases, you can use `TextSelection` and `MarqueeSelection`\n * individually.\n */\nexport function SelectionLayer({\n documentId,\n pageIndex,\n scale,\n rotation,\n background,\n textStyle,\n marqueeStyle,\n marqueeClassName,\n selectionMenu,\n}: Props) {\n return (\n <Fragment>\n <TextSelection\n documentId={documentId}\n pageIndex={pageIndex}\n scale={scale}\n rotation={rotation}\n background={textStyle?.background ?? background}\n selectionMenu={selectionMenu}\n />\n <MarqueeSelection\n documentId={documentId}\n pageIndex={pageIndex}\n scale={scale}\n background={marqueeStyle?.background}\n borderColor={marqueeStyle?.borderColor}\n borderStyle={marqueeStyle?.borderStyle}\n className={marqueeClassName}\n />\n </Fragment>\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","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n"],"names":["rects","boundingRect","Fragment","BaseSelectionPluginPackage"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-selection"),i=require("react/jsx-runtime"),n=require("react"),o=require("@embedpdf/core/react"),r=require("@embedpdf/utils/react"),l=()=>o.useCapability(t.SelectionPlugin.id),s=()=>o.usePlugin(t.SelectionPlugin.id);function u(){const{provides:e}=l();return n.useEffect(()=>{if(e)return e.onCopyToClipboard(({text:e})=>{navigator.clipboard.writeText(e)})},[e]),null}const a=e.createPluginPackage(t.SelectionPluginPackage).addUtility(u).build();exports.CopyToClipboard=u,exports.MarqueeSelection=({documentId:e,pageIndex:t,scale:r,className:l,stroke:u="rgba(0,122,204,0.8)",fill:a="rgba(0,122,204,0.15)"})=>{const{plugin:c}=s(),d=o.useDocumentState(e),[g,p]=n.useState(null),x=n.useMemo(()=>void 0!==r?r:(null==d?void 0:d.scale)??1,[r,null==d?void 0:d.scale]);return n.useEffect(()=>{if(c&&e)return c.registerMarqueeOnPage({documentId:e,pageIndex:t,scale:x,onRectChange:p})},[c,e,t,x]),g?i.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:g.origin.x*x,top:g.origin.y*x,width:g.size.width*x,height:g.size.height*x,border:`1px dashed ${u}`,background:a,boxSizing:"border-box",zIndex:1e3},className:l}):null},exports.SelectionLayer=function({documentId:e,pageIndex:t,scale:l,rotation:u,background:a="rgba(33,150,243)",selectionMenu:c}){var d,g;const{plugin:p}=s(),x=o.useDocumentState(e),h=null==(g=null==(d=null==x?void 0:x.document)?void 0:d.pages)?void 0:g[t],[b,f]=n.useState([]),[m,v]=n.useState(null),[y,S]=n.useState(null);n.useEffect(()=>{if(p&&e)return p.registerSelectionOnPage({documentId:e,pageIndex:t,onRectsChange:({rects:e,boundingRect:t})=>{f(e),v(t)}})},[p,e,t]),n.useEffect(()=>{if(p&&e)return p.onMenuPlacement(e,e=>{S(e)})},[p,e]);const P=n.useMemo(()=>void 0!==l?l:(null==x?void 0:x.scale)??1,[l,null==x?void 0:x.scale]),z=n.useMemo(()=>{if(void 0!==u)return u;return(((null==h?void 0:h.rotation)??0)+((null==x?void 0:x.rotation)??0))%4},[u,null==h?void 0:h.rotation,null==x?void 0:x.rotation]),I=c&&y&&y.pageIndex===t&&y.isVisible;return m?i.jsxs(i.Fragment,{children:[i.jsx("div",{style:{position:"absolute",left:m.origin.x*P,top:m.origin.y*P,width:m.size.width*P,height:m.size.height*P,mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"},children:b.map((e,t)=>i.jsx("div",{style:{position:"absolute",left:(e.origin.x-m.origin.x)*P,top:(e.origin.y-m.origin.y)*P,width:e.size.width*P,height:e.size.height*P,background:a}},t))}),I&&i.jsx(r.CounterRotate,{rect:{origin:{x:y.rect.origin.x*P,y:y.rect.origin.y*P},size:{width:y.rect.size.width*P,height:y.rect.size.height*P}},rotation:z,children:e=>c({...e,context:{type:"selection",pageIndex:t},selected:!0,placement:y})})]}):null},exports.SelectionPluginPackage=a,exports.useSelectionCapability=l,exports.useSelectionPlugin=s,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-selection"),o=require("react/jsx-runtime"),i=require("react"),n=require("@embedpdf/core/react"),r=require("@embedpdf/utils/react"),l=()=>n.useCapability(t.SelectionPlugin.id),u=()=>n.usePlugin(t.SelectionPlugin.id);function s({documentId:e,pageIndex:t,scale:l,rotation:s,background:a="rgba(33,150,243)",selectionMenu:d}){var c,g;const{plugin:p}=u(),x=n.useDocumentState(e),b=null==(g=null==(c=null==x?void 0:x.document)?void 0:c.pages)?void 0:g[t],[h,m]=i.useState([]),[f,y]=i.useState(null),[v,S]=i.useState(null);i.useEffect(()=>{if(p&&e)return p.registerSelectionOnPage({documentId:e,pageIndex:t,onRectsChange:({rects:e,boundingRect:t})=>{m(e),y(t)}})},[p,e,t]),i.useEffect(()=>{if(p&&e)return p.onMenuPlacement(e,e=>{S(e)})},[p,e]);const I=i.useMemo(()=>void 0!==l?l:(null==x?void 0:x.scale)??1,[l,null==x?void 0:x.scale]),P=i.useMemo(()=>{if(void 0!==s)return s;return(((null==b?void 0:b.rotation)??0)+((null==x?void 0:x.rotation)??0))%4},[s,null==b?void 0:b.rotation,null==x?void 0:x.rotation]),k=d&&v&&v.pageIndex===t&&v.isVisible;return f?o.jsxs(o.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:f.origin.x*I,top:f.origin.y*I,width:f.size.width*I,height:f.size.height*I,mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"},children:h.map((e,t)=>o.jsx("div",{style:{position:"absolute",left:(e.origin.x-f.origin.x)*I,top:(e.origin.y-f.origin.y)*I,width:e.size.width*I,height:e.size.height*I,background:a}},t))}),k&&o.jsx(r.CounterRotate,{rect:{origin:{x:v.rect.origin.x*I,y:v.rect.origin.y*I},size:{width:v.rect.size.width*I,height:v.rect.size.height*I}},rotation:P,children:e=>d({...e,context:{type:"selection",pageIndex:t},selected:!0,placement:v})})]}):null}const a=({documentId:e,pageIndex:t,scale:r,className:l,background:s,borderColor:a,borderStyle:d="dashed",stroke:c,fill:g})=>{const{plugin:p}=u(),x=n.useDocumentState(e),[b,h]=i.useState(null),m=a??c??"rgba(0,122,204,0.8)",f=s??g??"rgba(0,122,204,0.15)",y=i.useMemo(()=>void 0!==r?r:(null==x?void 0:x.scale)??1,[r,null==x?void 0:x.scale]);return i.useEffect(()=>{if(p&&e)return p.registerMarqueeOnPage({documentId:e,pageIndex:t,scale:y,onRectChange:h})},[p,e,t,y]),b?o.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:b.origin.x*y,top:b.origin.y*y,width:b.size.width*y,height:b.size.height*y,border:`1px ${d} ${m}`,background:f,boxSizing:"border-box",zIndex:1e3},className:l}):null};function d(){const{provides:e}=l();return i.useEffect(()=>{if(e)return e.onCopyToClipboard(({text:e})=>{navigator.clipboard.writeText(e)})},[e]),null}const c=e.createPluginPackage(t.SelectionPluginPackage).addUtility(d).build();exports.CopyToClipboard=d,exports.MarqueeSelection=a,exports.SelectionLayer=function({documentId:e,pageIndex:t,scale:n,rotation:r,background:l,textStyle:u,marqueeStyle:d,marqueeClassName:c,selectionMenu:g}){return o.jsxs(i.Fragment,{children:[o.jsx(s,{documentId:e,pageIndex:t,scale:n,rotation:r,background:(null==u?void 0:u.background)??l,selectionMenu:g}),o.jsx(a,{documentId:e,pageIndex:t,scale:n,background:null==d?void 0:d.background,borderColor:null==d?void 0:d.borderColor,borderStyle:null==d?void 0:d.borderStyle,className:c})]})},exports.SelectionPluginPackage=c,exports.TextSelection=s,exports.useSelectionCapability=l,exports.useSelectionPlugin=u,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/copy-to-clipboard.tsx","../../src/shared/components/marquee-selection.tsx","../../src/shared/index.ts","../../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 { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useSelectionPlugin } from '../hooks';\n\ninterface MarqueeSelectionProps {\n /** Document ID */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page (optional, defaults to document scale) */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke colour (default: 'rgba(0,122,204,0.8)') */\n stroke?: string;\n /** Fill colour (default: 'rgba(0,122,204,0.15)') */\n fill?: string;\n}\n\n/**\n * MarqueeSelection renders a selection rectangle when the user drags to select items.\n * Place this component on each page where you want marquee selection to work.\n *\n * Other plugins (e.g., annotation, form) can subscribe to `onMarqueeEnd` to\n * determine which objects intersect with the marquee rect.\n */\nexport const MarqueeSelection = ({\n documentId,\n pageIndex,\n scale,\n className,\n stroke = 'rgba(0,122,204,0.8)',\n fill = 'rgba(0,122,204,0.15)',\n}: MarqueeSelectionProps) => {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n onRectChange: setRect,\n });\n }, [selPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px dashed ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n zIndex: 1000,\n }}\n className={className}\n />\n );\n};\n","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n","import { useEffect, useMemo, useState } from '@framework';\nimport { Rect, Rotation } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\n\ntype Props = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n background?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\nexport function SelectionLayer({\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n}: Props) {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const page = documentState?.document?.pages?.[pageIndex];\n const [rects, setRects] = useState<Rect[]>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Store the placement object from the plugin\n const [placement, setPlacement] = useState<SelectionMenuPlacement | null>(null);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects, boundingRect }) => {\n setRects(rects);\n setBoundingRect(boundingRect);\n },\n });\n }, [selPlugin, documentId, pageIndex]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n // Subscribe to menu placement changes for this specific document\n return selPlugin.onMenuPlacement(documentId, (newPlacement) => {\n // Optimization: We could filter here, but React state updates are cheap enough usually.\n // Ideally, check: if (newPlacement?.pageIndex === pageIndex)\n setPlacement(newPlacement);\n });\n }, [selPlugin, documentId]);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotationOverride !== undefined) return rotationOverride;\n // Combine page intrinsic rotation with document rotation\n const pageRotation = page?.rotation ?? 0;\n const docRotation = documentState?.rotation ?? 0;\n return ((pageRotation + docRotation) % 4) as Rotation;\n }, [rotationOverride, page?.rotation, documentState?.rotation]);\n\n const shouldRenderMenu =\n selectionMenu && placement && placement.pageIndex === pageIndex && placement.isVisible;\n\n if (!boundingRect) return null;\n\n return (\n <>\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * actualScale,\n top: boundingRect.origin.y * actualScale,\n width: boundingRect.size.width * actualScale,\n height: boundingRect.size.height * actualScale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\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) * actualScale,\n top: (b.origin.y - boundingRect.origin.y) * actualScale,\n width: b.size.width * actualScale,\n height: b.size.height * actualScale,\n background,\n }}\n />\n ))}\n </div>\n {shouldRenderMenu && (\n <CounterRotate\n rect={{\n origin: {\n x: placement.rect.origin.x * actualScale,\n y: placement.rect.origin.y * actualScale,\n },\n size: {\n width: placement.rect.size.width * actualScale,\n height: placement.rect.size.height * actualScale,\n },\n }}\n rotation={actualRotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'selection',\n pageIndex,\n },\n selected: true,\n placement,\n })\n }\n </CounterRotate>\n )}\n </>\n );\n}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","CopyToClipboard","provides","sel","useEffect","onCopyToClipboard","text","navigator","clipboard","writeText","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","build","documentId","pageIndex","scale","className","stroke","fill","plugin","selPlugin","documentState","useDocumentState","rect","setRect","useState","actualScale","useMemo","registerMarqueeOnPage","onRectChange","jsx","style","position","pointerEvents","left","origin","x","top","y","width","size","height","border","background","boxSizing","zIndex","scaleOverride","rotation","rotationOverride","selectionMenu","page","_b","_a","document","pages","rects","setRects","boundingRect","setBoundingRect","placement","setPlacement","registerSelectionOnPage","onRectsChange","onMenuPlacement","newPlacement","actualRotation","shouldRenderMenu","isVisible","jsxs","Fragment","children","mixBlendMode","isolation","map","b","i","CounterRotate","props","context","type","selected"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-selection.ts","../../src/shared/components/text-selection.tsx","../../src/shared/components/marquee-selection.tsx","../../src/shared/components/copy-to-clipboard.tsx","../../src/shared/index.ts","../../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, useMemo, useState } from '@framework';\nimport { Rect, Rotation } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\n\ntype TextSelectionProps = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n /** Background color for text selection highlights. Default: 'rgba(33,150,243)' */\n background?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\n/**\n * TextSelection renders text selection highlight rects and the selection menu.\n * It registers the text selection handler on the page and subscribes to menu\n * placement changes.\n *\n * Use this component directly for advanced cases, or use `SelectionLayer`\n * which composes both `TextSelection` and `MarqueeSelection`.\n */\nexport function TextSelection({\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n}: TextSelectionProps) {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const page = documentState?.document?.pages?.[pageIndex];\n const [rects, setRects] = useState<Rect[]>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Store the placement object from the plugin\n const [placement, setPlacement] = useState<SelectionMenuPlacement | null>(null);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects, boundingRect }) => {\n setRects(rects);\n setBoundingRect(boundingRect);\n },\n });\n }, [selPlugin, documentId, pageIndex]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n // Subscribe to menu placement changes for this specific document\n return selPlugin.onMenuPlacement(documentId, (newPlacement) => {\n setPlacement(newPlacement);\n });\n }, [selPlugin, documentId]);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotationOverride !== undefined) return rotationOverride;\n // Combine page intrinsic rotation with document rotation\n const pageRotation = page?.rotation ?? 0;\n const docRotation = documentState?.rotation ?? 0;\n return ((pageRotation + docRotation) % 4) as Rotation;\n }, [rotationOverride, page?.rotation, documentState?.rotation]);\n\n const shouldRenderMenu =\n selectionMenu && placement && placement.pageIndex === pageIndex && placement.isVisible;\n\n if (!boundingRect) return null;\n\n return (\n <>\n <div\n style={{\n position: 'absolute',\n left: boundingRect.origin.x * actualScale,\n top: boundingRect.origin.y * actualScale,\n width: boundingRect.size.width * actualScale,\n height: boundingRect.size.height * actualScale,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\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) * actualScale,\n top: (b.origin.y - boundingRect.origin.y) * actualScale,\n width: b.size.width * actualScale,\n height: b.size.height * actualScale,\n background,\n }}\n />\n ))}\n </div>\n {shouldRenderMenu && (\n <CounterRotate\n rect={{\n origin: {\n x: placement.rect.origin.x * actualScale,\n y: placement.rect.origin.y * actualScale,\n },\n size: {\n width: placement.rect.size.width * actualScale,\n height: placement.rect.size.height * actualScale,\n },\n }}\n rotation={actualRotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'selection',\n pageIndex,\n },\n selected: true,\n placement,\n })\n }\n </CounterRotate>\n )}\n </>\n );\n}\n","import { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useSelectionPlugin } from '../hooks';\n\ninterface MarqueeSelectionProps {\n /** Document ID */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page (optional, defaults to document scale) */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Fill/background color inside the marquee rectangle. Default: 'rgba(0,122,204,0.15)' */\n background?: string;\n /** Border color of the marquee rectangle. Default: 'rgba(0,122,204,0.8)' */\n borderColor?: string;\n /** Border style. Default: 'dashed' */\n borderStyle?: 'solid' | 'dashed' | 'dotted';\n /**\n * @deprecated Use `borderColor` instead.\n */\n stroke?: string;\n /**\n * @deprecated Use `background` instead.\n */\n fill?: string;\n}\n\n/**\n * MarqueeSelection renders a selection rectangle when the user drags to select items.\n * It registers the marquee handler on the page.\n *\n * Other plugins (e.g., annotation, form, redaction) can subscribe to `onMarqueeEnd` to\n * determine which objects intersect with the marquee rect.\n *\n * Use this component directly for advanced cases, or use `SelectionLayer`\n * which composes both `TextSelection` and `MarqueeSelection`.\n */\nexport const MarqueeSelection = ({\n documentId,\n pageIndex,\n scale,\n className,\n background,\n borderColor,\n borderStyle = 'dashed',\n stroke,\n fill,\n}: MarqueeSelectionProps) => {\n const { plugin: selPlugin } = useSelectionPlugin();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n // Resolve deprecated props: new CSS-standard props take precedence\n const resolvedBorderColor = borderColor ?? stroke ?? 'rgba(0,122,204,0.8)';\n const resolvedBackground = background ?? fill ?? 'rgba(0,122,204,0.15)';\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n useEffect(() => {\n if (!selPlugin || !documentId) return;\n\n return selPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n onRectChange: setRect,\n });\n }, [selPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px ${borderStyle} ${resolvedBorderColor}`,\n background: resolvedBackground,\n boxSizing: 'border-box',\n zIndex: 1000,\n }}\n className={className}\n />\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","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n","import { Fragment } from '@framework';\nimport { Rotation } from '@embedpdf/models';\nimport { TextSelectionStyle, MarqueeSelectionStyle } from '@embedpdf/plugin-selection';\nimport { SelectionSelectionMenuRenderFn } from '../types';\nimport { TextSelection } from './text-selection';\nimport { MarqueeSelection } from './marquee-selection';\n\ntype Props = {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n /**\n * @deprecated Use `textStyle.background` instead.\n */\n background?: string;\n /** Styling options for text selection highlights */\n textStyle?: TextSelectionStyle;\n /** Styling options for the marquee selection rectangle */\n marqueeStyle?: MarqueeSelectionStyle;\n /** Optional CSS class applied to the marquee rectangle */\n marqueeClassName?: string;\n selectionMenu?: SelectionSelectionMenuRenderFn;\n};\n\n/**\n * SelectionLayer is a convenience component that composes both text selection\n * and marquee selection on a single page.\n *\n * For advanced use cases, you can use `TextSelection` and `MarqueeSelection`\n * individually.\n */\nexport function SelectionLayer({\n documentId,\n pageIndex,\n scale,\n rotation,\n background,\n textStyle,\n marqueeStyle,\n marqueeClassName,\n selectionMenu,\n}: Props) {\n return (\n <Fragment>\n <TextSelection\n documentId={documentId}\n pageIndex={pageIndex}\n scale={scale}\n rotation={rotation}\n background={textStyle?.background ?? background}\n selectionMenu={selectionMenu}\n />\n <MarqueeSelection\n documentId={documentId}\n pageIndex={pageIndex}\n scale={scale}\n background={marqueeStyle?.background}\n borderColor={marqueeStyle?.borderColor}\n borderStyle={marqueeStyle?.borderStyle}\n className={marqueeClassName}\n />\n </Fragment>\n );\n}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","TextSelection","documentId","pageIndex","scale","scaleOverride","rotation","rotationOverride","background","selectionMenu","plugin","selPlugin","documentState","useDocumentState","page","_b","_a","document","pages","rects","setRects","useState","boundingRect","setBoundingRect","placement","setPlacement","useEffect","registerSelectionOnPage","onRectsChange","onMenuPlacement","newPlacement","actualScale","useMemo","actualRotation","shouldRenderMenu","isVisible","jsxs","Fragment","children","jsx","style","position","left","origin","x","top","y","width","size","height","mixBlendMode","isolation","pointerEvents","map","b","i","CounterRotate","rect","props","context","type","selected","MarqueeSelection","className","borderColor","borderStyle","stroke","fill","setRect","resolvedBorderColor","resolvedBackground","registerMarqueeOnPage","onRectChange","border","boxSizing","zIndex","CopyToClipboard","provides","sel","onCopyToClipboard","text","navigator","clipboard","writeText","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","build","textStyle","marqueeStyle","marqueeClassName"],"mappings":"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"}