@embedpdf/react 3.0.0-next.14 → 3.0.0-next.16

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 (244) hide show
  1. package/dist/AnnotationList-DcyhF2kU-CiBFOq1z.d.cts +878 -0
  2. package/dist/AnnotationList-DcyhF2kU-CiBFOq1z.d.ts +878 -0
  3. package/dist/actions.cjs +25 -5
  4. package/dist/actions.cjs.map +1 -1
  5. package/dist/actions.d.cts +18 -5
  6. package/dist/actions.d.ts +18 -5
  7. package/dist/actions.js +22 -6
  8. package/dist/actions.js.map +1 -1
  9. package/dist/anchored-DeX95xSd.d.ts +85 -0
  10. package/dist/anchored-DzN3JywS.d.cts +85 -0
  11. package/dist/anchored.cjs +71 -28
  12. package/dist/anchored.cjs.map +1 -1
  13. package/dist/anchored.d.cts +2 -45
  14. package/dist/anchored.d.ts +2 -45
  15. package/dist/anchored.js +56 -19
  16. package/dist/anchored.js.map +1 -1
  17. package/dist/annotation-3UvABfJm.d.cts +305 -0
  18. package/dist/annotation-BNHQpMKv.cjs +806 -0
  19. package/dist/annotation-BNHQpMKv.cjs.map +1 -0
  20. package/dist/annotation-CDI8CFb3.js +684 -0
  21. package/dist/annotation-CDI8CFb3.js.map +1 -0
  22. package/dist/annotation-DhEfs0pH.d.ts +305 -0
  23. package/dist/annotation.cjs +20 -784
  24. package/dist/annotation.d.cts +2 -2
  25. package/dist/annotation.d.ts +2 -2
  26. package/dist/annotation.js +2 -769
  27. package/dist/attachment.cjs +39 -0
  28. package/dist/attachment.cjs.map +1 -0
  29. package/dist/attachment.d.cts +29 -0
  30. package/dist/attachment.d.ts +29 -0
  31. package/dist/attachment.js +28 -0
  32. package/dist/attachment.js.map +1 -0
  33. package/dist/commands.cjs +68 -28
  34. package/dist/commands.cjs.map +1 -1
  35. package/dist/commands.d.cts +37 -10
  36. package/dist/commands.d.ts +37 -10
  37. package/dist/commands.js +68 -31
  38. package/dist/commands.js.map +1 -1
  39. package/dist/form-BSGvjA5D.js +511 -0
  40. package/dist/form-BSGvjA5D.js.map +1 -0
  41. package/dist/form-BgztZyOK.cjs +548 -0
  42. package/dist/form-BgztZyOK.cjs.map +1 -0
  43. package/dist/form.cjs +5 -5
  44. package/dist/form.d.cts +41 -2
  45. package/dist/form.d.ts +41 -2
  46. package/dist/form.js +2 -3
  47. package/dist/history.cjs +38 -0
  48. package/dist/history.cjs.map +1 -0
  49. package/dist/history.d.cts +27 -0
  50. package/dist/history.d.ts +27 -0
  51. package/dist/history.js +27 -0
  52. package/dist/history.js.map +1 -0
  53. package/dist/i18n.cjs +26 -30
  54. package/dist/i18n.cjs.map +1 -1
  55. package/dist/i18n.d.cts +24 -21
  56. package/dist/i18n.d.ts +24 -21
  57. package/dist/i18n.js +24 -31
  58. package/dist/i18n.js.map +1 -1
  59. package/dist/index.cjs +227 -57
  60. package/dist/index.d.cts +35 -32
  61. package/dist/index.d.ts +35 -32
  62. package/dist/index.js +36 -30
  63. package/dist/inert-CmBEbKCn.cjs +19 -0
  64. package/dist/inert-CmBEbKCn.cjs.map +1 -0
  65. package/dist/inert-D8fkennb.js +14 -0
  66. package/dist/inert-D8fkennb.js.map +1 -0
  67. package/dist/interaction.cjs +48 -102
  68. package/dist/interaction.cjs.map +1 -1
  69. package/dist/interaction.d.cts +23 -32
  70. package/dist/interaction.d.ts +23 -32
  71. package/dist/interaction.js +33 -102
  72. package/dist/interaction.js.map +1 -1
  73. package/dist/link.cjs +65 -104
  74. package/dist/link.cjs.map +1 -1
  75. package/dist/link.d.cts +21 -16
  76. package/dist/link.d.ts +22 -17
  77. package/dist/link.js +67 -107
  78. package/dist/link.js.map +1 -1
  79. package/dist/measurement.cjs +36 -11
  80. package/dist/measurement.cjs.map +1 -1
  81. package/dist/measurement.d.cts +33 -7
  82. package/dist/measurement.d.ts +33 -7
  83. package/dist/measurement.js +35 -14
  84. package/dist/measurement.js.map +1 -1
  85. package/dist/metadata.cjs +20 -7
  86. package/dist/metadata.cjs.map +1 -1
  87. package/dist/metadata.d.cts +22 -7
  88. package/dist/metadata.d.ts +22 -7
  89. package/dist/metadata.js +20 -10
  90. package/dist/metadata.js.map +1 -1
  91. package/dist/outline.cjs +39 -0
  92. package/dist/outline.cjs.map +1 -0
  93. package/dist/outline.d.cts +31 -0
  94. package/dist/outline.d.ts +31 -0
  95. package/dist/outline.js +28 -0
  96. package/dist/outline.js.map +1 -0
  97. package/dist/page-edit.cjs +15 -3
  98. package/dist/page-edit.cjs.map +1 -1
  99. package/dist/page-edit.d.cts +17 -2
  100. package/dist/page-edit.d.ts +17 -2
  101. package/dist/page-edit.js +15 -5
  102. package/dist/page-edit.js.map +1 -1
  103. package/dist/page-layers-Bkaaz8Zf.js +26 -0
  104. package/dist/page-layers-Bkaaz8Zf.js.map +1 -0
  105. package/dist/page-layers-BloZDoOV.cjs +37 -0
  106. package/dist/page-layers-BloZDoOV.cjs.map +1 -0
  107. package/dist/page-view.cjs +89 -82
  108. package/dist/page-view.cjs.map +1 -1
  109. package/dist/page-view.d.cts +14 -7
  110. package/dist/page-view.d.ts +18 -11
  111. package/dist/page-view.js +86 -81
  112. package/dist/page-view.js.map +1 -1
  113. package/dist/redaction.cjs +30 -15
  114. package/dist/redaction.cjs.map +1 -1
  115. package/dist/redaction.d.cts +27 -9
  116. package/dist/redaction.d.ts +27 -9
  117. package/dist/redaction.js +29 -18
  118. package/dist/redaction.js.map +1 -1
  119. package/dist/render.cjs +71 -46
  120. package/dist/render.cjs.map +1 -1
  121. package/dist/render.d.cts +17 -5
  122. package/dist/render.d.ts +17 -5
  123. package/dist/render.js +70 -49
  124. package/dist/render.js.map +1 -1
  125. package/dist/runtime-BfnpyfY0.cjs +556 -0
  126. package/dist/runtime-BfnpyfY0.cjs.map +1 -0
  127. package/dist/runtime-DBEBlpQV.d.cts +237 -0
  128. package/dist/runtime-V3MVMb91.d.ts +237 -0
  129. package/dist/runtime-tD5iJU83.js +399 -0
  130. package/dist/runtime-tD5iJU83.js.map +1 -0
  131. package/dist/runtime.cjs +45 -324
  132. package/dist/runtime.d.cts +2 -2
  133. package/dist/runtime.d.ts +2 -2
  134. package/dist/runtime.js +2 -306
  135. package/dist/search.cjs +81 -50
  136. package/dist/search.cjs.map +1 -1
  137. package/dist/search.d.cts +37 -24
  138. package/dist/search.d.ts +37 -24
  139. package/dist/search.js +81 -53
  140. package/dist/search.js.map +1 -1
  141. package/dist/selection.cjs +105 -108
  142. package/dist/selection.cjs.map +1 -1
  143. package/dist/selection.d.cts +54 -26
  144. package/dist/selection.d.ts +56 -28
  145. package/dist/selection.js +103 -110
  146. package/dist/selection.js.map +1 -1
  147. package/dist/shell.cjs +36 -21
  148. package/dist/shell.cjs.map +1 -1
  149. package/dist/shell.d.cts +32 -17
  150. package/dist/shell.d.ts +32 -17
  151. package/dist/shell.js +36 -24
  152. package/dist/shell.js.map +1 -1
  153. package/dist/signature.cjs +29 -48
  154. package/dist/signature.cjs.map +1 -1
  155. package/dist/signature.d.cts +26 -26
  156. package/dist/signature.d.ts +26 -26
  157. package/dist/signature.js +30 -48
  158. package/dist/signature.js.map +1 -1
  159. package/dist/stage-B7BG2e8Q.cjs +369 -0
  160. package/dist/stage-B7BG2e8Q.cjs.map +1 -0
  161. package/dist/stage-BqfBjDu6.js +302 -0
  162. package/dist/stage-BqfBjDu6.js.map +1 -0
  163. package/dist/stage-ByFPD-Fv.d.cts +117 -0
  164. package/dist/stage-DaboaheR.d.ts +117 -0
  165. package/dist/stage-scope-CQgCuf1w.cjs +46 -0
  166. package/dist/stage-scope-CQgCuf1w.cjs.map +1 -0
  167. package/dist/stage-scope-D7ZeNduT.js +23 -0
  168. package/dist/stage-scope-D7ZeNduT.js.map +1 -0
  169. package/dist/stage.cjs +12 -235
  170. package/dist/stage.d.cts +2 -116
  171. package/dist/stage.d.ts +2 -116
  172. package/dist/stage.js +3 -228
  173. package/dist/stamp.cjs +41 -35
  174. package/dist/stamp.cjs.map +1 -1
  175. package/dist/stamp.d.cts +25 -18
  176. package/dist/stamp.d.ts +25 -18
  177. package/dist/stamp.js +40 -37
  178. package/dist/stamp.js.map +1 -1
  179. package/dist/state-0K1I5cM4.d.cts +29 -0
  180. package/dist/state-0K1I5cM4.d.ts +29 -0
  181. package/dist/state-CzI2KlZb.js +62 -0
  182. package/dist/state-CzI2KlZb.js.map +1 -0
  183. package/dist/state-Dtf8HAue.cjs +73 -0
  184. package/dist/state-Dtf8HAue.cjs.map +1 -0
  185. package/dist/svg-shapes-Dm1yTR1b.js +40 -0
  186. package/dist/svg-shapes-Dm1yTR1b.js.map +1 -0
  187. package/dist/svg-shapes-zo0GNkc9.cjs +53 -0
  188. package/dist/svg-shapes-zo0GNkc9.cjs.map +1 -0
  189. package/dist/toolbar.cjs +297 -295
  190. package/dist/toolbar.cjs.map +1 -1
  191. package/dist/toolbar.d.cts +58 -68
  192. package/dist/toolbar.d.ts +67 -77
  193. package/dist/toolbar.js +271 -293
  194. package/dist/toolbar.js.map +1 -1
  195. package/dist/view-manager.cjs +34 -0
  196. package/dist/view-manager.cjs.map +1 -0
  197. package/dist/view-manager.d.cts +21 -0
  198. package/dist/view-manager.d.ts +21 -0
  199. package/dist/view-manager.js +23 -0
  200. package/dist/view-manager.js.map +1 -0
  201. package/package.json +47 -39
  202. package/dist/annotation-BCED_p9H.d.cts +0 -160
  203. package/dist/annotation-anchors-CetwM1g7.js +0 -15
  204. package/dist/annotation-anchors-CetwM1g7.js.map +0 -1
  205. package/dist/annotation-anchors-DuYRBJLl.cjs +0 -26
  206. package/dist/annotation-anchors-DuYRBJLl.cjs.map +0 -1
  207. package/dist/annotation-hooks-BB5ZhPpf.cjs +0 -16
  208. package/dist/annotation-hooks-BB5ZhPpf.cjs.map +0 -1
  209. package/dist/annotation-hooks-Df8EmzDO.js +0 -11
  210. package/dist/annotation-hooks-Df8EmzDO.js.map +0 -1
  211. package/dist/annotation-k38KDlIZ.d.ts +0 -160
  212. package/dist/annotation-menu.cjs +0 -64
  213. package/dist/annotation-menu.cjs.map +0 -1
  214. package/dist/annotation-menu.d.cts +0 -33
  215. package/dist/annotation-menu.d.ts +0 -33
  216. package/dist/annotation-menu.js +0 -48
  217. package/dist/annotation-menu.js.map +0 -1
  218. package/dist/annotation.cjs.map +0 -1
  219. package/dist/annotation.js.map +0 -1
  220. package/dist/form-BVumS7up.cjs +0 -926
  221. package/dist/form-BVumS7up.cjs.map +0 -1
  222. package/dist/form-Bdjk0Z3T.d.cts +0 -537
  223. package/dist/form-CK3mp99m.js +0 -895
  224. package/dist/form-CK3mp99m.js.map +0 -1
  225. package/dist/form-CYRYgthn.d.ts +0 -537
  226. package/dist/rolldown-runtime-BBjsoOtd.js +0 -27
  227. package/dist/runtime-DE76hlnl.d.ts +0 -216
  228. package/dist/runtime-umHA_xHt.d.cts +0 -216
  229. package/dist/runtime.cjs.map +0 -1
  230. package/dist/runtime.js.map +0 -1
  231. package/dist/scrollbar.cjs +0 -241
  232. package/dist/scrollbar.cjs.map +0 -1
  233. package/dist/scrollbar.d.cts +0 -42
  234. package/dist/scrollbar.d.ts +0 -42
  235. package/dist/scrollbar.js +0 -213
  236. package/dist/scrollbar.js.map +0 -1
  237. package/dist/stage.cjs.map +0 -1
  238. package/dist/stage.js.map +0 -1
  239. package/dist/views.cjs +0 -35
  240. package/dist/views.cjs.map +0 -1
  241. package/dist/views.d.cts +0 -21
  242. package/dist/views.d.ts +0 -21
  243. package/dist/views.js +0 -27
  244. package/dist/views.js.map +0 -1
