@embedpdf/plugin-selection 1.5.0 → 2.0.0-next.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 (44) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +449 -169
  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 +27 -6
  8. package/dist/lib/selectors.d.ts +7 -7
  9. package/dist/lib/types.d.ts +68 -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 +161 -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
package/dist/vue/index.js CHANGED
@@ -1,64 +1,158 @@
1
1
  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
- import { defineComponent, ref, onMounted, onUnmounted, createElementBlock, createCommentVNode, openBlock, normalizeStyle, Fragment, renderList, watchEffect } from "vue";
5
- import { useCapability, usePlugin } from "@embedpdf/core/vue";
4
+ import { defineComponent, useSlots, ref, computed, watch, createElementBlock, createCommentVNode, openBlock, Fragment, createElementVNode, createBlock, normalizeStyle, renderList, unref, withCtx, renderSlot, resolveDynamicComponent, watchEffect } from "vue";
5
+ import { usePlugin, useCapability, useDocumentState } from "@embedpdf/core/vue";
6
+ import { Rotation } from "@embedpdf/models";
7
+ import { CounterRotate } from "@embedpdf/utils/vue";
6
8
  const useSelectionCapability = () => useCapability(SelectionPlugin.id);
7
9
  const useSelectionPlugin = () => usePlugin(SelectionPlugin.id);
