@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.
- package/dist/AnnotationList-DcyhF2kU-CiBFOq1z.d.cts +878 -0
- package/dist/AnnotationList-DcyhF2kU-CiBFOq1z.d.ts +878 -0
- package/dist/actions.cjs +25 -5
- package/dist/actions.cjs.map +1 -1
- package/dist/actions.d.cts +18 -5
- package/dist/actions.d.ts +18 -5
- package/dist/actions.js +22 -6
- package/dist/actions.js.map +1 -1
- package/dist/anchored-DeX95xSd.d.ts +85 -0
- package/dist/anchored-DzN3JywS.d.cts +85 -0
- package/dist/anchored.cjs +71 -28
- package/dist/anchored.cjs.map +1 -1
- package/dist/anchored.d.cts +2 -45
- package/dist/anchored.d.ts +2 -45
- package/dist/anchored.js +56 -19
- package/dist/anchored.js.map +1 -1
- package/dist/annotation-3UvABfJm.d.cts +305 -0
- package/dist/annotation-BNHQpMKv.cjs +806 -0
- package/dist/annotation-BNHQpMKv.cjs.map +1 -0
- package/dist/annotation-CDI8CFb3.js +684 -0
- package/dist/annotation-CDI8CFb3.js.map +1 -0
- package/dist/annotation-DhEfs0pH.d.ts +305 -0
- package/dist/annotation.cjs +20 -784
- package/dist/annotation.d.cts +2 -2
- package/dist/annotation.d.ts +2 -2
- package/dist/annotation.js +2 -769
- package/dist/attachment.cjs +39 -0
- package/dist/attachment.cjs.map +1 -0
- package/dist/attachment.d.cts +29 -0
- package/dist/attachment.d.ts +29 -0
- package/dist/attachment.js +28 -0
- package/dist/attachment.js.map +1 -0
- package/dist/commands.cjs +68 -28
- package/dist/commands.cjs.map +1 -1
- package/dist/commands.d.cts +37 -10
- package/dist/commands.d.ts +37 -10
- package/dist/commands.js +68 -31
- package/dist/commands.js.map +1 -1
- package/dist/form-BSGvjA5D.js +511 -0
- package/dist/form-BSGvjA5D.js.map +1 -0
- package/dist/form-BgztZyOK.cjs +548 -0
- package/dist/form-BgztZyOK.cjs.map +1 -0
- package/dist/form.cjs +5 -5
- package/dist/form.d.cts +41 -2
- package/dist/form.d.ts +41 -2
- package/dist/form.js +2 -3
- package/dist/history.cjs +38 -0
- package/dist/history.cjs.map +1 -0
- package/dist/history.d.cts +27 -0
- package/dist/history.d.ts +27 -0
- package/dist/history.js +27 -0
- package/dist/history.js.map +1 -0
- package/dist/i18n.cjs +26 -30
- package/dist/i18n.cjs.map +1 -1
- package/dist/i18n.d.cts +24 -21
- package/dist/i18n.d.ts +24 -21
- package/dist/i18n.js +24 -31
- package/dist/i18n.js.map +1 -1
- package/dist/index.cjs +227 -57
- package/dist/index.d.cts +35 -32
- package/dist/index.d.ts +35 -32
- package/dist/index.js +36 -30
- package/dist/inert-CmBEbKCn.cjs +19 -0
- package/dist/inert-CmBEbKCn.cjs.map +1 -0
- package/dist/inert-D8fkennb.js +14 -0
- package/dist/inert-D8fkennb.js.map +1 -0
- package/dist/interaction.cjs +48 -102
- package/dist/interaction.cjs.map +1 -1
- package/dist/interaction.d.cts +23 -32
- package/dist/interaction.d.ts +23 -32
- package/dist/interaction.js +33 -102
- package/dist/interaction.js.map +1 -1
- package/dist/link.cjs +65 -104
- package/dist/link.cjs.map +1 -1
- package/dist/link.d.cts +21 -16
- package/dist/link.d.ts +22 -17
- package/dist/link.js +67 -107
- package/dist/link.js.map +1 -1
- package/dist/measurement.cjs +36 -11
- package/dist/measurement.cjs.map +1 -1
- package/dist/measurement.d.cts +33 -7
- package/dist/measurement.d.ts +33 -7
- package/dist/measurement.js +35 -14
- package/dist/measurement.js.map +1 -1
- package/dist/metadata.cjs +20 -7
- package/dist/metadata.cjs.map +1 -1
- package/dist/metadata.d.cts +22 -7
- package/dist/metadata.d.ts +22 -7
- package/dist/metadata.js +20 -10
- package/dist/metadata.js.map +1 -1
- package/dist/outline.cjs +39 -0
- package/dist/outline.cjs.map +1 -0
- package/dist/outline.d.cts +31 -0
- package/dist/outline.d.ts +31 -0
- package/dist/outline.js +28 -0
- package/dist/outline.js.map +1 -0
- package/dist/page-edit.cjs +15 -3
- package/dist/page-edit.cjs.map +1 -1
- package/dist/page-edit.d.cts +17 -2
- package/dist/page-edit.d.ts +17 -2
- package/dist/page-edit.js +15 -5
- package/dist/page-edit.js.map +1 -1
- package/dist/page-layers-Bkaaz8Zf.js +26 -0
- package/dist/page-layers-Bkaaz8Zf.js.map +1 -0
- package/dist/page-layers-BloZDoOV.cjs +37 -0
- package/dist/page-layers-BloZDoOV.cjs.map +1 -0
- package/dist/page-view.cjs +89 -82
- package/dist/page-view.cjs.map +1 -1
- package/dist/page-view.d.cts +14 -7
- package/dist/page-view.d.ts +18 -11
- package/dist/page-view.js +86 -81
- package/dist/page-view.js.map +1 -1
- package/dist/redaction.cjs +30 -15
- package/dist/redaction.cjs.map +1 -1
- package/dist/redaction.d.cts +27 -9
- package/dist/redaction.d.ts +27 -9
- package/dist/redaction.js +29 -18
- package/dist/redaction.js.map +1 -1
- package/dist/render.cjs +71 -46
- package/dist/render.cjs.map +1 -1
- package/dist/render.d.cts +17 -5
- package/dist/render.d.ts +17 -5
- package/dist/render.js +70 -49
- package/dist/render.js.map +1 -1
- package/dist/runtime-BfnpyfY0.cjs +556 -0
- package/dist/runtime-BfnpyfY0.cjs.map +1 -0
- package/dist/runtime-DBEBlpQV.d.cts +237 -0
- package/dist/runtime-V3MVMb91.d.ts +237 -0
- package/dist/runtime-tD5iJU83.js +399 -0
- package/dist/runtime-tD5iJU83.js.map +1 -0
- package/dist/runtime.cjs +45 -324
- package/dist/runtime.d.cts +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +2 -306
- package/dist/search.cjs +81 -50
- package/dist/search.cjs.map +1 -1
- package/dist/search.d.cts +37 -24
- package/dist/search.d.ts +37 -24
- package/dist/search.js +81 -53
- package/dist/search.js.map +1 -1
- package/dist/selection.cjs +105 -108
- package/dist/selection.cjs.map +1 -1
- package/dist/selection.d.cts +54 -26
- package/dist/selection.d.ts +56 -28
- package/dist/selection.js +103 -110
- package/dist/selection.js.map +1 -1
- package/dist/shell.cjs +36 -21
- package/dist/shell.cjs.map +1 -1
- package/dist/shell.d.cts +32 -17
- package/dist/shell.d.ts +32 -17
- package/dist/shell.js +36 -24
- package/dist/shell.js.map +1 -1
- package/dist/signature.cjs +29 -48
- package/dist/signature.cjs.map +1 -1
- package/dist/signature.d.cts +26 -26
- package/dist/signature.d.ts +26 -26
- package/dist/signature.js +30 -48
- package/dist/signature.js.map +1 -1
- package/dist/stage-B7BG2e8Q.cjs +369 -0
- package/dist/stage-B7BG2e8Q.cjs.map +1 -0
- package/dist/stage-BqfBjDu6.js +302 -0
- package/dist/stage-BqfBjDu6.js.map +1 -0
- package/dist/stage-ByFPD-Fv.d.cts +117 -0
- package/dist/stage-DaboaheR.d.ts +117 -0
- package/dist/stage-scope-CQgCuf1w.cjs +46 -0
- package/dist/stage-scope-CQgCuf1w.cjs.map +1 -0
- package/dist/stage-scope-D7ZeNduT.js +23 -0
- package/dist/stage-scope-D7ZeNduT.js.map +1 -0
- package/dist/stage.cjs +12 -235
- package/dist/stage.d.cts +2 -116
- package/dist/stage.d.ts +2 -116
- package/dist/stage.js +3 -228
- package/dist/stamp.cjs +41 -35
- package/dist/stamp.cjs.map +1 -1
- package/dist/stamp.d.cts +25 -18
- package/dist/stamp.d.ts +25 -18
- package/dist/stamp.js +40 -37
- package/dist/stamp.js.map +1 -1
- package/dist/state-0K1I5cM4.d.cts +29 -0
- package/dist/state-0K1I5cM4.d.ts +29 -0
- package/dist/state-CzI2KlZb.js +62 -0
- package/dist/state-CzI2KlZb.js.map +1 -0
- package/dist/state-Dtf8HAue.cjs +73 -0
- package/dist/state-Dtf8HAue.cjs.map +1 -0
- package/dist/svg-shapes-Dm1yTR1b.js +40 -0
- package/dist/svg-shapes-Dm1yTR1b.js.map +1 -0
- package/dist/svg-shapes-zo0GNkc9.cjs +53 -0
- package/dist/svg-shapes-zo0GNkc9.cjs.map +1 -0
- package/dist/toolbar.cjs +297 -295
- package/dist/toolbar.cjs.map +1 -1
- package/dist/toolbar.d.cts +58 -68
- package/dist/toolbar.d.ts +67 -77
- package/dist/toolbar.js +271 -293
- package/dist/toolbar.js.map +1 -1
- package/dist/view-manager.cjs +34 -0
- package/dist/view-manager.cjs.map +1 -0
- package/dist/view-manager.d.cts +21 -0
- package/dist/view-manager.d.ts +21 -0
- package/dist/view-manager.js +23 -0
- package/dist/view-manager.js.map +1 -0
- package/package.json +47 -39
- package/dist/annotation-BCED_p9H.d.cts +0 -160
- package/dist/annotation-anchors-CetwM1g7.js +0 -15
- package/dist/annotation-anchors-CetwM1g7.js.map +0 -1
- package/dist/annotation-anchors-DuYRBJLl.cjs +0 -26
- package/dist/annotation-anchors-DuYRBJLl.cjs.map +0 -1
- package/dist/annotation-hooks-BB5ZhPpf.cjs +0 -16
- package/dist/annotation-hooks-BB5ZhPpf.cjs.map +0 -1
- package/dist/annotation-hooks-Df8EmzDO.js +0 -11
- package/dist/annotation-hooks-Df8EmzDO.js.map +0 -1
- package/dist/annotation-k38KDlIZ.d.ts +0 -160
- package/dist/annotation-menu.cjs +0 -64
- package/dist/annotation-menu.cjs.map +0 -1
- package/dist/annotation-menu.d.cts +0 -33
- package/dist/annotation-menu.d.ts +0 -33
- package/dist/annotation-menu.js +0 -48
- package/dist/annotation-menu.js.map +0 -1
- package/dist/annotation.cjs.map +0 -1
- package/dist/annotation.js.map +0 -1
- package/dist/form-BVumS7up.cjs +0 -926
- package/dist/form-BVumS7up.cjs.map +0 -1
- package/dist/form-Bdjk0Z3T.d.cts +0 -537
- package/dist/form-CK3mp99m.js +0 -895
- package/dist/form-CK3mp99m.js.map +0 -1
- package/dist/form-CYRYgthn.d.ts +0 -537
- package/dist/rolldown-runtime-BBjsoOtd.js +0 -27
- package/dist/runtime-DE76hlnl.d.ts +0 -216
- package/dist/runtime-umHA_xHt.d.cts +0 -216
- package/dist/runtime.cjs.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/scrollbar.cjs +0 -241
- package/dist/scrollbar.cjs.map +0 -1
- package/dist/scrollbar.d.cts +0 -42
- package/dist/scrollbar.d.ts +0 -42
- package/dist/scrollbar.js +0 -213
- package/dist/scrollbar.js.map +0 -1
- package/dist/stage.cjs.map +0 -1
- package/dist/stage.js.map +0 -1
- package/dist/views.cjs +0 -35
- package/dist/views.cjs.map +0 -1
- package/dist/views.d.cts +0 -21
- package/dist/views.d.ts +0 -21
- package/dist/views.js +0 -27
- 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
|