@@ -0,0 +1,684 @@
1
+ import { C as useOptionalSelector, D as useViewerSettings, E as useSelector, O as devWarn, S as useOptionalCapability, f as useCapability, h as useDocumentId, p as useCapabilityEvent, u as shallowArray, w as usePage, x as useKernelValue } from "./runtime-tD5iJU83.js";
2
+ import { n as stateHook, t as settingsHook } from "./state-CzI2KlZb.js";
3
+ import { Anchored, useProjectorBinding } from "./anchored.js";
4
+ import { n as usePaintsPagePart } from "./page-layers-Bkaaz8Zf.js";
5
+ import { t as INERT } from "./inert-D8fkennb.js";
6
+ import { t as SvgShapes } from "./svg-shapes-Dm1yTR1b.js";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { annotationChromePaint, annotationDrawingOf, bakedAppearanceOf, chromeInPixels, createShownUrls, createTextBoxEditorFollower, editingTextKeyOf, enrichCommentThreads, frameInPixels, freeTextBoxOf, ghostOpacity, installFilePickerProvider, layerTextBoxesOf, loadAppearanceUrls, loadObjectUrl, lookFrameOf, ownTextBoxOf, paint, paintDefault, pickRequestedFile, pictureOrPainting, rasterInFrame, rectInPixels, registerRendererBehaviors, sameAnnotationAnchor, sameCreationDraftAnchor, sameRotationAnchor, sameSelectionAnchor, sceneViewBox, shownAppearance, svgShapesOf, textBoxEditorScaleOf } from "@embedpdf/web";
9
+ import * as React$1 from "react";
10
+ import { useEffect, useRef, useState } from "react";
11
+ import { InteractionToken } from "@embedpdf/plugin-interaction/contract";
12
+ import { RenderToken } from "@embedpdf/plugin-render/contract/host";
13
+ import { AnnotationToken, annotationKey } from "@embedpdf/plugin-annotation";
14
+ import { MITER_LIMIT, hasLiveDrawing, scene } from "@embedpdf/core-annotation";
15
+ import { AnnotationToken as AnnotationToken$1, previewBucket } from "@embedpdf/plugin-annotation/contract/host";
16
+ import { AnnotationToken as AnnotationToken$2, annotationState } from "@embedpdf/plugin-annotation/contract";
17
+ //#region src/annotation-hooks.ts
18
+ /**
19
+ * The annotation hooks other feature entries use too (the form plugin reads
20
+ * the selection), kept apart so they don't import the whole annotation
21
+ * feature: the state and the settings, each from its declaration.
22
+ */
23
+ /**
24
+ * The annotation state: `status` (`'loading'` until every annotation is in,
25
+ * then `'ready'`), the `selected` annotations, the one `hovered` under the
26
+ * pointer and the text box being typed in (`editing`). Re-renders only when a
27
+ * field changes, or the value `select` picks. Empty without a document.
28
+ */
29
+ const useAnnotationState = stateHook(annotationState);
30
+ /**
31
+ * The annotation settings (`snap`, `chrome`, `afterCreate`, `tools`), or the
32
+ * value `select` picks. They belong to the plugin, so they read without a
33
+ * document; change them with `useAnnotation().updateSettings()`.
34
+ */
35
+ const useAnnotationSettings = settingsHook(AnnotationToken$2);
36
+ //#endregion
37
+ //#region src/annotation-menu.tsx
38
+ /**
39
+ * Your own menu next to the selection (one anchor, also for a selection over
40
+ * several pages), clear of the rotation handle. It hides while the selection
41
+ * is dragged, resized or turned. What's in it is yours: build it from
42
+ * `useAnnotation()` and `useAnnotationState()`.
43
+ */
44
+ function AnnotationMenu({ children, gap = 15, placement = "top" }) {
45
+ const { projector } = useProjectorBinding();
46
+ const anchor = useOptionalSelector(AnnotationToken$1, (annotation) => {
47
+ const selectionAnchor = annotation.selection.getAnchor();
48
+ if (!selectionAnchor) return null;
49
+ const env = projector.viewEnv(selectionAnchor.page);
50
+ return env ? annotation.getSelectionAnchorIn(env) : selectionAnchor;
51
+ }, null, sameSelectionAnchor);
52
+ if (!anchor) return null;
53
+ return /* @__PURE__ */ jsx(Anchored, {
54
+ anchor: {
55
+ page: anchor.page,
56
+ bounds: anchor.bounds,
57
+ ...anchor.rotationHandle ? { avoid: [anchor.rotationHandle] } : {}
58
+ },
59
+ placement,
60
+ gap,
61
+ children
62
+ });
63
+ }
64
+ /** Floats over a live multi-click creation draft (polygon, polyline, …). */
65
+ function AnnotationDraftMenu({ children, gap = 8, placement = "top" }) {
66
+ const anchor = useOptionalSelector(AnnotationToken$2, (annotation) => annotation.draft.get(), null, sameCreationDraftAnchor);
67
+ if (!anchor) return null;
68
+ return /* @__PURE__ */ jsx(Anchored, {
69
+ anchor,
70
+ placement,
71
+ gap,
72
+ children: children(anchor)
73
+ });
74
+ }
75
+ /**
76
+ * Follows the pointer while a selection is being turned, upright however the
77
+ * page is shown: it floats over the page like the menus, not in it. Shows
78
+ * nothing when no rotation is in progress.
79
+ */
80
+ function AnnotationRotationBadge({ children, gap = 16, placement = "right" }) {
81
+ const rotation = useOptionalSelector(AnnotationToken$2, (annotation) => annotation.selection.getRotationAnchor(), null, sameRotationAnchor);
82
+ const readout = useAnnotationSettings((settings) => settings.chrome.readout);
83
+ if (!rotation || !children && !readout.enabled) return null;
84
+ return /* @__PURE__ */ jsx(Anchored, {
85
+ anchor: {
86
+ page: rotation.page,
87
+ bounds: {
88
+ ...rotation.at,
89
+ width: 0,
90
+ height: 0
91
+ }
92
+ },
93
+ placement,
94
+ gap,
95
+ children: children ? children(rotation) : /* @__PURE__ */ jsxs("div", {
96
+ style: {
97
+ pointerEvents: "none",
98
+ whiteSpace: "nowrap",
99
+ borderRadius: 4,
100
+ padding: "2px 6px",
101
+ fontFamily: paintDefault("font-mono"),
102
+ fontSize: 12,
103
+ background: paint("readout-background", readout.background),
104
+ color: paint("readout-color", readout.color)
105
+ },
106
+ children: [rotation.angle, "°"]
107
+ })
108
+ });
109
+ }
110
+ //#endregion
111
+ //#region src/annotation.tsx
112
+ /** How much the layer scales the look around it: 1 outside a look, or in one drawn at its size on screen. */
113
+ const LookScaleContext = React$1.createContext(1);
114
+ /**
115
+ * The box an annotation draws into, placed, sized and turned like the
116
+ * annotation (`item.frame`) inside the page layer, which the page itself
117
+ * turns. The annotation's own drawing and any look of yours draw inside it.
118
+ */
119
+ function AnnotationFrame({ item, page, interactive = false, inert = false, children }) {
120
+ const box = frameInPixels(item.frame, page.transform);
121
+ return /* @__PURE__ */ jsx("div", {
122
+ ...inert ? INERT : {},
123
+ style: {
124
+ position: "absolute",
125
+ left: box.left,
126
+ top: box.top,
127
+ width: box.width,
128
+ height: box.height,
129
+ transform: box.transform,
130
+ transformOrigin: "center",
131
+ mixBlendMode: item.blend,
132
+ pointerEvents: interactive ? "auto" : "none"
133
+ },
134
+ children
135
+ });
136
+ }
137
+ /** SVG attribute names as React props: `stroke-width` is `strokeWidth`. */
138
+ /**
139
+ * The scene, filling the item's frame: drawn upright in it, the frame turns
140
+ * it. The core computed the box and the painted scene; `@embedpdf/web`
141
+ * describes each scene node as one SVG element, so there is no per-kind
142
+ * logic and no bounds math here.
143
+ */
144
+ function Shape({ item }) {
145
+ const viewBox = sceneViewBox(item.box);
146
+ if (!viewBox) return null;
147
+ return /* @__PURE__ */ jsx("svg", {
148
+ viewBox,
149
+ style: {
150
+ position: "absolute",
151
+ left: 0,
152
+ top: 0,
153
+ width: "100%",
154
+ height: "100%",
155
+ overflow: "visible",
156
+ pointerEvents: "none",
157
+ ...item.source === "ghost" ? { opacity: ghostOpacity(item.ghostOpacity ?? .5) } : {}
158
+ },
159
+ children: /* @__PURE__ */ jsx(SvgShapes, { shapes: svgShapesOf(scene(item), { miterLimit: MITER_LIMIT }) })
160
+ });
161
+ }
162
+ /** The engine's raster inside the item's frame, where `item.raster` puts it, at any frame size. */
163
+ function BakedImage({ url, box }) {
164
+ return /* @__PURE__ */ jsx("img", {
165
+ src: url,
166
+ alt: "",
167
+ draggable: false,
168
+ style: {
169
+ position: "absolute",
170
+ left: box.left,
171
+ top: box.top,
172
+ width: box.width,
173
+ height: box.height,
174
+ maxWidth: "none",
175
+ maxHeight: "none",
176
+ pointerEvents: "none",
177
+ transform: box.transform,
178
+ transformOrigin: "center"
179
+ }
180
+ });
181
+ }
182
+ /**
183
+ * The armed stamp's ghost: a see-through render of the payload drawn in the
184
+ * exact box a click would place it (the plugin computes it with the same fit
185
+ * + clamp as placement). Every other tool's ghost rides `pageItems` like a
186
+ * drawing in progress. The preview bytes live in the capability closure; this
187
+ * layer owns only the object-URL lifetime, keyed on the armed stamp — a new
188
+ * arm swaps the image, a disarm (or tool change) drops it.
189
+ */
190
+ function ToolGhostImage({ page }) {
191
+ const anno = useCapability(AnnotationToken$1);
192
+ const ghost = useSelector(AnnotationToken$1, (annotation) => annotation.getImageGhost(page.ref));
193
+ const armed = useSelector(AnnotationToken$1, (annotation) => annotation.getArmedStamp());
194
+ const [url, setUrl] = useState(null);
195
+ const bucket = ghost ? previewBucket(ghost.box.width * page.transform.renderScale) : 0;
196
+ useEffect(() => {
197
+ if (!bucket) {
198
+ setUrl(null);
199
+ return;
200
+ }
201
+ return loadObjectUrl(() => anno.renderArmedStampPreview(bucket), setUrl);
202
+ }, [
203
+ anno,
204
+ armed,
205
+ bucket
206
+ ]);
207
+ if (!ghost || !url) return null;
208
+ const frame = rectInPixels(ghost.box, page.transform);
209
+ return /* @__PURE__ */ jsx("img", {
210
+ src: url,
211
+ alt: "",
212
+ draggable: false,
213
+ style: {
214
+ position: "absolute",
215
+ left: frame.left,
216
+ top: frame.top,
217
+ width: frame.width,
218
+ height: frame.height,
219
+ maxWidth: "none",
220
+ maxHeight: "none",
221
+ pointerEvents: "none",
222
+ opacity: ghostOpacity(ghost.opacity),
223
+ ...ghost.rot ? {
224
+ transform: `rotate(${ghost.rot}deg)`,
225
+ transformOrigin: "center"
226
+ } : {}
227
+ }
228
+ });
229
+ }
230
+ /** The chrome settings, painted: follows the settings and the viewer's accent live. */
231
+ function useChromePaint() {
232
+ const chrome = useAnnotationSettings((settings) => settings.chrome);
233
+ const accent = useViewerSettings((settings) => settings.accent);
234
+ return {
235
+ chrome,
236
+ painted: React$1.useMemo(() => annotationChromePaint(chrome, accent), [chrome, accent])
237
+ };
238
+ }
239
+ /** A handle as the layer draws it: a square or a circle, `size` px across. */
240
+ function DefaultHandle({ at, size, rotation, shape, style }) {
241
+ if (shape === "circle") return /* @__PURE__ */ jsx("circle", {
242
+ cx: at.x,
243
+ cy: at.y,
244
+ r: size / 2,
245
+ strokeWidth: 1.5,
246
+ style
247
+ });
248
+ return /* @__PURE__ */ jsx("rect", {
249
+ x: at.x - size / 2,
250
+ y: at.y - size / 2,
251
+ width: size,
252
+ height: size,
253
+ strokeWidth: 1.5,
254
+ style,
255
+ ...rotation ? { transform: `rotate(${rotation} ${at.x} ${at.y})` } : {}
256
+ });
257
+ }
258
+ function Chrome({ page, components }) {
259
+ const scale = page.transform.viewScale;
260
+ const rotation = page.transform.rotation;
261
+ const zoom = page.transform.zoom;
262
+ const nodes = useSelector(AnnotationToken$1, (annotation) => annotation.listChromeNodes(page.ref, scale, rotation, zoom), shallowArray);
263
+ const { chrome, painted } = useChromePaint();
264
+ const Handle = components?.Handle;
265
+ const RotationHandle = components?.RotationHandle;
266
+ const custom = [];
267
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("svg", {
268
+ style: {
269
+ position: "absolute",
270
+ inset: 0,
271
+ overflow: "visible",
272
+ pointerEvents: "none"
273
+ },
274
+ children: chromeInPixels(nodes, page.transform).map((node, i) => {
275
+ switch (node.kind) {
276
+ case "handle":
277
+ if (Handle) {
278
+ custom.push(/* @__PURE__ */ jsx(Handle, {
279
+ at: node.at,
280
+ size: chrome.handles.size,
281
+ rotation: node.rotation,
282
+ kind: node.role,
283
+ active: node.active
284
+ }, i));
285
+ return null;
286
+ }
287
+ return /* @__PURE__ */ jsx(DefaultHandle, {
288
+ at: node.at,
289
+ size: chrome.handles.size,
290
+ rotation: node.rotation,
291
+ shape: chrome.handles.shape,
292
+ style: painted.handle
293
+ }, i);
294
+ case "guide": return /* @__PURE__ */ jsx("line", {
295
+ x1: node.from.x,
296
+ y1: node.from.y,
297
+ x2: node.to.x,
298
+ y2: node.to.y,
299
+ shapeRendering: "crispEdges",
300
+ style: painted.guide
301
+ }, i);
302
+ case "turned-outline": return /* @__PURE__ */ jsx("polygon", {
303
+ points: node.points,
304
+ fill: "none",
305
+ style: painted.outline
306
+ }, i);
307
+ case "rotation-guides": return /* @__PURE__ */ jsx("g", { children: node.lines.map((line, j) => /* @__PURE__ */ jsx("line", {
308
+ x1: line.from.x,
309
+ y1: line.from.y,
310
+ x2: line.to.x,
311
+ y2: line.to.y,
312
+ opacity: line.opacity,
313
+ style: painted.rotationGuide
314
+ }, j)) }, i);
315
+ case "rotation-handle":
316
+ if (RotationHandle) {
317
+ custom.push(/* @__PURE__ */ jsx(RotationHandle, {
318
+ at: node.at,
319
+ from: node.from,
320
+ size: chrome.rotationHandle.size,
321
+ rotation: 0,
322
+ active: false
323
+ }, i));
324
+ return null;
325
+ }
326
+ return /* @__PURE__ */ jsxs("g", { children: [chrome.rotationHandle.stalk && /* @__PURE__ */ jsx("line", {
327
+ x1: node.from.x,
328
+ y1: node.from.y,
329
+ x2: node.at.x,
330
+ y2: node.at.y,
331
+ strokeWidth: 1,
332
+ style: { stroke: painted.rotationHandle.stroke }
333
+ }), /* @__PURE__ */ jsx("circle", {
334
+ cx: node.at.x,
335
+ cy: node.at.y,
336
+ r: chrome.rotationHandle.size / 2,
337
+ strokeWidth: 1.5,
338
+ style: painted.rotationHandle
339
+ })] }, i);
340
+ case "marquee": return /* @__PURE__ */ jsx("rect", {
341
+ x: node.box.left,
342
+ y: node.box.top,
343
+ width: node.box.width,
344
+ height: node.box.height,
345
+ strokeWidth: 1,
346
+ strokeDasharray: "4 3",
347
+ style: painted.marquee
348
+ }, i);
349
+ case "outline": return /* @__PURE__ */ jsx("rect", {
350
+ x: node.box.left,
351
+ y: node.box.top,
352
+ width: node.box.width,
353
+ height: node.box.height,
354
+ fill: "none",
355
+ style: painted.outline
356
+ }, i);
357
+ }
358
+ })
359
+ }), custom.length > 0 && /* @__PURE__ */ jsx("div", {
360
+ style: {
361
+ position: "absolute",
362
+ inset: 0,
363
+ pointerEvents: "none"
364
+ },
365
+ children: custom
366
+ })] });
367
+ }
368
+ /**
369
+ * Make an element the editor of a text box: `@embedpdf/web`'s text box
370
+ * editor binds it (rich text, focus and `contentEditable` following
371
+ * `item.editing`, presses kept inside), and its follower attaches again for
372
+ * another element or document and hands it the item and the scale. Returns
373
+ * the ref callback for the element.
374
+ */
375
+ function useTextBoxEditor(item, scale) {
376
+ const anno = useCapability(AnnotationToken$1);
377
+ const [element, setElement] = useState(null);
378
+ const [follower] = useState(() => createTextBoxEditorFollower());
379
+ useEffect(() => follower.follow(element, anno, item, scale), [
380
+ follower,
381
+ anno,
382
+ element,
383
+ item,
384
+ scale
385
+ ]);
386
+ useEffect(() => () => follower.detach(), [follower]);
387
+ return setElement;
388
+ }
389
+ /** A free text annotation: the same styled element for reading and typing. */
390
+ function FreeText({ item, page }) {
391
+ const { painted } = useChromePaint();
392
+ const box = freeTextBoxOf(item, page.transform, painted.textOutline);
393
+ return /* @__PURE__ */ jsx("div", {
394
+ ref: useTextBoxEditor(item, box.scale),
395
+ suppressContentEditableWarning: true,
396
+ style: box.style
397
+ });
398
+ }
399
+ const NO_STYLE = {};
400
+ /**
401
+ * Make your own element the editor of a text box you draw yourself (a
402
+ * renderer for free text): it draws the runs, turns typing back into runs,
403
+ * keeps the caret when the style changes, and handles pasting, input methods
404
+ * and the format shortcuts. The formatting calls (`text.toggleFormat`,
405
+ * `selection.update`) work on it as they do on the built-in one.
406
+ */
407
+ function useRichTextEditor(annotation) {
408
+ const page = usePage();
409
+ const zoom = page.transform.zoom;
410
+ const rotation = page.transform.rotation;
411
+ const item = useOptionalSelector(AnnotationToken$1, (anno) => anno.getTextItem(annotation.ref, {
412
+ zoom,
413
+ rotation
414
+ }), null);
415
+ const scale = textBoxEditorScaleOf(item, page.transform, React$1.useContext(LookScaleContext));
416
+ const own = React$1.useMemo(() => item ? ownTextBoxOf(item, scale) : null, [item, scale]);
417
+ return {
418
+ ref: useTextBoxEditor(item, own?.scale ?? scale),
419
+ style: own?.style ?? NO_STYLE,
420
+ editing: item?.editing ?? false
421
+ };
422
+ }
423
+ /**
424
+ * Register the behaviors this layer's `interactive` renderers need, through
425
+ * `@embedpdf/web`'s `registerRendererBehaviors`: counted per capability and
426
+ * entry, since the layer mounts once per page. Entry identity is the key,
427
+ * hence the "define entries outside render" rule on {@link AnnotationRenderer}.
428
+ * Once they are registered the layer draws again: its drawings ask them.
429
+ */
430
+ function useRendererBehaviors(anno, activeToolId, renderers) {
431
+ const toolRef = useRef(activeToolId);
432
+ toolRef.current = activeToolId;
433
+ const [, setRegistrations] = useState(0);
434
+ useEffect(() => {
435
+ if (!renderers) return;
436
+ const release = registerRendererBehaviors(anno, renderers, () => toolRef.current());
437
+ setRegistrations((count) => count + 1);
438
+ return release;
439
+ }, [anno, renderers]);
440
+ }
441
+ /**
442
+ * Draws a page's annotations, the selection's outline and handles, the tool's
443
+ * preview and the text boxes being typed in. Put it above the rendered page:
444
+ * while it's there, the render layer leaves the annotations out of the
445
+ * page's picture.
446
+ */
447
+ function AnnotationLayer({ renderers, components } = {}) {
448
+ const page = usePage();
449
+ const anno = useCapability(AnnotationToken$1);
450
+ useOptionalSelector(InteractionToken, (interaction) => interaction.getActiveToolId(), "");
451
+ const interaction = useOptionalCapability(InteractionToken);
452
+ const viewZoom = page.transform.zoom;
453
+ const viewRotation = page.transform.rotation;
454
+ const items = useSelector(AnnotationToken$1, (annotation) => annotation.listPageItems(page.ref, {
455
+ zoom: viewZoom,
456
+ rotation: viewRotation
457
+ }), shallowArray);
458
+ const texts = useSelector(AnnotationToken$1, (annotation) => annotation.listTextItems(page.ref, {
459
+ zoom: viewZoom,
460
+ rotation: viewRotation
461
+ }), shallowArray);
462
+ const [urls, setUrls] = useState(null);
463
+ const [shown] = useState(createShownUrls);
464
+ useEffect(() => () => shown.release(), [shown]);
465
+ useRendererBehaviors(anno, () => interaction?.getActiveToolId() ?? "", renderers);
466
+ usePaintsPagePart(page.ref, "annotations");
467
+ const previousRenderers = useRef(renderers);
468
+ if (renderers && previousRenderers.current && renderers !== previousRenderers.current && shallowArray(renderers, previousRenderers.current)) devWarn("annotation-renderers-inline", "<AnnotationLayer renderers> was given a new array with the same entries — define it outside render (module scope or useMemo), because entry identity keys the behavior registration.");
469
+ previousRenderers.current = renderers;
470
+ const bakedKey = useSelector(AnnotationToken$1, (annotation) => annotation.getAppearanceEpoch(page.ref));
471
+ const bakeScale = useOptionalSelector(RenderToken, (render) => render.getAppearanceScale(page.transform.renderScale), page.transform.renderScale);
472
+ useEffect(() => loadAppearanceUrls(shown, (signal) => anno.renderAppearances(page.ref, bakeScale, signal), annotationKey, setUrls), [
473
+ shown,
474
+ anno,
475
+ page.ref,
476
+ bakeScale,
477
+ bakedKey
478
+ ]);
479
+ /** The text box being typed in, by key. */
480
+ const editingKey = editingTextKeyOf(texts, annotationKey);
481
+ return /* @__PURE__ */ jsxs("div", {
482
+ style: {
483
+ position: "absolute",
484
+ inset: 0,
485
+ pointerEvents: "none"
486
+ },
487
+ children: [
488
+ items.map((item) => {
489
+ const state = item.annotation?.appearanceState ?? null;
490
+ const shows = pictureOrPainting({
491
+ pending: item.source !== "baked",
492
+ picture: urls && shownAppearance(urls, item.id, state),
493
+ version: item.pictureVersion ?? 0,
494
+ loaded: urls !== null,
495
+ paint: () => hasLiveDrawing(item) ? item : null
496
+ });
497
+ const native = shows?.kind === "painting" ? /* @__PURE__ */ jsx(Shape, { item }) : shows?.kind === "picture" && item.raster ? /* @__PURE__ */ jsx(BakedImage, {
498
+ url: shows.picture.url,
499
+ box: rasterInFrame(item.raster, item.frame)
500
+ }) : null;
501
+ const framed = (content, options) => /* @__PURE__ */ jsx(AnnotationFrame, {
502
+ item,
503
+ page,
504
+ ...options,
505
+ children: content
506
+ }, item.id);
507
+ const annotation = item.annotation;
508
+ if (!annotation) return framed(native);
509
+ /** Your look in the frame: drawn at the annotation's 100% size and scaled with the page, unless it opts out. */
510
+ const look = (entry, interactive) => {
511
+ const pixels = frameInPixels(item.frame, page.transform);
512
+ const scaled = entry.scale !== false;
513
+ const Look = entry.component;
514
+ const drawn = /* @__PURE__ */ jsx(Look, {
515
+ annotation,
516
+ frame: lookFrameOf(pixels, scaled),
517
+ native,
518
+ appearance: urls && bakedAppearanceOf(urls, item.id, state),
519
+ hovered: item.hovered ?? false,
520
+ selected: item.selected,
521
+ interactive
522
+ });
523
+ if (!scaled) return drawn;
524
+ return /* @__PURE__ */ jsx("div", {
525
+ style: {
526
+ position: "absolute",
527
+ left: 0,
528
+ top: 0,
529
+ width: pixels.design.width,
530
+ height: pixels.design.height,
531
+ transform: `scale(${pixels.scale})`,
532
+ transformOrigin: "0 0"
533
+ },
534
+ children: /* @__PURE__ */ jsx(LookScaleContext.Provider, {
535
+ value: pixels.scale,
536
+ children: drawn
537
+ })
538
+ });
539
+ };
540
+ const typing = editingKey !== null && annotationKey(annotation.ref) === editingKey;
541
+ const drawing = annotationDrawingOf(annotation, anno, renderers, typing);
542
+ switch (drawing.kind) {
543
+ case "owned": {
544
+ const Owner = drawing.entry.component;
545
+ return /* @__PURE__ */ jsx(Owner, {
546
+ annotation,
547
+ item,
548
+ page,
549
+ native: framed(native),
550
+ hovered: item.hovered ?? false,
551
+ selected: item.selected,
552
+ interactive: true
553
+ }, item.id);
554
+ }
555
+ case "look": return framed(look(drawing.entry, drawing.interactive), {
556
+ interactive: drawing.interactive,
557
+ inert: drawing.inert
558
+ });
559
+ case "native": return framed(native, { inert: drawing.inert });
560
+ }
561
+ }),
562
+ layerTextBoxesOf(texts, items, renderers, annotationKey).map((text) => /* @__PURE__ */ jsx(FreeText, {
563
+ item: text,
564
+ page
565
+ }, text.id)),
566
+ /* @__PURE__ */ jsx(ToolGhostImage, { page }),
567
+ /* @__PURE__ */ jsx(Chrome, {
568
+ page,
569
+ components
570
+ })
571
+ ]
572
+ });
573
+ }
574
+ /**
575
+ * The default file-picker provider: the built-in file dialog (from
576
+ * `@embedpdf/web`), honouring the tool's `accept` filter. This is the adapter
577
+ * fulfilling the plugin's DOM-free port — the dialog lives in the framework
578
+ * layer, never in the plugin.
579
+ */
580
+ const filePickerProvider = pickRequestedFile;
581
+ /**
582
+ * Install the file-picker provider for the active document — the one port
583
+ * behind every click-then-pick tool (a stamp `'prompt'` source, the file-
584
+ * attachment tool). Call once at a document-scoped spot (not inside
585
+ * `<AnnotationLayer>`, which is per page). Defaults to
586
+ * {@link filePickerProvider}, so a bare `useFilePickerProvider()` makes all of
587
+ * them work out of the box; pass a custom provider (asset library, cloud
588
+ * drive — switch on `req.subtype` / `req.toolId`) or `null` to make
589
+ * click-then-pick tools inert. Cleared on unmount.
590
+ */
591
+ function useFilePickerProvider(provider = filePickerProvider) {
592
+ const anno = useOptionalCapability(AnnotationToken);
593
+ useEffect(() => {
594
+ if (!anno) return;
595
+ return installFilePickerProvider(anno, provider, () => devWarn("file-picker-provider-twice", "useFilePickerProvider() is called from two mounted components for the same document — the later one wins. Call it once, at a document-scoped spot."));
596
+ }, [anno, provider]);
597
+ }
598
+ function useAnnotation() {
599
+ return useCapability(AnnotationToken);
600
+ }
601
+ /** Listen to one annotation event while the component is mounted: `useAnnotationEvent((annotation) => annotation.onCreated, handler)`. */
602
+ function useAnnotationEvent(select, handler) {
603
+ useCapabilityEvent(AnnotationToken, select, handler);
604
+ }
605
+ const NO_ANNOTATIONS = [];
606
+ /**
607
+ * The annotations matching `filter` (some pages, one kind), in drawing order,
608
+ * as the user sees them; the same array while they stay the same. Empty
609
+ * without a document.
610
+ */
611
+ function useAnnotationList(filter) {
612
+ const key = filter ? `${(filter.pages ?? []).map((page) => typeof page === "number" ? `#${page}` : page.objectNumber).join(",")}|${filter.pages ? "p" : ""}|${filter.subtype ?? ""}` : "";
613
+ const stable = React$1.useMemo(() => filter, [key]);
614
+ return useOptionalSelector(AnnotationToken, (annotation) => annotation.list(stable), NO_ANNOTATIONS, shallowArray);
615
+ }
616
+ const NO_DEFAULTS = {};
617
+ /**
618
+ * A tool's defaults: the fields its next annotation starts with, over the
619
+ * engine's. The component re-renders when they change, so a color picker
620
+ * always shows the current color. Empty without a document.
621
+ */
622
+ function useAnnotationDefaults(toolId) {
623
+ return useOptionalSelector(AnnotationToken, (annotation) => annotation.tools.getDefaults(toolId), NO_DEFAULTS);
624
+ }
625
+ const NO_PROPERTIES = {
626
+ properties: [],
627
+ values: {},
628
+ mixed: []
629
+ };
630
+ /**
631
+ * What a style panel shows: the selection's properties (`selection.getProperties()`),
632
+ * or, given a tool id, the tool's (`tools.getProperties(id)`). The component
633
+ * re-renders when they change. Empty without a document.
634
+ */
635
+ function useAnnotationProperties(toolId) {
636
+ return useOptionalSelector(AnnotationToken, (annotation) => toolId === void 0 ? annotation.selection.getProperties() : annotation.tools.getProperties(toolId), NO_PROPERTIES);
637
+ }
638
+ /**
639
+ * An anchor for `<Anchored>` that keeps a card or a badge attached to one
640
+ * annotation: its page and the box around what it shows, following a move
641
+ * as it happens. `null` for `null`, or an annotation that isn't here. The
642
+ * component re-renders when the annotation moves, not while people scroll or
643
+ * zoom: a note that keeps its size on screen hands `<Anchored>` its
644
+ * `boundsIn`.
645
+ */
646
+ function useAnnotationAnchor(ref) {
647
+ const key = ref ? annotationKey(ref) : null;
648
+ const stable = React$1.useMemo(() => ref, [key]);
649
+ return useOptionalSelector(AnnotationToken$1, (annotation) => stable ? annotation.getAnnotationAnchor(stable) : null, null, sameAnnotationAnchor);
650
+ }
651
+ /** The comments API: the `comments` part of `useAnnotation()`. Pair it with
652
+ * {@link useCommentThreads} for the threads to show. */
653
+ function useComments() {
654
+ return useCapability(AnnotationToken).comments;
655
+ }
656
+ const EMPTY_PAGES = [];
657
+ const NO_THREADS = [];
658
+ /**
659
+ * Every comment thread in the document, display-ordered (page position →
660
+ * top of page → creation date) and enriched with `pageIndex`/`pageLabel`.
661
+ * Subscribed to both stores: annotation writes (own, remote, hydration)
662
+ * recompute the threads; page moves/deletes re-run the join. Reference-
663
+ * stable between changes — safe to memo child renders on the array.
664
+ */
665
+ function useCommentThreads() {
666
+ const docId = useDocumentId();
667
+ const threads = useOptionalSelector(AnnotationToken, (annotation) => annotation.comments.listThreads(), NO_THREADS);
668
+ const pages = useKernelValue((kernel) => docId ? kernel.documents.listPages(docId) : EMPTY_PAGES);
669
+ return React$1.useMemo(() => enrichCommentThreads(threads, pages), [threads, pages]);
670
+ }
671
+ /** The enriched thread containing any member ref (root, reply, grouped part,
672
+ * state annotation), or null. */
673
+ function useCommentThread(ref) {
674
+ const views = useCommentThreads();
675
+ const api = useOptionalCapability(AnnotationToken);
676
+ if (ref == null || !api) return null;
677
+ const thread = api.comments.getThread(ref);
678
+ if (!thread) return null;
679
+ return views.find((view) => annotationKey(view.root.ref) === annotationKey(thread.root.ref)) ?? null;
680
+ }
681
+ //#endregion
682
+ export { useAnnotationSettings as _, useAnnotationDefaults as a, useAnnotationProperties as c, useComments as d, useFilePickerProvider as f, AnnotationRotationBadge as g, AnnotationMenu as h, useAnnotationAnchor as i, useCommentThread as l, AnnotationDraftMenu as m, filePickerProvider as n, useAnnotationEvent as o, useRichTextEditor as p, useAnnotation as r, useAnnotationList as s, AnnotationLayer as t, useCommentThreads as u, useAnnotationState as v };
683
+
684
+ //# sourceMappingURL=annotation-CDI8CFb3.js.map