8
10
  const _sfc_main$1 = /* @__PURE__ */ defineComponent({
9
11
  __name: "selection-layer",
10
12
  props: {
13
+ documentId: {},
11
14
  pageIndex: {},
12
15
  scale: {},
13
- background: { default: "rgba(33, 150, 243)" }
16
+ rotation: { default: Rotation.Degree0 },
17
+ background: { default: "rgba(33,150,243)" },
18
+ selectionMenu: {}
14
19
  },
15
20
  setup(__props) {
16
21
  const props = __props;
17
- const { plugin: sel } = useSelectionPlugin();
22
+ const slots = useSlots();
23
+ const { plugin: selPlugin } = useSelectionPlugin();
24
+ const documentState = useDocumentState(() => props.documentId);
18
25
  const rects = ref([]);
19
26
  const boundingRect = ref(null);
20
- let unregister;
21
- onMounted(() => {
22
- if (!sel.value) return;
23
- unregister = sel.value.registerSelectionOnPage({
24
- pageIndex: props.pageIndex,
25
- onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {
26
- rects.value = newRects;
27
- boundingRect.value = newBoundingRect;
28
- }
29
- });
27
+ const placement = ref(null);
28
+ const actualScale = computed(() => {
29
+ var _a;
30
+ if (props.scale !== void 0) return props.scale;
31
+ return ((_a = documentState.value) == null ? void 0 : _a.scale) ?? 1;
32
+ });
33
+ const actualRotation = computed(() => {
34
+ var _a;
35
+ if (props.rotation !== void 0) return props.rotation;
36
+ return ((_a = documentState.value) == null ? void 0 : _a.rotation) ?? Rotation.Degree0;
30
37
  });
31
- onUnmounted(() => {
32
- unregister == null ? void 0 : unregister();
38
+ const shouldRenderMenu = computed(() => {
39
+ if (!placement.value) return false;
40
+ if (placement.value.pageIndex !== props.pageIndex) return false;
41
+ if (!placement.value.isVisible) return false;
42
+ return !!props.selectionMenu || !!slots["selection-menu"];
43
+ });
44
+ watch(
45
+ [() => selPlugin.value, () => props.documentId, () => props.pageIndex],
46
+ ([plugin, docId, pageIdx], _, onCleanup) => {
47
+ if (!plugin || !docId) {
48
+ rects.value = [];
49
+ boundingRect.value = null;
50
+ return;
51
+ }
52
+ const unregister = plugin.registerSelectionOnPage({
53
+ documentId: docId,
54
+ pageIndex: pageIdx,
55
+ onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {
56
+ rects.value = newRects;
57
+ boundingRect.value = newBoundingRect;
58
+ }
59
+ });
60
+ onCleanup(unregister);
61
+ },
62
+ { immediate: true }
63
+ );
64
+ watch(
65
+ [() => selPlugin.value, () => props.documentId],
66
+ ([plugin, docId], _, onCleanup) => {
67
+ if (!plugin || !docId) {
68
+ placement.value = null;
69
+ return;
70
+ }
71
+ const unsubscribe = plugin.onMenuPlacement(docId, (newPlacement) => {
72
+ placement.value = newPlacement;
73
+ });
74
+ onCleanup(unsubscribe);
75
+ },
76
+ { immediate: true }
77
+ );
78
+ const buildContext = () => ({
79
+ type: "selection",
80
+ pageIndex: props.pageIndex
33
81
  });
82
+ const buildMenuPlacement = () => {
83
+ var _a, _b, _c;
84
+ return {
85
+ suggestTop: ((_a = placement.value) == null ? void 0 : _a.suggestTop) ?? false,
86
+ spaceAbove: ((_b = placement.value) == null ? void 0 : _b.spaceAbove) ?? 0,
87
+ spaceBelow: ((_c = placement.value) == null ? void 0 : _c.spaceBelow) ?? 0
88
+ };
89
+ };
90
+ const renderSelectionMenu = (rect, menuWrapperProps) => {
91
+ if (!props.selectionMenu) return null;
92
+ return props.selectionMenu({
93
+ rect,
94
+ menuWrapperProps,
95
+ selected: true,
96
+ // Selection is always "selected" when visible
97
+ placement: buildMenuPlacement(),
98
+ context: buildContext()
99
+ });
100
+ };
34
101
  return (_ctx, _cache) => {
35
- return boundingRect.value ? (openBlock(), createElementBlock("div", {
36
- key: 0,
37
- style: normalizeStyle({
38
- position: "absolute",
39
- left: `${boundingRect.value.origin.x * _ctx.scale}px`,
40
- top: `${boundingRect.value.origin.y * _ctx.scale}px`,
41
- width: `${boundingRect.value.size.width * _ctx.scale}px`,
42
- height: `${boundingRect.value.size.height * _ctx.scale}px`,
43
- mixBlendMode: "multiply",
44
- isolation: "isolate",
45
- pointerEvents: "none"
46
- })
47
- }, [
48
- (openBlock(true), createElementBlock(Fragment, null, renderList(rects.value, (rect, i) => {
49
- return openBlock(), createElementBlock("div", {
50
- key: i,
51
- style: normalizeStyle({
52
- position: "absolute",
53
- left: `${(rect.origin.x - boundingRect.value.origin.x) * _ctx.scale}px`,
54
- top: `${(rect.origin.y - boundingRect.value.origin.y) * _ctx.scale}px`,
55
- width: `${rect.size.width * _ctx.scale}px`,
56
- height: `${rect.size.height * _ctx.scale}px`,
57
- background: _ctx.background
102
+ return boundingRect.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
103
+ createElementVNode("div", {
104
+ style: normalizeStyle({
105
+ position: "absolute",
106
+ left: `${boundingRect.value.origin.x * actualScale.value}px`,
107
+ top: `${boundingRect.value.origin.y * actualScale.value}px`,
108
+ width: `${boundingRect.value.size.width * actualScale.value}px`,
109
+ height: `${boundingRect.value.size.height * actualScale.value}px`,
110
+ mixBlendMode: "multiply",
111
+ isolation: "isolate",
112
+ pointerEvents: "none"
113
+ })
114
+ }, [
115
+ (openBlock(true), createElementBlock(Fragment, null, renderList(rects.value, (rect, i) => {
116
+ return openBlock(), createElementBlock("div", {
117
+ key: i,
118
+ style: normalizeStyle({
119
+ position: "absolute",
120
+ left: `${(rect.origin.x - boundingRect.value.origin.x) * actualScale.value}px`,
121
+ top: `${(rect.origin.y - boundingRect.value.origin.y) * actualScale.value}px`,
122
+ width: `${rect.size.width * actualScale.value}px`,
123
+ height: `${rect.size.height * actualScale.value}px`,
124
+ background: __props.background
125
+ })
126
+ }, null, 4);
127
+ }), 128))
128
+ ], 4),
129
+ shouldRenderMenu.value ? (openBlock(), createBlock(unref(CounterRotate), {
130
+ key: 0,
131
+ rect: {
132
+ origin: {
133
+ x: placement.value.rect.origin.x * actualScale.value,
134
+ y: placement.value.rect.origin.y * actualScale.value
135
+ },
136
+ size: {
137
+ width: placement.value.rect.size.width * actualScale.value,
138
+ height: placement.value.rect.size.height * actualScale.value
139
+ }
140
+ },
141
+ rotation: actualRotation.value
142
+ }, {
143
+ default: withCtx(({ rect, menuWrapperProps }) => [
144
+ __props.selectionMenu ? (openBlock(), createBlock(resolveDynamicComponent(renderSelectionMenu(rect, menuWrapperProps)), { key: 0 })) : renderSlot(_ctx.$slots, "selection-menu", {
145
+ key: 1,
146
+ context: buildContext(),
147
+ selected: true,
148
+ rect,
149
+ placement: buildMenuPlacement(),
150
+ menuWrapperProps
58
151
  })
59
- }, null, 4);
60
- }), 128))
61
- ], 4)) : createCommentVNode("", true);
152
+ ]),
153
+ _: 3
154
+ }, 8, ["rect", "rotation"])) : createCommentVNode("", true)
155
+ ], 64)) : createCommentVNode("", true);
62
156
  };
63
157
  }
64
158
  });
@@ -68,7 +162,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
68
162
  const { provides: sel } = useSelectionCapability();
69
163
  watchEffect((onCleanup) => {
70
164
  if (sel.value) {
71
- const unsubscribe = sel.value.onCopyToClipboard((text) => {
165
+ const unsubscribe = sel.value.onCopyToClipboard(({ text }) => {
72
166
  navigator.clipboard.writeText(text).catch((err) => {
73
167
  console.error("Failed to copy text to clipboard:", err);
74
168
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","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":["_createElementBlock","_normalizeStyle","scale","_openBlock","_Fragment","_renderList","background","BaseSelectionPluginPackage","CopyToClipboard"],"mappings":";;;;;AAOO,MAAM,yBAAyB,MAAM,cAA+B,gBAAgB,EAAE;AAMtF,MAAM,qBAAqB,MAAM,UAA2B,gBAAgB,EAAE;;;;;;;;;AC2BrF,UAAM,QAAQ;AAId,UAAM,EAAE,QAAQ,IAAI,IAAI,mBAAmB;AACrC,UAAA,QAAQ,IAAY,EAAE;AACtB,UAAA,eAAe,IAAiB,IAAI;AAEtC,QAAA;AAEJ,cAAU,MAAM;AACV,UAAA,CAAC,IAAI,MAAO;AAEH,mBAAA,IAAI,MAAM,wBAAwB;AAAA,QAC7C,WAAW,MAAM;AAAA,QACjB,eAAe,CAAC,EAAE,OAAO,UAAU,cAAc,sBAAsB;AACrE,gBAAM,QAAQ;AACd,uBAAa,QAAQ;AAAA,QAAA;AAAA,MACvB,CACD;AAAA,IAAA,CACF;AAED,gBAAY,MAAM;AACH;AAAA,IAAA,CACd;;aA9DS,aAAY,sBADpBA,mBAyBM,OAAA;AAAA;QAvBH,OAAKC,eAAA;AAAA;UAA+C,MAAA,GAAA,aAAA,MAAa,OAAO,IAAIC,KAAK,KAAA;AAAA,UAAoB,KAAA,GAAA,aAAA,MAAa,OAAO,IAAIA,KAAK,KAAA;AAAA,UAAsB,OAAA,GAAA,aAAA,MAAa,KAAK,QAAQA,KAAK,KAAA;AAAA,UAAuB,QAAA,GAAA,aAAA,MAAa,KAAK,SAASA,KAAK,KAAA;AAAA;;;;;SAW/OC,UAAA,IAAA,GAAAH,mBAWEI,UAVoB,MAAAC,WAAA,MAAA,OAAZ,CAAA,MAAM,MAAC;8BADjBL,mBAWE,OAAA;AAAA,YATC,KAAK;AAAA,YACL,OAAKC,eAAA;AAAA;wBAAoD,KAAK,OAAO,IAAI,aAAY,MAAC,OAAO,KAAKC,KAAK,KAAA;AAAA,uBAAuB,KAAK,OAAO,IAAI,aAAY,MAAC,OAAO,KAAKA,KAAK,KAAA;AAAA,cAAwB,OAAA,GAAA,KAAK,KAAK,QAAQA,KAAK,KAAA;AAAA,cAAyB,QAAA,GAAA,KAAK,KAAK,SAASA,KAAK,KAAA;AAAA,0BAA0BI,KAAU;AAAA;;;;;;;;;;ACbvT,UAAM,EAAE,UAAU,IAAI,IAAI,uBAAuB;AAIjD,gBAAY,CAAC,cAAc;AACzB,UAAI,IAAI,OAAO;AACb,cAAM,cAAc,IAAI,MAAM,kBAAkB,CAAC,SAAS;AAExD,oBAAU,UAAU,UAAU,IAAI,EAAE,MAAM,CAAC,QAAQ;AACzC,oBAAA,MAAM,qCAAqC,GAAG;AAAA,UAAA,CACvD;AAAA,QAAA,CACF;AAGD,kBAAU,WAAW;AAAA,MAAA;AAAA,IACvB,CACD;;;;;;ACXM,MAAM,yBAAyB,oBAAoBC,wBAA0B,EACjF,WAAWC,SAAe,EAC1B,MAAM;"}
1
+ {"version":3,"file":"index.js","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":["_createElementBlock","_Fragment","_createElementVNode","_normalizeStyle","_openBlock","_renderList","_createBlock","_unref","_withCtx","_resolveDynamicComponent","_renderSlot","BaseSelectionPluginPackage","CopyToClipboard"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { SelectionMenuRenderFn, SelectionMenuPropsBase } from '@embedpdf/utils/vue';
2
+ export interface SelectionSelectionContext {
3
+ type: 'selection';
4
+ pageIndex: number;
5
+ }
6
+ export type SelectionSelectionMenuRenderFn = SelectionMenuRenderFn<SelectionSelectionContext>;
7
+ export type SelectionSelectionMenuProps = SelectionMenuPropsBase<SelectionSelectionContext>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-selection",
3
- "version": "1.5.0",
3
+ "version": "2.0.0-next.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
@@ -34,15 +34,17 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@embedpdf/models": "1.5.0"
37
+ "@embedpdf/models": "2.0.0-next.1",
38
+ "@embedpdf/utils": "2.0.0-next.1"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@types/react": "^18.2.0",
41
42
  "typescript": "^5.0.0",
43
+ "@embedpdf/core": "2.0.0-next.1",
42
44
  "@embedpdf/build": "1.1.0",
43
- "@embedpdf/core": "1.5.0",
44
- "@embedpdf/plugin-viewport": "1.5.0",
45
- "@embedpdf/plugin-interaction-manager": "1.5.0"
45
+ "@embedpdf/plugin-viewport": "2.0.0-next.1",
46
+ "@embedpdf/plugin-scroll": "2.0.0-next.1",
47
+ "@embedpdf/plugin-interaction-manager": "2.0.0-next.1"
46
48
  },
47
49
  "peerDependencies": {
48
50
  "react": ">=16.8.0",
@@ -50,9 +52,8 @@
50
52
  "preact": "^10.26.4",
51
53
  "vue": ">=3.2.0",
52
54
  "svelte": ">=5 <6",
53
- "@embedpdf/core": "1.5.0",
54
- "@embedpdf/plugin-viewport": "1.5.0",
55
- "@embedpdf/plugin-interaction-manager": "1.5.0"
55
+ "@embedpdf/core": "2.0.0-next.1",
56
+ "@embedpdf/plugin-interaction-manager": "2.0.0-next.1"
56
57
  },
57
58
  "files": [
58
59
  "dist",