@embedpdf/plugin-selection 1.5.0 → 2.0.0-next.0

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 (44) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +445 -166
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +61 -24
  6. package/dist/lib/reducer.d.ts +2 -1
  7. package/dist/lib/selection-plugin.d.ts +25 -5
  8. package/dist/lib/selectors.d.ts +7 -7
  9. package/dist/lib/types.d.ts +62 -9
  10. package/dist/preact/index.cjs +1 -1
  11. package/dist/preact/index.cjs.map +1 -1
  12. package/dist/preact/index.js +88 -34
  13. package/dist/preact/index.js.map +1 -1
  14. package/dist/preact/utils.d.ts +1 -0
  15. package/dist/react/index.cjs +1 -1
  16. package/dist/react/index.cjs.map +1 -1
  17. package/dist/react/index.js +88 -34
  18. package/dist/react/index.js.map +1 -1
  19. package/dist/react/utils.d.ts +1 -0
  20. package/dist/shared/components/selection-layer.d.ts +7 -2
  21. package/dist/shared/index.d.ts +1 -0
  22. package/dist/shared/types.d.ts +7 -0
  23. package/dist/shared-preact/components/selection-layer.d.ts +7 -2
  24. package/dist/shared-preact/index.d.ts +1 -0
  25. package/dist/shared-preact/types.d.ts +7 -0
  26. package/dist/shared-react/components/selection-layer.d.ts +7 -2
  27. package/dist/shared-react/index.d.ts +1 -0
  28. package/dist/shared-react/types.d.ts +7 -0
  29. package/dist/svelte/components/SelectionLayer.svelte.d.ts +13 -2
  30. package/dist/svelte/index.cjs +1 -1
  31. package/dist/svelte/index.cjs.map +1 -1
  32. package/dist/svelte/index.d.ts +1 -0
  33. package/dist/svelte/index.js +162 -34
  34. package/dist/svelte/index.js.map +1 -1
  35. package/dist/svelte/types.d.ts +7 -0
  36. package/dist/vue/components/copy-to-clipboard.vue.d.ts +2 -1
  37. package/dist/vue/components/selection-layer.vue.d.ts +27 -3
  38. package/dist/vue/index.cjs +1 -1
  39. package/dist/vue/index.cjs.map +1 -1
  40. package/dist/vue/index.d.ts +1 -0
  41. package/dist/vue/index.js +137 -43
  42. package/dist/vue/index.js.map +1 -1
  43. package/dist/vue/types.d.ts +7 -0
  44. package/package.json +9 -8
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-selection.svelte.ts","../../src/svelte/components/CopyToClipboard.svelte","../../src/svelte/index.ts","../../src/svelte/components/SelectionLayer.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<script lang=\"ts\">\n import { useSelectionCapability } from '../hooks/use-selection.svelte';\n\n const selectionCapability = useSelectionCapability();\n\n $effect(() => {\n if (!selectionCapability.provides) return;\n\n return selectionCapability.provides.onCopyToClipboard((text) => {\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('Failed to copy text to clipboard:', err);\n });\n });\n });\n</script>\n\n<!-- This component renders nothing to the DOM -->\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 '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n","<script lang=\"ts\">\n import type { Rect } from '@embedpdf/models';\n import { useSelectionPlugin } from '../hooks/use-selection.svelte';\n\n interface SelectionLayerProps {\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale: number;\n /** Background color for selection rectangles */\n background?: string;\n }\n\n let { pageIndex, scale, background = 'rgba(33, 150, 243, 0.4)' }: SelectionLayerProps = $props();\n\n const selectionPlugin = useSelectionPlugin();\n let rects = $state<Rect[]>([]);\n let boundingRect = $state<Rect | null>(null);\n\n $effect(() => {\n // Track pageIndex as dependency\n const _pageIndex = pageIndex;\n\n if (!selectionPlugin.plugin) return;\n\n return selectionPlugin.plugin.registerSelectionOnPage({\n pageIndex: _pageIndex,\n onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n rects = newRects;\n boundingRect = newBoundingRect;\n },\n });\n });\n</script>\n\n{#if boundingRect}\n <div\n style:position=\"absolute\"\n style:left={`${boundingRect.origin.x * scale}px`}\n style:top={`${boundingRect.origin.y * scale}px`}\n style:width={`${boundingRect.size.width * scale}px`}\n style:height={`${boundingRect.size.height * scale}px`}\n style:mix-blend-mode=\"multiply\"\n style:isolation=\"isolate\"\n style:pointer-events=\"none\"\n >\n {#each rects as rect, i (i)}\n <div\n style:position=\"absolute\"\n style:left={`${(rect.origin.x - boundingRect.origin.x) * scale}px`}\n style:top={`${(rect.origin.y - boundingRect.origin.y) * scale}px`}\n style:width={`${rect.size.width * scale}px`}\n style:height={`${rect.size.height * scale}px`}\n style:background\n style:pointer-events=\"none\"\n ></div>\n {/each}\n </div>\n{/if}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","selectionCapability","$","user_effect","provides","onCopyToClipboard","text","navigator","clipboard","writeText","catch","err","console","error","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","CopyToClipboard","build","background","selectionPlugin","rects","state","proxy","boundingRect","_pageIndex","$$props","pageIndex","plugin","registerSelectionOnPage","onRectsChange","newRects","newBoundingRect","$__namespace","set","each","div","get","rect","origin","x","scale","y","size","width","height","consequent"],"mappings":"2iBAOaA,EAA+B,IAAAC,gBAA+BC,EAAAA,gBAAgBC,IAM9EC,EAA2B,IAAAC,YAA2BH,EAAAA,gBAAgBC,+FCV3E,MAAAG,EAAsBN,IAE5BO,EAAAC,aAAc,KACP,GAAAF,EAAoBG,SAElB,OAAAH,EAAoBG,SAASC,mBAAmBC,IACrDC,UAAUC,UAAUC,UAAUH,GAAMI,OAAOC,IACjCC,QAAAC,MAAM,oCAAqCF,EAAG,GACvD,GACF,WAEL,CCLO,MAAMG,EAAyBC,EAAoBA,oBAAAC,EAA0BF,wBACjFG,WAAWC,GACXC,oFCEuB,IAAAC,0BAAa,2BAE/B,MAAAC,EAAkBtB,QACpBuB,EAAKpB,EAAAqB,MAAArB,EAAAsB,MAAA,KACLC,UAAmC,MAEvCvB,EAAAC,aAAc,WAENuB,EAAUC,EAAAC,UAEX,GAAAP,EAAgBQ,OAEd,OAAAR,EAAgBQ,OAAOC,wBAAuB,CACnDF,UAAWF,EACXK,cAAa,EAAKT,MAAOU,EAAUP,aAAcQ,MAC/CC,EAAAC,IAAAb,EAAQU,GAAQ,GAChBE,EAAAC,IAAAV,EAAeQ,GAAe,EAAA,kEAiB3B/B,EAAAkC,KAAAC,EAAA,IAAA,IAAAnC,EAAAoC,IAAAhB,gBAASiB,2GAGIA,GAAKC,OAAOC,QAAIhB,GAAae,OAAOC,GAACd,EAAAe,sBACtCH,GAAKC,OAAOG,QAAIlB,GAAae,OAAOG,GAAChB,EAAAe,uBACpCH,GAAKK,KAAKC,MAAKlB,EAAAe,wBACdH,GAAKK,KAAKE,OAAMnB,EAAAe,uKAdtBjB,GAAae,OAAOC,EAACd,EAAAe,qBACtBjB,GAAae,OAAOG,EAAChB,EAAAe,uBACnBjB,GAAamB,KAAKC,MAAKlB,EAAAe,wBACtBjB,GAAamB,KAAKE,OAAMnB,EAAAe,wHANxCjB,MAAYsB,EAAA,yBAFjB"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-selection.svelte.ts","../../src/svelte/components/CopyToClipboard.svelte","../../src/svelte/index.ts","../../src/svelte/components/SelectionLayer.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<script lang=\"ts\">\n import { useSelectionCapability } from '../hooks/use-selection.svelte';\n\n const selectionCapability = useSelectionCapability();\n\n $effect(() => {\n if (!selectionCapability.provides) return;\n\n return selectionCapability.provides.onCopyToClipboard(({ text }) => {\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('Failed to copy text to clipboard:', err);\n });\n });\n });\n</script>\n\n<!-- This component renders nothing to the DOM -->\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","<script lang=\"ts\">\n import { Snippet } from 'svelte';\n import type { Rect } from '@embedpdf/models';\n import { Rotation } from '@embedpdf/models';\n import { useDocumentState } from '@embedpdf/core/svelte';\n import { CounterRotate, MenuWrapperProps, SelectionMenuPlacement } from '@embedpdf/utils/svelte';\n import { useSelectionPlugin } from '../hooks/use-selection.svelte';\n import type {\n SelectionSelectionMenuRenderFn,\n SelectionSelectionMenuProps,\n SelectionSelectionContext,\n } from '../types';\n import type { SelectionMenuPlacement as UtilsSelectionMenuPlacement } from '@embedpdf/plugin-selection';\n\n interface SelectionLayerProps {\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 /** Rotation of the page (optional, defaults to document rotation) */\n rotation?: Rotation;\n /** Background color for selection rectangles */\n background?: string;\n /** Render function for selection menu (schema-driven approach) */\n selectionMenu?: SelectionSelectionMenuRenderFn;\n /** Snippet for custom selection menu (slot-based approach) */\n selectionMenuSnippet?: Snippet<[SelectionSelectionMenuProps]>;\n }\n\n let {\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n selectionMenuSnippet,\n }: SelectionLayerProps = $props();\n\n const selectionPlugin = useSelectionPlugin();\n const documentState = useDocumentState(() => documentId);\n\n let rects = $state<Rect[]>([]);\n let boundingRect = $state<Rect | null>(null);\n let placement = $state<UtilsSelectionMenuPlacement | null>(null);\n\n const actualScale = $derived(\n scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n );\n\n const actualRotation = $derived(\n rotationOverride !== undefined\n ? rotationOverride\n : (documentState.current?.rotation ?? Rotation.Degree0),\n );\n\n // Check if menu should render: placement is valid AND (render fn OR snippet exists)\n const shouldRenderMenu = $derived(\n Boolean(\n placement &&\n placement.pageIndex === pageIndex &&\n placement.isVisible &&\n (selectionMenu || selectionMenuSnippet),\n ),\n );\n\n // Track selection rectangles on this page\n $effect(() => {\n if (!selectionPlugin.plugin || !documentId) {\n rects = [];\n boundingRect = null;\n return;\n }\n\n return selectionPlugin.plugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n rects = newRects;\n boundingRect = newBoundingRect;\n },\n });\n });\n\n // Track menu placement for this document\n $effect(() => {\n if (!selectionPlugin.plugin || !documentId) {\n placement = null;\n return;\n }\n\n return selectionPlugin.plugin.onMenuPlacement(documentId, (newPlacement) => {\n placement = newPlacement;\n });\n });\n\n // --- Selection Menu Logic ---\n\n // Build context object for selection menu\n function buildContext(): SelectionSelectionContext {\n return {\n type: 'selection',\n pageIndex,\n };\n }\n\n // Build placement hints from plugin placement data\n function buildMenuPlacement(): SelectionMenuPlacement {\n return {\n suggestTop: placement?.suggestTop ?? false,\n spaceAbove: placement?.spaceAbove ?? 0,\n spaceBelow: placement?.spaceBelow ?? 0,\n };\n }\n\n // Build menu props\n function buildMenuProps(\n rect: Rect,\n menuWrapperProps: MenuWrapperProps,\n ): SelectionSelectionMenuProps {\n return {\n context: buildContext(),\n selected: true, // Selection is always \"selected\" when visible\n rect,\n placement: buildMenuPlacement(),\n menuWrapperProps,\n };\n }\n</script>\n\n{#if boundingRect}\n <!-- Highlight layer -->\n <div\n style:position=\"absolute\"\n style:left={`${boundingRect.origin.x * actualScale}px`}\n style:top={`${boundingRect.origin.y * actualScale}px`}\n style:width={`${boundingRect.size.width * actualScale}px`}\n style:height={`${boundingRect.size.height * actualScale}px`}\n style:mix-blend-mode=\"multiply\"\n style:isolation=\"isolate\"\n style:pointer-events=\"none\"\n >\n {#each rects as rect, i (i)}\n <div\n style:position=\"absolute\"\n style:left={`${(rect.origin.x - boundingRect.origin.x) * actualScale}px`}\n style:top={`${(rect.origin.y - boundingRect.origin.y) * actualScale}px`}\n style:width={`${rect.size.width * actualScale}px`}\n style:height={`${rect.size.height * actualScale}px`}\n style:background\n style:pointer-events=\"none\"\n ></div>\n {/each}\n </div>\n\n <!-- Selection menu (counter-rotated) -->\n {#if shouldRenderMenu && placement}\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 {#snippet children({ rect, menuWrapperProps })}\n {@const menuProps = buildMenuProps(rect, menuWrapperProps)}\n {#if selectionMenu}\n <!-- Priority 1: Render function (schema-driven) -->\n {@const result = selectionMenu(menuProps)}\n {#if result}\n <result.component {...result.props} />\n {/if}\n {:else if selectionMenuSnippet}\n <!-- Priority 2: Snippet (manual customization) -->\n {@render selectionMenuSnippet(menuProps)}\n {/if}\n {/snippet}\n </CounterRotate>\n {/if}\n{/if}\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","selectionCapability","$","user_effect","provides","onCopyToClipboard","text","navigator","clipboard","writeText","catch","err","console","error","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","CopyToClipboard","build","background","selectionPlugin","documentState","useDocumentState","$$props","documentId","rects","state","proxy","boundingRect","placement","actualScale","derived","scale","_a","current","actualRotation","rotation","Rotation","Degree0","shouldRenderMenu","Boolean","get","pageIndex","isVisible","selectionMenu","selectionMenuSnippet","plugin","registerSelectionOnPage","onRectsChange","newRects","newBoundingRect","set","onMenuPlacement","newPlacement","each","div","rect","origin","x","y","width","size","height","menuProps","menuWrapperProps","context","type","selected","suggestTop","spaceAbove","spaceBelow","buildMenuProps","result","result_component","$$anchor","spread_props","props","consequent","$$render","consequent_3","left","top","consequent_4"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
+ export * from './types';
3
4
  export * from '../lib/index.ts';
4
5
  export declare const SelectionPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').SelectionPlugin, import('../lib/index.ts').SelectionPluginConfig, import('../lib/index.ts').SelectionState, import('src/lib/actions').SelectionAction>>;
@@ -3,67 +3,195 @@ import { SelectionPlugin, SelectionPluginPackage as SelectionPluginPackage$1 } f
3
3
  export * from "@embedpdf/plugin-selection";
4
4
  import "svelte/internal/disclose-version";
5
5
  import * as $ from "svelte/internal/client";
6
- import { useCapability, usePlugin } from "@embedpdf/core/svelte";
6
+ import "svelte";
7
+ import { Rotation } from "@embedpdf/models";
8
+ import { useCapability, usePlugin, useDocumentState } from "@embedpdf/core/svelte";
9
+ import { CounterRotate } from "@embedpdf/utils/svelte";
7
10
  const useSelectionCapability = () => useCapability(SelectionPlugin.id);
8
11
  const useSelectionPlugin = () => usePlugin(SelectionPlugin.id);
9
12
  var root_2 = $.from_html(`<div></div>`);
10
- var root_1 = $.from_html(`<div></div>`);
13
+ var root_1 = $.from_html(`<div></div> <!>`, 1);
11
14
  function SelectionLayer($$anchor, $$props) {
12
15
  $.push($$props, true);
13
- let background = $.prop($$props, "background", 3, "rgba(33, 150, 243, 0.4)");
16
+ let background = $.prop($$props, "background", 3, "rgba(33,150,243)");
14
17
  const selectionPlugin = useSelectionPlugin();
18
+ const documentState = useDocumentState(() => $$props.documentId);
15
19
  let rects = $.state($.proxy([]));
16
20
  let boundingRect = $.state(null);
21
+ let placement = $.state(null);
22
+ const actualScale = $.derived(() => {
23
+ var _a;
24
+ return $$props.scale !== void 0 ? $$props.scale : ((_a = documentState.current) == null ? void 0 : _a.scale) ?? 1;
25
+ });
26
+ const actualRotation = $.derived(() => {
27
+ var _a;
28
+ return $$props.rotation !== void 0 ? $$props.rotation : ((_a = documentState.current) == null ? void 0 : _a.rotation) ?? Rotation.Degree0;
29
+ });
30
+ const shouldRenderMenu = $.derived(() => Boolean($.get(placement) && $.get(placement).pageIndex === $$props.pageIndex && $.get(placement).isVisible && ($$props.selectionMenu || $$props.selectionMenuSnippet)));
17
31
  $.user_effect(() => {
18
- const _pageIndex = $$props.pageIndex;
19
- if (!selectionPlugin.plugin) return;
32
+ if (!selectionPlugin.plugin || !$$props.documentId) {
33
+ $.set(rects, [], true);
34
+ $.set(boundingRect, null);
35
+ return;
36
+ }
20
37
  return selectionPlugin.plugin.registerSelectionOnPage({
21
- pageIndex: _pageIndex,
38
+ documentId: $$props.documentId,
39
+ pageIndex: $$props.pageIndex,
22
40
  onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {
23
41
  $.set(rects, newRects, true);
24
42
  $.set(boundingRect, newBoundingRect, true);
25
43
  }
26
44
  });
27
45
  });
46
+ $.user_effect(() => {
47
+ if (!selectionPlugin.plugin || !$$props.documentId) {
48
+ $.set(placement, null);
49
+ return;
50
+ }
51
+ return selectionPlugin.plugin.onMenuPlacement($$props.documentId, (newPlacement) => {
52
+ $.set(placement, newPlacement, true);
53
+ });
54
+ });
55
+ function buildContext() {
56
+ return { type: "selection", pageIndex: $$props.pageIndex };
57
+ }
58
+ function buildMenuPlacement() {
59
+ var _a, _b, _c;
60
+ return {
61
+ suggestTop: ((_a = $.get(placement)) == null ? void 0 : _a.suggestTop) ?? false,
62
+ spaceAbove: ((_b = $.get(placement)) == null ? void 0 : _b.spaceAbove) ?? 0,
63
+ spaceBelow: ((_c = $.get(placement)) == null ? void 0 : _c.spaceBelow) ?? 0
64
+ };
65
+ }
66
+ function buildMenuProps(rect, menuWrapperProps) {
67
+ return {
68
+ context: buildContext(),
69
+ selected: true,
70
+ // Selection is always "selected" when visible
71
+ rect,
72
+ placement: buildMenuPlacement(),
73
+ menuWrapperProps
74
+ };
75
+ }
28
76
  var fragment = $.comment();
29
77
  var node = $.first_child(fragment);
30
78
  {
31
- var consequent = ($$anchor2) => {
32
- var div = root_1();
79
+ var consequent_4 = ($$anchor2) => {
80
+ var fragment_1 = root_1();
81
+ var div = $.first_child(fragment_1);
33
82
  let styles;
34
83
  $.each(div, 21, () => $.get(rects), $.index, ($$anchor3, rect) => {
35
84
  var div_1 = root_2();
36
85
  let styles_1;
37
- $.template_effect(($0) => styles_1 = $.set_style(div_1, "", styles_1, $0), [
38
- () => ({
39
- position: "absolute",
40
- left: `${($.get(rect).origin.x - $.get(boundingRect).origin.x) * $$props.scale}px`,
41
- top: `${($.get(rect).origin.y - $.get(boundingRect).origin.y) * $$props.scale}px`,
42
- width: `${$.get(rect).size.width * $$props.scale}px`,
43
- height: `${$.get(rect).size.height * $$props.scale}px`,
44
- background: background(),
45
- "pointer-events": "none"
46
- })
47
- ]);
86
+ $.template_effect(() => styles_1 = $.set_style(div_1, "", styles_1, {
87
+ position: "absolute",
88
+ left: `${($.get(rect).origin.x - $.get(boundingRect).origin.x) * $.get(actualScale)}px`,
89
+ top: `${($.get(rect).origin.y - $.get(boundingRect).origin.y) * $.get(actualScale)}px`,
90
+ width: `${$.get(rect).size.width * $.get(actualScale)}px`,
91
+ height: `${$.get(rect).size.height * $.get(actualScale)}px`,
92
+ background: background(),
93
+ "pointer-events": "none"
94
+ }));
48
95
  $.append($$anchor3, div_1);
49
96
  });
50
97
  $.reset(div);
51
- $.template_effect(($0) => styles = $.set_style(div, "", styles, $0), [
52
- () => ({
53
- position: "absolute",
54
- left: `${$.get(boundingRect).origin.x * $$props.scale}px`,
55
- top: `${$.get(boundingRect).origin.y * $$props.scale}px`,
56
- width: `${$.get(boundingRect).size.width * $$props.scale}px`,
57
- height: `${$.get(boundingRect).size.height * $$props.scale}px`,
58
- "mix-blend-mode": "multiply",
59
- isolation: "isolate",
60
- "pointer-events": "none"
61
- })
62
- ]);
63
- $.append($$anchor2, div);
98
+ var node_1 = $.sibling(div, 2);
99
+ {
100
+ var consequent_3 = ($$anchor3) => {
101
+ {
102
+ const children = ($$anchor4, $$arg0) => {
103
+ let rect = () => $$arg0 == null ? void 0 : $$arg0().rect;
104
+ let menuWrapperProps = () => $$arg0 == null ? void 0 : $$arg0().menuWrapperProps;
105
+ const menuProps = $.derived(() => buildMenuProps(rect(), menuWrapperProps()));
106
+ var fragment_3 = $.comment();
107
+ var node_2 = $.first_child(fragment_3);
108
+ {
109
+ var consequent_1 = ($$anchor5) => {
110
+ const result = $.derived(() => $$props.selectionMenu($.get(menuProps)));
111
+ var fragment_4 = $.comment();
112
+ var node_3 = $.first_child(fragment_4);
113
+ {
114
+ var consequent = ($$anchor6) => {
115
+ var fragment_5 = $.comment();
116
+ var node_4 = $.first_child(fragment_5);
117
+ $.component(node_4, () => $.get(result).component, ($$anchor7, result_component) => {
118
+ result_component($$anchor7, $.spread_props(() => $.get(result).props));
119
+ });
120
+ $.append($$anchor6, fragment_5);
121
+ };
122
+ $.if(node_3, ($$render) => {
123
+ if ($.get(result)) $$render(consequent);
124
+ });
125
+ }
126
+ $.append($$anchor5, fragment_4);
127
+ };
128
+ var alternate = ($$anchor5) => {
129
+ var fragment_6 = $.comment();
130
+ var node_5 = $.first_child(fragment_6);
131
+ {
132
+ var consequent_2 = ($$anchor6) => {
133
+ var fragment_7 = $.comment();
134
+ var node_6 = $.first_child(fragment_7);
135
+ $.snippet(node_6, () => $$props.selectionMenuSnippet, () => $.get(menuProps));
136
+ $.append($$anchor6, fragment_7);
137
+ };
138
+ $.if(
139
+ node_5,
140
+ ($$render) => {
141
+ if ($$props.selectionMenuSnippet) $$render(consequent_2);
142
+ },
143
+ true
144
+ );
145
+ }
146
+ $.append($$anchor5, fragment_6);
147
+ };
148
+ $.if(node_2, ($$render) => {
149
+ if ($$props.selectionMenu) $$render(consequent_1);
150
+ else $$render(alternate, false);
151
+ });
152
+ }
153
+ $.append($$anchor4, fragment_3);
154
+ };
155
+ let $0 = $.derived(() => ({
156
+ origin: {
157
+ x: $.get(placement).rect.origin.x * $.get(actualScale),
158
+ y: $.get(placement).rect.origin.y * $.get(actualScale)
159
+ },
160
+ size: {
161
+ width: $.get(placement).rect.size.width * $.get(actualScale),
162
+ height: $.get(placement).rect.size.height * $.get(actualScale)
163
+ }
164
+ }));
165
+ CounterRotate($$anchor3, {
166
+ get rect() {
167
+ return $.get($0);
168
+ },
169
+ get rotation() {
170
+ return $.get(actualRotation);
171
+ },
172
+ children,
173
+ $$slots: { default: true }
174
+ });
175
+ }
176
+ };
177
+ $.if(node_1, ($$render) => {
178
+ if ($.get(shouldRenderMenu) && $.get(placement)) $$render(consequent_3);
179
+ });
180
+ }
181
+ $.template_effect(() => styles = $.set_style(div, "", styles, {
182
+ position: "absolute",
183
+ left: `${$.get(boundingRect).origin.x * $.get(actualScale)}px`,
184
+ top: `${$.get(boundingRect).origin.y * $.get(actualScale)}px`,
185
+ width: `${$.get(boundingRect).size.width * $.get(actualScale)}px`,
186
+ height: `${$.get(boundingRect).size.height * $.get(actualScale)}px`,
187
+ "mix-blend-mode": "multiply",
188
+ isolation: "isolate",
189
+ "pointer-events": "none"
190
+ }));
191
+ $.append($$anchor2, fragment_1);
64
192
  };
65
193
  $.if(node, ($$render) => {
66
- if ($.get(boundingRect)) $$render(consequent);
194
+ if ($.get(boundingRect)) $$render(consequent_4);
67
195
  });
68
196
  }
69
197
  $.append($$anchor, fragment);
@@ -74,7 +202,7 @@ function CopyToClipboard($$anchor, $$props) {
74
202
  const selectionCapability = useSelectionCapability();
75
203
  $.user_effect(() => {
76
204
  if (!selectionCapability.provides) return;
77
- return selectionCapability.provides.onCopyToClipboard((text) => {
205
+ return selectionCapability.provides.onCopyToClipboard(({ text }) => {
78
206
  navigator.clipboard.writeText(text).catch((err) => {
79
207
  console.error("Failed to copy text to clipboard:", err);
80
208
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/svelte/hooks/use-selection.svelte.ts","../../src/svelte/components/SelectionLayer.svelte","../../src/svelte/components/CopyToClipboard.svelte","../../src/svelte/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<script lang=\"ts\">\n import type { Rect } from '@embedpdf/models';\n import { useSelectionPlugin } from '../hooks/use-selection.svelte';\n\n interface SelectionLayerProps {\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale: number;\n /** Background color for selection rectangles */\n background?: string;\n }\n\n let { pageIndex, scale, background = 'rgba(33, 150, 243, 0.4)' }: SelectionLayerProps = $props();\n\n const selectionPlugin = useSelectionPlugin();\n let rects = $state<Rect[]>([]);\n let boundingRect = $state<Rect | null>(null);\n\n $effect(() => {\n // Track pageIndex as dependency\n const _pageIndex = pageIndex;\n\n if (!selectionPlugin.plugin) return;\n\n return selectionPlugin.plugin.registerSelectionOnPage({\n pageIndex: _pageIndex,\n onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n rects = newRects;\n boundingRect = newBoundingRect;\n },\n });\n });\n</script>\n\n{#if boundingRect}\n <div\n style:position=\"absolute\"\n style:left={`${boundingRect.origin.x * scale}px`}\n style:top={`${boundingRect.origin.y * scale}px`}\n style:width={`${boundingRect.size.width * scale}px`}\n style:height={`${boundingRect.size.height * scale}px`}\n style:mix-blend-mode=\"multiply\"\n style:isolation=\"isolate\"\n style:pointer-events=\"none\"\n >\n {#each rects as rect, i (i)}\n <div\n style:position=\"absolute\"\n style:left={`${(rect.origin.x - boundingRect.origin.x) * scale}px`}\n style:top={`${(rect.origin.y - boundingRect.origin.y) * scale}px`}\n style:width={`${rect.size.width * scale}px`}\n style:height={`${rect.size.height * scale}px`}\n style:background\n style:pointer-events=\"none\"\n ></div>\n {/each}\n </div>\n{/if}\n","<script lang=\"ts\">\n import { useSelectionCapability } from '../hooks/use-selection.svelte';\n\n const selectionCapability = useSelectionCapability();\n\n $effect(() => {\n if (!selectionCapability.provides) return;\n\n return selectionCapability.provides.onCopyToClipboard((text) => {\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('Failed to copy text to clipboard:', err);\n });\n });\n });\n</script>\n\n<!-- This component renders nothing to the DOM -->\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 '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n"],"names":["BaseSelectionPluginPackage"],"mappings":";;;;;;AAOa,MAAA,yBAA+B,MAAA,cAA+B,gBAAgB,EAAE;AAMhF,MAAA,qBAA2B,MAAA,UAA2B,gBAAgB,EAAE;;;2CCbrF;;AAa0B,MAAA,8CAAa,yBAAyB;AAExD,QAAA,kBAAkB,mBAAkB;MACtC,QAAK,EAAA,MAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AACL,MAAA,uBAAmC,IAAI;AAE3C,IAAA,YAAc,MAAA;UAEN,aAAU,QAAA;AAEX,QAAA,CAAA,gBAAgB,OAAM;WAEpB,gBAAgB,OAAO,wBAAuB;AAAA,MACnD,WAAW;AAAA,MACX,eAAa,CAAA,EAAK,OAAO,UAAU,cAAc,gBAAe,MAAO;AACrE,UAAA,IAAA,OAAQ,UAAQ,IAAA;AAChB,UAAA,IAAA,cAAe,iBAAe,IAAA;AAAA;;GAGnC;;;;;;;AAcQ,QAAA,KAAA,KAAA,IAAA,MAAA,EAAA,IAAA,KAAK,wBAAI,SAAI;;;;;;4BAGA,IAAI,EAAC,OAAO,UAAI,YAAY,EAAC,OAAO,KAAC,QAAA,KAAA;AAAA,2BACtC,IAAI,EAAC,OAAO,UAAI,YAAY,EAAC,OAAO,KAAC,QAAA,KAAA;AAAA,4BACpC,IAAI,EAAC,KAAK,QAAK,QAAA,KAAA;AAAA,6BACd,IAAI,EAAC,KAAK,SAAM,QAAA,KAAA;AAAA;;;;;;;;;;yBAdtB,YAAY,EAAC,OAAO,IAAC,QAAA,KAAA;AAAA,wBACtB,YAAY,EAAC,OAAO,IAAC,QAAA,KAAA;AAAA,0BACnB,YAAY,EAAC,KAAK,QAAK,QAAA,KAAA;AAAA,2BACtB,YAAY,EAAC,KAAK,SAAM,QAAA,KAAA;AAAA;;;;;;;;gBANxC,YAAY,EAAA,UAAA,UAAA;AAAA;;;;AAFjB;4CCjCA;;AAGQ,QAAA,sBAAsB,uBAAsB;AAElD,IAAA,YAAc,MAAA;AACP,QAAA,CAAA,oBAAoB,SAAQ;AAE1B,WAAA,oBAAoB,SAAS,kBAAiB,CAAE,SAAS;AAC9D,gBAAU,UAAU,UAAU,IAAI,EAAE,MAAO,CAAA,QAAQ;AACjD,gBAAQ,MAAM,qCAAqC,GAAG;AAAA,OACvD;AAAA,KACF;AAAA,GACF;;AACH;ACLO,MAAM,yBAAyB,oBAAoBA,wBAA0B,EACjF,WAAW,eAAe,EAC1B,MAAM;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/svelte/hooks/use-selection.svelte.ts","../../src/svelte/components/SelectionLayer.svelte","../../src/svelte/components/CopyToClipboard.svelte","../../src/svelte/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<script lang=\"ts\">\n import { Snippet } from 'svelte';\n import type { Rect } from '@embedpdf/models';\n import { Rotation } from '@embedpdf/models';\n import { useDocumentState } from '@embedpdf/core/svelte';\n import { CounterRotate, MenuWrapperProps, SelectionMenuPlacement } from '@embedpdf/utils/svelte';\n import { useSelectionPlugin } from '../hooks/use-selection.svelte';\n import type {\n SelectionSelectionMenuRenderFn,\n SelectionSelectionMenuProps,\n SelectionSelectionContext,\n } from '../types';\n import type { SelectionMenuPlacement as UtilsSelectionMenuPlacement } from '@embedpdf/plugin-selection';\n\n interface SelectionLayerProps {\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 /** Rotation of the page (optional, defaults to document rotation) */\n rotation?: Rotation;\n /** Background color for selection rectangles */\n background?: string;\n /** Render function for selection menu (schema-driven approach) */\n selectionMenu?: SelectionSelectionMenuRenderFn;\n /** Snippet for custom selection menu (slot-based approach) */\n selectionMenuSnippet?: Snippet<[SelectionSelectionMenuProps]>;\n }\n\n let {\n documentId,\n pageIndex,\n scale: scaleOverride,\n rotation: rotationOverride,\n background = 'rgba(33,150,243)',\n selectionMenu,\n selectionMenuSnippet,\n }: SelectionLayerProps = $props();\n\n const selectionPlugin = useSelectionPlugin();\n const documentState = useDocumentState(() => documentId);\n\n let rects = $state<Rect[]>([]);\n let boundingRect = $state<Rect | null>(null);\n let placement = $state<UtilsSelectionMenuPlacement | null>(null);\n\n const actualScale = $derived(\n scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n );\n\n const actualRotation = $derived(\n rotationOverride !== undefined\n ? rotationOverride\n : (documentState.current?.rotation ?? Rotation.Degree0),\n );\n\n // Check if menu should render: placement is valid AND (render fn OR snippet exists)\n const shouldRenderMenu = $derived(\n Boolean(\n placement &&\n placement.pageIndex === pageIndex &&\n placement.isVisible &&\n (selectionMenu || selectionMenuSnippet),\n ),\n );\n\n // Track selection rectangles on this page\n $effect(() => {\n if (!selectionPlugin.plugin || !documentId) {\n rects = [];\n boundingRect = null;\n return;\n }\n\n return selectionPlugin.plugin.registerSelectionOnPage({\n documentId,\n pageIndex,\n onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n rects = newRects;\n boundingRect = newBoundingRect;\n },\n });\n });\n\n // Track menu placement for this document\n $effect(() => {\n if (!selectionPlugin.plugin || !documentId) {\n placement = null;\n return;\n }\n\n return selectionPlugin.plugin.onMenuPlacement(documentId, (newPlacement) => {\n placement = newPlacement;\n });\n });\n\n // --- Selection Menu Logic ---\n\n // Build context object for selection menu\n function buildContext(): SelectionSelectionContext {\n return {\n type: 'selection',\n pageIndex,\n };\n }\n\n // Build placement hints from plugin placement data\n function buildMenuPlacement(): SelectionMenuPlacement {\n return {\n suggestTop: placement?.suggestTop ?? false,\n spaceAbove: placement?.spaceAbove ?? 0,\n spaceBelow: placement?.spaceBelow ?? 0,\n };\n }\n\n // Build menu props\n function buildMenuProps(\n rect: Rect,\n menuWrapperProps: MenuWrapperProps,\n ): SelectionSelectionMenuProps {\n return {\n context: buildContext(),\n selected: true, // Selection is always \"selected\" when visible\n rect,\n placement: buildMenuPlacement(),\n menuWrapperProps,\n };\n }\n</script>\n\n{#if boundingRect}\n <!-- Highlight layer -->\n <div\n style:position=\"absolute\"\n style:left={`${boundingRect.origin.x * actualScale}px`}\n style:top={`${boundingRect.origin.y * actualScale}px`}\n style:width={`${boundingRect.size.width * actualScale}px`}\n style:height={`${boundingRect.size.height * actualScale}px`}\n style:mix-blend-mode=\"multiply\"\n style:isolation=\"isolate\"\n style:pointer-events=\"none\"\n >\n {#each rects as rect, i (i)}\n <div\n style:position=\"absolute\"\n style:left={`${(rect.origin.x - boundingRect.origin.x) * actualScale}px`}\n style:top={`${(rect.origin.y - boundingRect.origin.y) * actualScale}px`}\n style:width={`${rect.size.width * actualScale}px`}\n style:height={`${rect.size.height * actualScale}px`}\n style:background\n style:pointer-events=\"none\"\n ></div>\n {/each}\n </div>\n\n <!-- Selection menu (counter-rotated) -->\n {#if shouldRenderMenu && placement}\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 {#snippet children({ rect, menuWrapperProps })}\n {@const menuProps = buildMenuProps(rect, menuWrapperProps)}\n {#if selectionMenu}\n <!-- Priority 1: Render function (schema-driven) -->\n {@const result = selectionMenu(menuProps)}\n {#if result}\n <result.component {...result.props} />\n {/if}\n {:else if selectionMenuSnippet}\n <!-- Priority 2: Snippet (manual customization) -->\n {@render selectionMenuSnippet(menuProps)}\n {/if}\n {/snippet}\n </CounterRotate>\n {/if}\n{/if}\n","<script lang=\"ts\">\n import { useSelectionCapability } from '../hooks/use-selection.svelte';\n\n const selectionCapability = useSelectionCapability();\n\n $effect(() => {\n if (!selectionCapability.provides) return;\n\n return selectionCapability.provides.onCopyToClipboard(({ text }) => {\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('Failed to copy text to clipboard:', err);\n });\n });\n });\n</script>\n\n<!-- This component renders nothing to the DOM -->\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":["$$anchor","BaseSelectionPluginPackage"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { SelectionMenuRenderFn, SelectionMenuPropsBase } from '@embedpdf/utils/svelte';
2
+ export interface SelectionSelectionContext {
3
+ type: 'selection';
4
+ pageIndex: number;
5
+ }
6
+ export type SelectionSelectionMenuRenderFn = SelectionMenuRenderFn<SelectionSelectionContext>;
7
+ export type SelectionSelectionMenuProps = SelectionMenuPropsBase<SelectionSelectionContext>;
@@ -1,2 +1,3 @@
1
- declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
1
+ declare const __VLS_export: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
2
3
  export default _default;
@@ -1,9 +1,33 @@
1
- interface Props {
1
+ import { Rotation } from '@embedpdf/models';
2
+ import { SelectionSelectionMenuRenderFn } from '../types';
3
+ interface SelectionLayerProps {
4
+ documentId: string;
2
5
  pageIndex: number;
3
- scale: number;
6
+ scale?: number;
7
+ rotation?: Rotation;
4
8
  background?: string;
9
+ /** Render function for selection menu (schema-driven approach) */
10
+ selectionMenu?: SelectionSelectionMenuRenderFn;
5
11
  }
6
- declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
12
+ declare var __VLS_12: {
13
+ context: any;
14
+ selected: boolean;
15
+ rect: any;
16
+ placement: any;
17
+ menuWrapperProps: any;
18
+ };
19
+ type __VLS_Slots = {} & {
20
+ 'selection-menu'?: (props: typeof __VLS_12) => any;
21
+ };
22
+ declare const __VLS_base: import('vue').DefineComponent<SelectionLayerProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SelectionLayerProps> & Readonly<{}>, {
23
+ rotation: Rotation;
7
24
  background: string;
8
25
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
26
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
27
+ declare const _default: typeof __VLS_export;
9
28
  export default _default;
29
+ type __VLS_WithSlots<T, S> = T & {
30
+ new (): {
31
+ $slots: S;
32
+ };
33
+ };
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-selection"),o=require("vue"),l=require("@embedpdf/core/vue"),i=()=>l.useCapability(t.SelectionPlugin.id),n=()=>l.usePlugin(t.SelectionPlugin.id),a=o.defineComponent({__name:"selection-layer",props:{pageIndex:{},scale:{},background:{default:"rgba(33, 150, 243)"}},setup(e){const t=e,{plugin:l}=n(),i=o.ref([]),a=o.ref(null);let r;return o.onMounted((()=>{l.value&&(r=l.value.registerSelectionOnPage({pageIndex:t.pageIndex,onRectsChange:({rects:e,boundingRect:t})=>{i.value=e,a.value=t}}))})),o.onUnmounted((()=>{null==r||r()})),(e,t)=>a.value?(o.openBlock(),o.createElementBlock("div",{key:0,style:o.normalizeStyle({position:"absolute",left:a.value.origin.x*e.scale+"px",top:a.value.origin.y*e.scale+"px",width:a.value.size.width*e.scale+"px",height:a.value.size.height*e.scale+"px",mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"})},[(o.openBlock(!0),o.createElementBlock(o.Fragment,null,o.renderList(i.value,((t,l)=>(o.openBlock(),o.createElementBlock("div",{key:l,style:o.normalizeStyle({position:"absolute",left:(t.origin.x-a.value.origin.x)*e.scale+"px",top:(t.origin.y-a.value.origin.y)*e.scale+"px",width:t.size.width*e.scale+"px",height:t.size.height*e.scale+"px",background:e.background})},null,4)))),128))],4)):o.createCommentVNode("",!0)}}),r=o.defineComponent({__name:"copy-to-clipboard",setup(e){const{provides:t}=i();return o.watchEffect((e=>{if(t.value){e(t.value.onCopyToClipboard((e=>{navigator.clipboard.writeText(e).catch((e=>{console.error("Failed to copy text to clipboard:",e)}))})))}})),(e,t)=>null}}),c=e.createPluginPackage(t.SelectionPluginPackage).addUtility(r).build();exports.CopyToClipboard=r,exports.SelectionLayer=a,exports.SelectionPluginPackage=c,exports.useSelectionCapability=i,exports.useSelectionPlugin=n,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("vue"),l=require("@embedpdf/core/vue"),n=require("@embedpdf/models"),a=require("@embedpdf/utils/vue"),i=()=>l.useCapability(t.SelectionPlugin.id),u=()=>l.usePlugin(t.SelectionPlugin.id),r=o.defineComponent({__name:"selection-layer",props:{documentId:{},pageIndex:{},scale:{},rotation:{default:n.Rotation.Degree0},background:{default:"rgba(33,150,243)"},selectionMenu:{}},setup(e){const t=e,i=o.useSlots(),{plugin:r}=u(),c=l.useDocumentState(()=>t.documentId),p=o.ref([]),d=o.ref(null),s=o.ref(null),v=o.computed(()=>{var e;return void 0!==t.scale?t.scale:(null==(e=c.value)?void 0:e.scale)??1}),g=o.computed(()=>{var e;return void 0!==t.rotation?t.rotation:(null==(e=c.value)?void 0:e.rotation)??n.Rotation.Degree0}),m=o.computed(()=>!!s.value&&(s.value.pageIndex===t.pageIndex&&(!!s.value.isVisible&&(!!t.selectionMenu||!!i["selection-menu"]))));o.watch([()=>r.value,()=>t.documentId,()=>t.pageIndex],([e,t,o],l,n)=>{if(!e||!t)return p.value=[],void(d.value=null);n(e.registerSelectionOnPage({documentId:t,pageIndex:o,onRectsChange:({rects:e,boundingRect:t})=>{p.value=e,d.value=t}}))},{immediate:!0}),o.watch([()=>r.value,()=>t.documentId],([e,t],o,l)=>{if(!e||!t)return void(s.value=null);l(e.onMenuPlacement(t,e=>{s.value=e}))},{immediate:!0});const x=()=>({type:"selection",pageIndex:t.pageIndex}),y=()=>{var e,t,o;return{suggestTop:(null==(e=s.value)?void 0:e.suggestTop)??!1,spaceAbove:(null==(t=s.value)?void 0:t.spaceAbove)??0,spaceBelow:(null==(o=s.value)?void 0:o.spaceBelow)??0}},b=(e,o)=>t.selectionMenu?t.selectionMenu({rect:e,menuWrapperProps:o,selected:!0,placement:y(),context:x()}):null;return(t,l)=>d.value?(o.openBlock(),o.createElementBlock(o.Fragment,{key:0},[o.createElementVNode("div",{style:o.normalizeStyle({position:"absolute",left:d.value.origin.x*v.value+"px",top:d.value.origin.y*v.value+"px",width:d.value.size.width*v.value+"px",height:d.value.size.height*v.value+"px",mixBlendMode:"multiply",isolation:"isolate",pointerEvents:"none"})},[(o.openBlock(!0),o.createElementBlock(o.Fragment,null,o.renderList(p.value,(t,l)=>(o.openBlock(),o.createElementBlock("div",{key:l,style:o.normalizeStyle({position:"absolute",left:(t.origin.x-d.value.origin.x)*v.value+"px",top:(t.origin.y-d.value.origin.y)*v.value+"px",width:t.size.width*v.value+"px",height:t.size.height*v.value+"px",background:e.background})},null,4))),128))],4),m.value?(o.openBlock(),o.createBlock(o.unref(a.CounterRotate),{key:0,rect:{origin:{x:s.value.rect.origin.x*v.value,y:s.value.rect.origin.y*v.value},size:{width:s.value.rect.size.width*v.value,height:s.value.rect.size.height*v.value}},rotation:g.value},{default:o.withCtx(({rect:l,menuWrapperProps:n})=>[e.selectionMenu?(o.openBlock(),o.createBlock(o.resolveDynamicComponent(b(l,n)),{key:0})):o.renderSlot(t.$slots,"selection-menu",{key:1,context:x(),selected:!0,rect:l,placement:y(),menuWrapperProps:n})]),_:3},8,["rect","rotation"])):o.createCommentVNode("",!0)],64)):o.createCommentVNode("",!0)}}),c=o.defineComponent({__name:"copy-to-clipboard",setup(e){const{provides:t}=i();return o.watchEffect(e=>{if(t.value){e(t.value.onCopyToClipboard(({text:e})=>{navigator.clipboard.writeText(e).catch(e=>{console.error("Failed to copy text to clipboard:",e)})}))}}),(e,t)=>null}}),p=e.createPluginPackage(t.SelectionPluginPackage).addUtility(c).build();exports.CopyToClipboard=c,exports.SelectionLayer=r,exports.SelectionPluginPackage=p,exports.useSelectionCapability=i,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/vue/hooks/use-selection.ts","../../src/vue/components/selection-layer.vue","../../src/vue/components/copy-to-clipboard.vue","../../src/vue/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<template>\n <div\n v-if=\"boundingRect\"\n :style=\"{\n position: 'absolute',\n left: `${boundingRect.origin.x * scale}px`,\n top: `${boundingRect.origin.y * scale}px`,\n width: `${boundingRect.size.width * scale}px`,\n height: `${boundingRect.size.height * scale}px`,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\n }\"\n >\n <div\n v-for=\"(rect, i) in rects\"\n :key=\"i\"\n :style=\"{\n position: 'absolute',\n left: `${(rect.origin.x - boundingRect.origin.x) * scale}px`,\n top: `${(rect.origin.y - boundingRect.origin.y) * scale}px`,\n width: `${rect.size.width * scale}px`,\n height: `${rect.size.height * scale}px`,\n background: background,\n }\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted } from 'vue';\nimport type { Rect } from '@embedpdf/models';\nimport { useSelectionPlugin } from '../hooks/use-selection';\n\ninterface Props {\n pageIndex: number;\n scale: number;\n background?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n background: 'rgba(33, 150, 243)',\n});\n\nconst { plugin: sel } = useSelectionPlugin();\nconst rects = ref<Rect[]>([]);\nconst boundingRect = ref<Rect | null>(null);\n\nlet unregister: (() => void) | undefined;\n\nonMounted(() => {\n if (!sel.value) return;\n\n unregister = sel.value.registerSelectionOnPage({\n pageIndex: props.pageIndex,\n onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n rects.value = newRects;\n boundingRect.value = newBoundingRect;\n },\n });\n});\n\nonUnmounted(() => {\n unregister?.();\n});\n</script>\n","<script setup lang=\"ts\">\nimport { watchEffect } from 'vue';\nimport { useSelectionCapability } from '../hooks';\n\nconst { provides: sel } = useSelectionCapability();\n\n// This effect runs when the component is mounted and the capability is available.\n// It automatically handles unsubscribing when the component is unmounted.\nwatchEffect((onCleanup) => {\n if (sel.value) {\n const unsubscribe = sel.value.onCopyToClipboard((text) => {\n // Use the Clipboard API to write the text\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('Failed to copy text to clipboard:', err);\n });\n });\n\n // Register the cleanup function to run on unmount or re-run\n onCleanup(unsubscribe);\n }\n});\n</script>\n\n<template>\n <!-- This component renders nothing to the DOM -->\n</template>\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 '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n .addUtility(CopyToClipboard)\n .build();\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","props","__props","plugin","sel","rects","ref","boundingRect","unregister","onMounted","value","registerSelectionOnPage","pageIndex","onRectsChange","newRects","newBoundingRect","onUnmounted","_createElementBlock","style","_normalizeStyle","left","origin","x","scale","top","y","width","size","height","_openBlock","createElementBlock","_Fragment","_renderList","renderList","rect","i","key","background","provides","vue$1","watchEffect","onCleanup","onCopyToClipboard","text","navigator","clipboard","writeText","catch","err","console","error","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","CopyToClipboard","build"],"mappings":"2MAOaA,EAAyB,IAAMC,gBAA+BC,EAAAA,gBAAgBC,IAM9EC,EAAqB,IAAMC,YAA2BH,EAAAA,gBAAgBC,mIC2BnF,MAAMG,EAAQC,GAINC,OAAQC,GAAQL,IAClBM,EAAQC,EAAYA,IAAA,IACpBC,EAAeD,MAAiB,MAElC,IAAAE,SAEJC,EAAAA,WAAU,KACHL,EAAIM,QAEIF,EAAAJ,EAAIM,MAAMC,wBAAwB,CAC7CC,UAAWX,EAAMW,UACjBC,cAAe,EAAGR,MAAOS,EAAUP,aAAcQ,MAC/CV,EAAMK,MAAQI,EACdP,EAAaG,MAAQK,CAAA,IAExB,IAGHC,EAAAA,aAAY,KACG,MAAAR,GAAAA,GAAA,WA7DLD,EAAYG,qBADpBO,EAAAA,mBAyBM,MAAA,OAvBHC,MAAKC,EAAAA,eAAA,qBAA+CC,KAAAb,EAAAG,MAAaW,OAAOC,EAAIC,EAAKA,MAA7B,KAAiDC,IAAAjB,EAAAG,MAAaW,OAAOI,EAAIF,EAAKA,MAA7B,KAAmDG,MAAAnB,EAAAG,MAAaiB,KAAKD,MAAQH,EAAKA,MAA/B,KAAsDK,OAAArB,EAAAG,MAAaiB,KAAKC,OAASL,EAAKA,MAAhC,2EAW/MM,EAAAA,WAAA,GAAAZ,EAWEa,mBAAAC,WAVoB,KAAAC,EAAAC,WAAA5B,EAAAK,OAAZ,CAAAwB,EAAMC,mBADhBlB,EAAAa,mBAWE,MAAA,CATCM,IAAKD,EACLjB,MAAKC,EAAAA,eAAA,2BAAoDe,EAAKb,OAAOC,EAAIf,EAAYG,MAACW,OAAOC,GAAKC,EAAKA,gBAAuBW,EAAKb,OAAOI,EAAIlB,EAAYG,MAACW,OAAOI,GAAKF,EAAKA,WAAwBG,MAAAQ,EAAKP,KAAKD,MAAQH,EAAKA,MAAvB,KAAgDK,OAAAM,EAAKP,KAAKC,OAASL,EAAKA,MAAxB,gBAAkDc,EAAUA,4HCbvT,MAAQC,SAAUlC,GAAQT,WAI1B4C,EAAAC,aAAaC,IACX,GAAIrC,EAAIM,MAAO,CASb+B,EARoBrC,EAAIM,MAAMgC,mBAAmBC,IAE/CC,UAAUC,UAAUC,UAAUH,GAAMI,OAAOC,IACjCC,QAAAC,MAAM,oCAAqCF,EAAG,GACvD,IAIkB,oBCTZG,EAAyBC,EAAoBA,oBAAAC,EAA0BF,wBACjFG,WAAWC,GACXC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/vue/hooks/use-selection.ts","../../src/vue/components/selection-layer.vue","../../src/vue/components/copy-to-clipboard.vue","../../src/vue/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<script setup lang=\"ts\">\nimport { ref, watch, computed, useSlots, type VNode } from 'vue';\nimport { useDocumentState } from '@embedpdf/core/vue';\nimport { Rotation, type Rect } from '@embedpdf/models';\nimport type { SelectionMenuPlacement } from '@embedpdf/plugin-selection';\nimport { CounterRotate, type MenuWrapperProps } from '@embedpdf/utils/vue';\nimport { useSelectionPlugin } from '../hooks/use-selection';\nimport type { SelectionSelectionContext, SelectionSelectionMenuRenderFn } from '../types';\n\ninterface SelectionLayerProps {\n documentId: string;\n pageIndex: number;\n scale?: number;\n rotation?: Rotation;\n background?: string;\n /** Render function for selection menu (schema-driven approach) */\n selectionMenu?: SelectionSelectionMenuRenderFn;\n}\n\nconst props = withDefaults(defineProps<SelectionLayerProps>(), {\n background: 'rgba(33,150,243)',\n rotation: Rotation.Degree0,\n});\n\nconst slots = useSlots();\nconst { plugin: selPlugin } = useSelectionPlugin();\nconst documentState = useDocumentState(() => props.documentId);\nconst rects = ref<Rect[]>([]);\nconst boundingRect = ref<Rect | null>(null);\nconst placement = ref<SelectionMenuPlacement | null>(null);\n\nconst actualScale = computed(() => {\n if (props.scale !== undefined) return props.scale;\n return documentState.value?.scale ?? 1;\n});\n\nconst actualRotation = computed(() => {\n if (props.rotation !== undefined) return props.rotation;\n return documentState.value?.rotation ?? Rotation.Degree0;\n});\n\n// Check if menu should render: placement is valid AND (render fn OR slot exists)\nconst shouldRenderMenu = computed(() => {\n if (!placement.value) return false;\n if (placement.value.pageIndex !== props.pageIndex) return false;\n if (!placement.value.isVisible) return false;\n\n // Must have either render function or slot\n return !!props.selectionMenu || !!slots['selection-menu'];\n});\n\nwatch(\n [() => selPlugin.value, () => props.documentId, () => props.pageIndex],\n ([plugin, docId, pageIdx], _, onCleanup) => {\n if (!plugin || !docId) {\n rects.value = [];\n boundingRect.value = null;\n return;\n }\n\n const unregister = plugin.registerSelectionOnPage({\n documentId: docId,\n pageIndex: pageIdx,\n onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n rects.value = newRects;\n boundingRect.value = newBoundingRect;\n },\n });\n\n onCleanup(unregister);\n },\n { immediate: true },\n);\n\nwatch(\n [() => selPlugin.value, () => props.documentId],\n ([plugin, docId], _, onCleanup) => {\n if (!plugin || !docId) {\n placement.value = null;\n return;\n }\n\n const unsubscribe = plugin.onMenuPlacement(docId, (newPlacement) => {\n placement.value = newPlacement;\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n);\n\n// --- Selection Menu Logic ---\n\n// Build context object for selection menu\nconst buildContext = (): SelectionSelectionContext => ({\n type: 'selection',\n pageIndex: props.pageIndex,\n});\n\n// Build placement hints from plugin placement data\nconst buildMenuPlacement = () => ({\n suggestTop: placement.value?.suggestTop ?? false,\n spaceAbove: placement.value?.spaceAbove ?? 0,\n spaceBelow: placement.value?.spaceBelow ?? 0,\n});\n\n// Render via function (for schema-driven approach)\nconst renderSelectionMenu = (rect: Rect, menuWrapperProps: MenuWrapperProps): VNode | null => {\n if (!props.selectionMenu) return null;\n\n return props.selectionMenu({\n rect,\n menuWrapperProps,\n selected: true, // Selection is always \"selected\" when visible\n placement: buildMenuPlacement(),\n context: buildContext(),\n });\n};\n</script>\n\n<template>\n <template v-if=\"boundingRect\">\n <div\n :style=\"{\n position: 'absolute',\n left: `${boundingRect.origin.x * actualScale}px`,\n top: `${boundingRect.origin.y * actualScale}px`,\n width: `${boundingRect.size.width * actualScale}px`,\n height: `${boundingRect.size.height * actualScale}px`,\n mixBlendMode: 'multiply',\n isolation: 'isolate',\n pointerEvents: 'none',\n }\"\n >\n <div\n v-for=\"(rect, i) in rects\"\n :key=\"i\"\n :style=\"{\n position: 'absolute',\n left: `${(rect.origin.x - boundingRect.origin.x) * actualScale}px`,\n top: `${(rect.origin.y - boundingRect.origin.y) * actualScale}px`,\n width: `${rect.size.width * actualScale}px`,\n height: `${rect.size.height * actualScale}px`,\n background: background,\n }\"\n />\n </div>\n\n <!-- Selection Menu: Supports BOTH render function and slot -->\n <CounterRotate\n v-if=\"shouldRenderMenu\"\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 <template #default=\"{ rect, menuWrapperProps }\">\n <!-- Priority 1: Render function prop (schema-driven) -->\n <component v-if=\"selectionMenu\" :is=\"renderSelectionMenu(rect, menuWrapperProps)\" />\n\n <!-- Priority 2: Slot (manual customization) -->\n <slot\n v-else\n name=\"selection-menu\"\n :context=\"buildContext()\"\n :selected=\"true\"\n :rect=\"rect\"\n :placement=\"buildMenuPlacement()\"\n :menuWrapperProps=\"menuWrapperProps\"\n />\n </template>\n </CounterRotate>\n </template>\n</template>\n","<script setup lang=\"ts\">\nimport { watchEffect } from 'vue';\nimport { useSelectionCapability } from '../hooks';\n\nconst { provides: sel } = useSelectionCapability();\n\n// This effect runs when the component is mounted and the capability is available.\n// It automatically handles unsubscribing when the component is unmounted.\nwatchEffect((onCleanup) => {\n if (sel.value) {\n const unsubscribe = sel.value.onCopyToClipboard(({ text }) => {\n // Use the Clipboard API to write the text\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('Failed to copy text to clipboard:', err);\n });\n });\n\n // Register the cleanup function to run on unmount or re-run\n onCleanup(unsubscribe);\n }\n});\n</script>\n\n<template>\n <!-- This component renders nothing to the DOM -->\n</template>\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":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","props","__props","slots","useSlots","plugin","selPlugin","documentState","useDocumentState","documentId","rects","ref","boundingRect","placement","actualScale","computed","scale","_a","value","actualRotation","rotation","Rotation","Degree0","shouldRenderMenu","pageIndex","isVisible","selectionMenu","watch","docId","pageIdx","_","onCleanup","registerSelectionOnPage","onRectsChange","newRects","newBoundingRect","immediate","onMenuPlacement","newPlacement","buildContext","type","buildMenuPlacement","suggestTop","spaceAbove","_b","spaceBelow","_c","renderSelectionMenu","rect","menuWrapperProps","selected","context","_createElementBlock","_Fragment","key","_createElementVNode","style","_normalizeStyle","left","origin","x","top","y","width","size","height","_openBlock","_renderList","i","background","_createBlock","_unref","CounterRotate","default","_withCtx","_resolveDynamicComponent","_renderSlot","_ctx","$slots","provides","sel","watchEffect","onCopyToClipboard","text","navigator","clipboard","writeText","catch","err","console","error","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","CopyToClipboard","build"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
+ export * from './types';
3
4
  export * from '../lib/index.ts';
4
5
  export declare const SelectionPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').SelectionPlugin, import('../lib/index.ts').SelectionPluginConfig, import('../lib/index.ts').SelectionState, import('src/lib/actions').SelectionAction>>;