@embedpdf/plugin-annotation 3.0.0-next.10 → 3.0.0-next.11
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/authoring-BhtyfsMx.d.cts +37 -0
- package/dist/authoring-R4ezdnXd.d.ts +37 -0
- package/dist/authoring.cjs +16 -0
- package/dist/authoring.d.cts +2 -0
- package/dist/authoring.d.ts +2 -0
- package/dist/authoring.js +3 -0
- package/dist/{capability-Cl9x8oLS.cjs → capability-Csb9WMm-.cjs} +256 -348
- package/dist/capability-Csb9WMm-.cjs.map +1 -0
- package/dist/{capability-BRf0HrOi.js → capability-DBsr2D-L.js} +191 -259
- package/dist/capability-DBsr2D-L.js.map +1 -0
- package/dist/contract/host.cjs +3 -0
- package/dist/contract/host.d.cts +2 -0
- package/dist/contract/host.d.ts +2 -0
- package/dist/contract/host.js +2 -0
- package/dist/contract.cjs +8 -0
- package/dist/contract.cjs.map +1 -0
- package/dist/contract.d.cts +10 -0
- package/dist/contract.d.ts +10 -0
- package/dist/contract.js +8 -0
- package/dist/contract.js.map +1 -0
- package/dist/index.cjs +22 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -46
- package/dist/index.d.ts +4 -46
- package/dist/index.js +12 -13
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +4 -2
- package/dist/internal.d.cts +2 -1
- package/dist/internal.d.ts +2 -1
- package/dist/internal.js +3 -1
- package/dist/seam-6pJeKOOJ.cjs +296 -0
- package/dist/seam-6pJeKOOJ.cjs.map +1 -0
- package/dist/seam-C4L_7rDt.js +225 -0
- package/dist/seam-C4L_7rDt.js.map +1 -0
- package/dist/types-CwytT-TI.js +13 -0
- package/dist/types-CwytT-TI.js.map +1 -0
- package/dist/types-DimcLIic.cjs +17 -0
- package/dist/types-DimcLIic.cjs.map +1 -0
- package/dist/{types-Due7UgzE.d.cts → types-eLTpocXz.d.cts} +37 -9
- package/dist/{types-DITX_3CG.d.ts → types-otwv-Cdl.d.ts} +36 -8
- package/package.json +21 -7
- package/dist/capability-BRf0HrOi.js.map +0 -1
- package/dist/capability-Cl9x8oLS.cjs.map +0 -1
|
@@ -1,238 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { a as contentToPdfRect$1, c as insetPdfRectByRD, d as refKey, f as rotFromDTO, g as writableTarget, i as contentToPdfPoint, l as pdfToContentPoint$1, m as toPdfRotation, n as boxGeomFromDTO, o as cssToColor, p as styleFromDTO, r as colorToCss, s as fromPdfRotation, t as boxGeomFields, u as pdfToContentRect$1 } from "./seam-C4L_7rDt.js";
|
|
2
|
+
import { CONTINUOUS_RENDER_POLICY, snapAppearanceScale } from "@embedpdf/core";
|
|
3
|
+
import { ActionsToken, createHoverPump } from "@embedpdf/plugin-actions/contract";
|
|
4
|
+
import { InteractionToken } from "@embedpdf/plugin-interaction/contract";
|
|
3
5
|
import { buildCommentThreads, encodeStableIdKey, resolveBinarySource, sniffBinaryMetadata } from "@embedpdf/engine-core/runtime";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
+
import { scriptColorToRgb } from "@embedpdf/core-acrojs";
|
|
7
|
+
import { SelectionToken } from "@embedpdf/plugin-selection/contract";
|
|
8
|
+
import { FLAG_KEYS, annotContentsEditable, annotDeletable, annotTransformable, calloutLinePoints, canMove, chrome, clickCreateGeom, cloudyBorderExtent, contentToPdfRect, creationDraftAnchor, cursorAt, defaultsFor, expandGroups, fitStampBox, geomPdfBounds, geomRotation, geomVisualBounds, groupKeyOf, hitTest, initialTextStyle, isSubstrateOnly, linkChildrenOf, linkOf, pageItems, pdfToContentPoint, pdfToContentRect, propsFor, readProp, resolveClickPlacement, rotatedAabb, selectionAnchor, selectionQuad, sharedProps, styleFromProps, textBoxes, unionRect, update, uprightRotation, viewable } from "@embedpdf/core-annotation";
|
|
6
9
|
import { normalizeQuad, textQuadBounds } from "@embedpdf/core-geometry";
|
|
7
|
-
//#region src/types.ts
|
|
8
|
-
/**
|
|
9
|
-
* The annotation capability token. Typed to the full {@link AnnotationHostCapability}
|
|
10
|
-
* here (the package internals + the `/internal` entry use this view). The package
|
|
11
|
-
* root re-exports the SAME token narrowed to {@link AnnotationCapability}.
|
|
12
|
-
*/
|
|
13
|
-
const AnnotationToken = createCapabilityToken("annotation", { hint: `add annotationPlugin() from '@embedpdf/plugin-annotation' to your plugins list` });
|
|
14
|
-
//#endregion
|
|
15
|
-
//#region src/repository/seam.ts
|
|
16
|
-
function refKey(ref) {
|
|
17
|
-
return ref.kind === "objectNumber" ? `obj:${ref.annotObjectNumber}` : ref.kind === "nm" ? `nm:${ref.nm}` : `idx:${ref.pageObjectNumber}:${ref.index}`;
|
|
18
|
-
}
|
|
19
|
-
const h2 = (n) => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, "0");
|
|
20
|
-
const colorToCss = (c) => `#${h2(c.r)}${h2(c.g)}${h2(c.b)}`;
|
|
21
|
-
function cssToColor(css) {
|
|
22
|
-
const s = css.trim();
|
|
23
|
-
const m6 = /^#?([0-9a-f]{6})$/i.exec(s);
|
|
24
|
-
if (m6) {
|
|
25
|
-
const n = parseInt(m6[1], 16);
|
|
26
|
-
return {
|
|
27
|
-
r: n >> 16 & 255,
|
|
28
|
-
g: n >> 8 & 255,
|
|
29
|
-
b: n & 255
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
const m3 = /^#?([0-9a-f]{3})$/i.exec(s);
|
|
33
|
-
if (m3) {
|
|
34
|
-
const [a, b, c] = m3[1];
|
|
35
|
-
return {
|
|
36
|
-
r: parseInt(a + a, 16),
|
|
37
|
-
g: parseInt(b + b, 16),
|
|
38
|
-
b: parseInt(c + c, 16)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
r: 0,
|
|
43
|
-
g: 0,
|
|
44
|
-
b: 0
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
const toPdfRotation = (rotCW) => normalizeDeg(-rotCW);
|
|
48
|
-
const fromPdfRotation = (rotPdf) => normalizeDeg(-rotPdf);
|
|
49
|
-
/** Advisory `rot` for a vertex geom, from a DTO's (PDF-convention) `rotation`.
|
|
50
|
-
* Absent → no `rot` key (kept off the geom so unrotated shapes stay clean). */
|
|
51
|
-
const rotFromDTO = (rotation) => rotation ? { rot: fromPdfRotation(rotation) } : {};
|
|
52
|
-
/**
|
|
53
|
-
* Geometry/rotation fields for a BOX kind (square/circle/plain free-text). The
|
|
54
|
-
* model's `rect` is the UNROTATED logical box and `rot` the applied tilt, so:
|
|
55
|
-
* - rot == 0 → `/Rect` IS the box; the transform pair is stated as `null`
|
|
56
|
-
* (TOTAL projection — the engine's tri-state writes preserve omissions, so
|
|
57
|
-
* an omitted field would keep a stale rotation instead of flattening it).
|
|
58
|
-
* - rot != 0 → `/Rect` is the rotated visual AABB (PDFium clips the baked /AP
|
|
59
|
-
* to it), `unrotatedRect` the logical box, `rotation` the PDF angle.
|
|
60
|
-
*/
|
|
61
|
-
function boxGeomFields(rect, rot, crop) {
|
|
62
|
-
if (!rot) return {
|
|
63
|
-
rect: contentToPdfRect(rect, crop),
|
|
64
|
-
rotation: null,
|
|
65
|
-
unrotatedRect: null
|
|
66
|
-
};
|
|
67
|
-
return {
|
|
68
|
-
rect: contentToPdfRect(rotatedAabb(rect, rot), crop),
|
|
69
|
-
unrotatedRect: contentToPdfRect(rect, crop),
|
|
70
|
-
rotation: toPdfRotation(rot)
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/** A box geom (square/circle/stamp) from its DTO: when rotated, the LOCAL box
|
|
74
|
-
* is the stored `unrotatedRect` (the AABB `/Rect` is the rendered envelope)
|
|
75
|
-
* and `rot` the converted tilt; unrotated, `/Rect` IS the box. */
|
|
76
|
-
function boxGeomFromDTO(dto, rotation, unrotatedRect, crop, ellipse) {
|
|
77
|
-
const rot = rotation ? fromPdfRotation(rotation) : 0;
|
|
78
|
-
return {
|
|
79
|
-
t: "rect",
|
|
80
|
-
rect: pdfToContentRect(rot && unrotatedRect ? unrotatedRect : dto.rect, crop),
|
|
81
|
-
ellipse,
|
|
82
|
-
...rot ? { rot } : {}
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
/** Inset a PdfRect by a `/RD` (PDF user space, y-up: all four are non-negative
|
|
86
|
-
* insets from the matching `/Rect` edge). Used to recover the callout text box. */
|
|
87
|
-
const insetPdfRectByRD = (r, rd) => rd ? {
|
|
88
|
-
left: r.left + rd.left,
|
|
89
|
-
bottom: r.bottom + rd.bottom,
|
|
90
|
-
right: r.right - rd.right,
|
|
91
|
-
top: r.top - rd.top
|
|
92
|
-
} : r;
|
|
93
|
-
/** Engine border fields (`/BS /S`, `/BS /D`, `/BE /I`) → the `Border` union. A
|
|
94
|
-
* cloudy effect wins over the underlying border style (which stays solid). */
|
|
95
|
-
function borderFromDTO(d) {
|
|
96
|
-
if ((d.cloudyIntensity ?? 0) > 0) return {
|
|
97
|
-
kind: "cloudy",
|
|
98
|
-
intensity: d.cloudyIntensity
|
|
99
|
-
};
|
|
100
|
-
if (d.borderStyle === "dashed") return {
|
|
101
|
-
kind: "dashed",
|
|
102
|
-
dash: d.dashArray?.length ? d.dashArray : [3, 3]
|
|
103
|
-
};
|
|
104
|
-
return { kind: "solid" };
|
|
105
|
-
}
|
|
106
|
-
/** The writable projection of a `link` value: `goto`/`uri` pass through,
|
|
107
|
-
* read-only arms (`javascript`, `named`, `goto-remote`, `launch`,
|
|
108
|
-
* `unsupported`) yield `null` — they can be carried, never (re)written. */
|
|
109
|
-
function writableTarget(t) {
|
|
110
|
-
return t && (t.kind === "goto" || t.kind === "uri") ? t : null;
|
|
111
|
-
}
|
|
112
|
-
const TEXT_MARKUP = /* @__PURE__ */ new Set([
|
|
113
|
-
"highlight",
|
|
114
|
-
"underline",
|
|
115
|
-
"squiggly",
|
|
116
|
-
"strikeout"
|
|
117
|
-
]);
|
|
118
|
-
const STROKE_KINDS = /* @__PURE__ */ new Set([
|
|
119
|
-
"square",
|
|
120
|
-
"circle",
|
|
121
|
-
"line",
|
|
122
|
-
"polygon",
|
|
123
|
-
"polyline",
|
|
124
|
-
"ink"
|
|
125
|
-
]);
|
|
126
|
-
/** Engine DTO → content-space `Style` (CSS colours, `Border` union). Exported so
|
|
127
|
-
* selection-aware UIs can read display values straight off a {@link AnnotationDTO}
|
|
128
|
-
* without re-deriving the colour/border mapping. */
|
|
129
|
-
function styleFromDTO(dto) {
|
|
130
|
-
if (dto.subtype === "widget") return {
|
|
131
|
-
color: dto.color ? colorToCss(dto.color) : "#1a1a1a",
|
|
132
|
-
interiorColor: dto.interiorColor ? colorToCss(dto.interiorColor) : null,
|
|
133
|
-
strokeWidth: dto.strokeWidth,
|
|
134
|
-
opacity: 1,
|
|
135
|
-
blendMode: dto.blendMode,
|
|
136
|
-
border: dto.borderStyle === "dashed" ? {
|
|
137
|
-
kind: "dashed",
|
|
138
|
-
dash: [3, 3]
|
|
139
|
-
} : { kind: "solid" }
|
|
140
|
-
};
|
|
141
|
-
if (STROKE_KINDS.has(dto.subtype)) {
|
|
142
|
-
const d = dto;
|
|
143
|
-
return {
|
|
144
|
-
color: colorToCss(d.color),
|
|
145
|
-
interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,
|
|
146
|
-
strokeWidth: d.strokeWidth,
|
|
147
|
-
opacity: d.opacity,
|
|
148
|
-
blendMode: dto.blendMode,
|
|
149
|
-
border: borderFromDTO(d)
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
if (TEXT_MARKUP.has(dto.subtype)) {
|
|
153
|
-
const d = dto;
|
|
154
|
-
return {
|
|
155
|
-
color: colorToCss(d.color),
|
|
156
|
-
interiorColor: null,
|
|
157
|
-
strokeWidth: 0,
|
|
158
|
-
opacity: d.opacity,
|
|
159
|
-
blendMode: dto.blendMode,
|
|
160
|
-
border: { kind: "solid" }
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
if (dto.subtype === "caret") {
|
|
164
|
-
const d = dto;
|
|
165
|
-
return {
|
|
166
|
-
color: colorToCss(d.color),
|
|
167
|
-
interiorColor: null,
|
|
168
|
-
strokeWidth: 1,
|
|
169
|
-
opacity: d.opacity,
|
|
170
|
-
blendMode: dto.blendMode,
|
|
171
|
-
border: { kind: "solid" }
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
if (dto.subtype === "free-text") {
|
|
175
|
-
const d = dto;
|
|
176
|
-
return {
|
|
177
|
-
color: colorToCss(d.color),
|
|
178
|
-
interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,
|
|
179
|
-
strokeWidth: d.strokeWidth,
|
|
180
|
-
opacity: d.opacity,
|
|
181
|
-
blendMode: dto.blendMode,
|
|
182
|
-
border: borderFromDTO(d)
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
if (dto.subtype === "redact") {
|
|
186
|
-
const d = dto;
|
|
187
|
-
return {
|
|
188
|
-
color: colorToCss(d.color),
|
|
189
|
-
interiorColor: d.interiorColor ? colorToCss(d.interiorColor) : null,
|
|
190
|
-
strokeWidth: 1.5,
|
|
191
|
-
opacity: d.opacity,
|
|
192
|
-
blendMode: dto.blendMode,
|
|
193
|
-
border: { kind: "solid" }
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
if (dto.subtype === "text" || dto.subtype === "file-attachment") {
|
|
197
|
-
const d = dto;
|
|
198
|
-
return {
|
|
199
|
-
color: colorToCss(d.color),
|
|
200
|
-
interiorColor: null,
|
|
201
|
-
strokeWidth: 1,
|
|
202
|
-
opacity: d.opacity,
|
|
203
|
-
blendMode: dto.blendMode,
|
|
204
|
-
border: { kind: "solid" }
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
return {
|
|
208
|
-
color: "#444444",
|
|
209
|
-
interiorColor: null,
|
|
210
|
-
strokeWidth: 1,
|
|
211
|
-
opacity: 1,
|
|
212
|
-
blendMode: dto.blendMode,
|
|
213
|
-
border: { kind: "solid" }
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* The flat props vocabulary (CSS colours, house keys) → the engine's widget
|
|
218
|
-
* appearance for `doc.forms` authoring — the SAME mapping the widget patch
|
|
219
|
-
* lowering uses, exported as a boundary utility so the form plugin can style
|
|
220
|
-
* `placeField` from a tool's `currentDefaults` without growing a second CSS
|
|
221
|
-
* parser. Absent keys stay absent (the engine writes nothing for them).
|
|
222
|
-
*/
|
|
223
|
-
function widgetAppearanceFromProps(props) {
|
|
224
|
-
return {
|
|
225
|
-
...props.color !== void 0 ? { color: cssToColor(props.color) } : {},
|
|
226
|
-
...props.interiorColor !== void 0 ? { interiorColor: props.interiorColor ? cssToColor(props.interiorColor) : null } : {},
|
|
227
|
-
...props.strokeWidth !== void 0 ? { strokeWidth: props.strokeWidth } : {},
|
|
228
|
-
...props.border !== void 0 ? { borderStyle: props.border.kind === "dashed" ? "dashed" : "solid" } : {},
|
|
229
|
-
...props.fontFamily !== void 0 ? { fontFamily: props.fontFamily } : {},
|
|
230
|
-
...props.fontSize !== void 0 ? { fontSize: props.fontSize } : {},
|
|
231
|
-
...props.fontColor !== void 0 ? { fontColor: cssToColor(props.fontColor) } : {},
|
|
232
|
-
...props.textAlign !== void 0 ? { textAlign: props.textAlign } : {}
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
//#endregion
|
|
236
10
|
//#region src/repository/props.ts
|
|
237
11
|
/**
|
|
238
12
|
* GENERIC per-key prop lowerings — the 1:1 mappings from the flat props
|
|
@@ -909,6 +683,46 @@ function toCreateDraft(a, crop) {
|
|
|
909
683
|
};
|
|
910
684
|
}
|
|
911
685
|
//#endregion
|
|
686
|
+
//#region src/hover-feed.ts
|
|
687
|
+
/**
|
|
688
|
+
* The annotation plane's E/X trigger feed — a thin adapter from the ONE
|
|
689
|
+
* pointer-driven hover seam (the `hoverAt` diff) onto the shared hover pump.
|
|
690
|
+
*
|
|
691
|
+
* Anti-cascade is structural and lives in the CALLER's seam placement:
|
|
692
|
+
* reducer-side hover clears (session-hide, remove, reload) never pass
|
|
693
|
+
* through `hoverAt`, so an effect-induced hover loss can never masquerade as
|
|
694
|
+
* a cursor exit. This module only decides WHO is hoverable here:
|
|
695
|
+
*
|
|
696
|
+
* - Drafts (no engine ref) can't carry /AA — skipped.
|
|
697
|
+
* - Widgets and links belong to their own event planes (fill controls /
|
|
698
|
+
* LinkLayer anchors own their pixels). When they ARE hit-testable on this
|
|
699
|
+
* plane, an authoring tool owns them — firing hover actions while editing
|
|
700
|
+
* would be wrong — so they are skipped unconditionally.
|
|
701
|
+
* - Tree-less annotations are FREE: no target, no dispatch, and per-event
|
|
702
|
+
* flags keep a lone /E or /X from dispatching its inert twin.
|
|
703
|
+
*/
|
|
704
|
+
function createAnnotationHoverFeed(actions, annotOf) {
|
|
705
|
+
const pump = createHoverPump(actions.dispatch);
|
|
706
|
+
const targetOf = (id) => {
|
|
707
|
+
if (!id) return null;
|
|
708
|
+
const annot = annotOf(id);
|
|
709
|
+
if (!annot?.ref) return null;
|
|
710
|
+
if (annot.subtype.startsWith("widget") || annot.subtype === "link") return null;
|
|
711
|
+
const enter = Boolean(annot.data?.actions?.cursorEnter?.root);
|
|
712
|
+
const exit = Boolean(annot.data?.actions?.cursorExit?.root);
|
|
713
|
+
if (!enter && !exit) return null;
|
|
714
|
+
return {
|
|
715
|
+
ref: annot.ref,
|
|
716
|
+
pon: annot.pon,
|
|
717
|
+
events: {
|
|
718
|
+
enter,
|
|
719
|
+
exit
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
};
|
|
723
|
+
return { hover: (id) => pump.hover(targetOf(id)) };
|
|
724
|
+
}
|
|
725
|
+
//#endregion
|
|
912
726
|
//#region src/text-item.ts
|
|
913
727
|
/**
|
|
914
728
|
* The free-text presentation projection: the core's geometry-only `textBoxes`
|
|
@@ -1522,6 +1336,8 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
1522
1336
|
* slot. See {@link FilePickerProvider}. */
|
|
1523
1337
|
let filePickerProvider = null;
|
|
1524
1338
|
const model = () => ctx.getState().model;
|
|
1339
|
+
const actionsForHover = ctx.tryGet(ActionsToken);
|
|
1340
|
+
const hoverFeed = actionsForHover ? createAnnotationHoverFeed(actionsForHover, (id) => model().byId[id] ?? null) : null;
|
|
1525
1341
|
const chromeSettings = () => ctx.getState().chrome;
|
|
1526
1342
|
/**
|
|
1527
1343
|
* Ids on a page whose Behavior is currently ENGAGED (form widgets under a
|
|
@@ -1674,11 +1490,21 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
1674
1490
|
if (!viewable(a.flags, false)) continue;
|
|
1675
1491
|
const target = a.link ?? (a.data?.subtype === "link" ? a.data.target ?? null : null);
|
|
1676
1492
|
if (target == null || a.geom.t !== "rect") continue;
|
|
1493
|
+
const activate = a.data?.actions?.activate;
|
|
1494
|
+
const ref = a.ref ?? a.data?.ref ?? void 0;
|
|
1495
|
+
const hoverEnter = Boolean(a.data?.actions?.cursorEnter?.root);
|
|
1496
|
+
const hoverExit = Boolean(a.data?.actions?.cursorExit?.root);
|
|
1677
1497
|
v.push({
|
|
1678
1498
|
id,
|
|
1679
1499
|
rect: a.geom.rect,
|
|
1680
1500
|
target,
|
|
1681
|
-
attached: a.group !== void 0
|
|
1501
|
+
attached: a.group !== void 0,
|
|
1502
|
+
...activate ? { activate } : {},
|
|
1503
|
+
...ref ? { ref } : {},
|
|
1504
|
+
...hoverEnter || hoverExit ? { hoverEvents: {
|
|
1505
|
+
enter: hoverEnter,
|
|
1506
|
+
exit: hoverExit
|
|
1507
|
+
} } : {}
|
|
1682
1508
|
});
|
|
1683
1509
|
}
|
|
1684
1510
|
linkItemsCache.set(pon, {
|
|
@@ -2637,8 +2463,62 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
2637
2463
|
});
|
|
2638
2464
|
});
|
|
2639
2465
|
} else if (fx.fx === "syncLink") scheduleLinkSync(fx.id, { target: fx.target });
|
|
2640
|
-
else
|
|
2466
|
+
else {
|
|
2467
|
+
refKey(fx.ref);
|
|
2468
|
+
doc.page(fx.ref.pageObjectNumber).annotations.delete(fx.ref).then(() => {}, () => {});
|
|
2469
|
+
}
|
|
2641
2470
|
}
|
|
2471
|
+
const reloadPageNow = async (pon) => {
|
|
2472
|
+
const doc = ctx.doc;
|
|
2473
|
+
const crop = cropOf(pon);
|
|
2474
|
+
if (!doc || !crop) return;
|
|
2475
|
+
try {
|
|
2476
|
+
const snap = await doc.page(pon).annotations.list();
|
|
2477
|
+
const m = model();
|
|
2478
|
+
const stale = m.order.filter((id) => m.byId[id]?.pon === pon);
|
|
2479
|
+
if (stale.length) apply({
|
|
2480
|
+
t: "remove",
|
|
2481
|
+
ids: stale
|
|
2482
|
+
});
|
|
2483
|
+
apply({
|
|
2484
|
+
t: "loaded",
|
|
2485
|
+
annots: snap.annotations.map((d) => ingestDTO(d, crop))
|
|
2486
|
+
});
|
|
2487
|
+
} catch {}
|
|
2488
|
+
};
|
|
2489
|
+
/** Script patch → the engine's per-kind patch vocabulary. Colors cross the
|
|
2490
|
+
* Acrobat-array → engine {r,g,b}/255 boundary here; everything else maps
|
|
2491
|
+
* one-to-one (the VM's validity matrix already scoped keys per kind). */
|
|
2492
|
+
const engineScriptPatch = (subtype, patch) => {
|
|
2493
|
+
const out = { subtype };
|
|
2494
|
+
const toEngineColor = (color) => {
|
|
2495
|
+
const rgb = scriptColorToRgb(color);
|
|
2496
|
+
return rgb ? {
|
|
2497
|
+
r: Math.round(rgb.r * 255),
|
|
2498
|
+
g: Math.round(rgb.g * 255),
|
|
2499
|
+
b: Math.round(rgb.b * 255)
|
|
2500
|
+
} : null;
|
|
2501
|
+
};
|
|
2502
|
+
if (patch.strokeColor) {
|
|
2503
|
+
const color = toEngineColor(patch.strokeColor);
|
|
2504
|
+
if (!color) return /* @__PURE__ */ new Error("transparent stroke colours are not supported");
|
|
2505
|
+
out.color = color;
|
|
2506
|
+
}
|
|
2507
|
+
if (patch.fillColor) out.interiorColor = toEngineColor(patch.fillColor);
|
|
2508
|
+
if (patch.opacity !== void 0) out.opacity = patch.opacity;
|
|
2509
|
+
if (patch.width !== void 0) out.strokeWidth = patch.width;
|
|
2510
|
+
if (patch.borderStyle) out.borderStyle = patch.borderStyle === "D" ? "dashed" : "solid";
|
|
2511
|
+
if (patch.dash) out.dashArray = patch.dash;
|
|
2512
|
+
if (patch.rect) out.rect = {
|
|
2513
|
+
left: patch.rect[0],
|
|
2514
|
+
bottom: patch.rect[1],
|
|
2515
|
+
right: patch.rect[2],
|
|
2516
|
+
top: patch.rect[3]
|
|
2517
|
+
};
|
|
2518
|
+
if (patch.contents !== void 0) out.contents = patch.contents;
|
|
2519
|
+
if (patch.flags) out.flags = patch.flags;
|
|
2520
|
+
return out;
|
|
2521
|
+
};
|
|
2642
2522
|
return {
|
|
2643
2523
|
create: async (pon, draft) => {
|
|
2644
2524
|
const doc = ctx.doc;
|
|
@@ -2779,10 +2659,13 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
2779
2659
|
const h = hitTest(m, at.pon, at.point, chromeGeomAt(at.scale), m.hitMargin, pageBoxOf(at.pon), inertIdsAt(at.pon), viewEnv(at.zoom, at.rotation));
|
|
2780
2660
|
if (h.t === "annot") id = h.id;
|
|
2781
2661
|
}
|
|
2782
|
-
if (m.hovered !== id)
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2662
|
+
if (m.hovered !== id) {
|
|
2663
|
+
hoverFeed?.hover(id);
|
|
2664
|
+
apply({
|
|
2665
|
+
t: "hover",
|
|
2666
|
+
id
|
|
2667
|
+
});
|
|
2668
|
+
}
|
|
2786
2669
|
},
|
|
2787
2670
|
behaviorFor: (a) => behaviors.find((b) => b.matches(a) && b.engaged()) ?? null,
|
|
2788
2671
|
linkItemsOn: (pon) => memoLinkItems(pon),
|
|
@@ -3002,24 +2885,7 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
3002
2885
|
return subs.length > 0 && subs.every((a) => a.ref != null && allowsMutation("update", a.ref));
|
|
3003
2886
|
},
|
|
3004
2887
|
ensurePage: () => {},
|
|
3005
|
-
reloadPage:
|
|
3006
|
-
const doc = ctx.doc;
|
|
3007
|
-
const crop = cropOf(pon);
|
|
3008
|
-
if (!doc || !crop) return;
|
|
3009
|
-
try {
|
|
3010
|
-
const snap = await doc.page(pon).annotations.list();
|
|
3011
|
-
const m = model();
|
|
3012
|
-
const stale = m.order.filter((id) => m.byId[id]?.pon === pon);
|
|
3013
|
-
if (stale.length) apply({
|
|
3014
|
-
t: "remove",
|
|
3015
|
-
ids: stale
|
|
3016
|
-
});
|
|
3017
|
-
apply({
|
|
3018
|
-
t: "loaded",
|
|
3019
|
-
annots: snap.annotations.map((d) => ingestDTO(d, crop))
|
|
3020
|
-
});
|
|
3021
|
-
} catch {}
|
|
3022
|
-
},
|
|
2888
|
+
reloadPage: (pon) => reloadPageNow(pon),
|
|
3023
2889
|
hydration: () => ctx.getState().hydration,
|
|
3024
2890
|
ensureHydrated: () => {
|
|
3025
2891
|
if (hydrationStarted) return;
|
|
@@ -3085,6 +2951,72 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
3085
2951
|
textTimers.clear();
|
|
3086
2952
|
apply({ t: "endTextEdit" });
|
|
3087
2953
|
},
|
|
2954
|
+
commitScriptEffects: async (entries) => {
|
|
2955
|
+
const doc = ctx.doc;
|
|
2956
|
+
if (!doc) return { results: entries.map((entry) => ({
|
|
2957
|
+
annotObjectNumber: entry.annotObjectNumber,
|
|
2958
|
+
status: "failed",
|
|
2959
|
+
error: "no document"
|
|
2960
|
+
})) };
|
|
2961
|
+
const results = [];
|
|
2962
|
+
const touchedPons = /* @__PURE__ */ new Set();
|
|
2963
|
+
let failed = false;
|
|
2964
|
+
for (const entry of entries) {
|
|
2965
|
+
if (failed) {
|
|
2966
|
+
results.push({
|
|
2967
|
+
annotObjectNumber: entry.annotObjectNumber,
|
|
2968
|
+
status: "skipped"
|
|
2969
|
+
});
|
|
2970
|
+
continue;
|
|
2971
|
+
}
|
|
2972
|
+
const loaded = model().byId[`obj:${entry.annotObjectNumber}`];
|
|
2973
|
+
const pon = loaded?.pon ?? entry.pageObjectNumber;
|
|
2974
|
+
let ref = loaded?.ref ?? null;
|
|
2975
|
+
let subtype = loaded?.subtype;
|
|
2976
|
+
if ((!ref || !subtype) && pon !== void 0) try {
|
|
2977
|
+
const { annotations } = await doc.page(pon).annotations.list();
|
|
2978
|
+
const dto = annotations.find((candidate) => candidate.ref.kind === "objectNumber" && candidate.ref.annotObjectNumber === entry.annotObjectNumber);
|
|
2979
|
+
if (dto) {
|
|
2980
|
+
ref = dto.ref;
|
|
2981
|
+
subtype = dto.subtype;
|
|
2982
|
+
}
|
|
2983
|
+
} catch {}
|
|
2984
|
+
if (pon === void 0 || !ref || !subtype) {
|
|
2985
|
+
results.push({
|
|
2986
|
+
annotObjectNumber: entry.annotObjectNumber,
|
|
2987
|
+
status: "failed",
|
|
2988
|
+
error: "annotation not resolved (page not loaded)"
|
|
2989
|
+
});
|
|
2990
|
+
continue;
|
|
2991
|
+
}
|
|
2992
|
+
const patch = engineScriptPatch(subtype, entry.patch);
|
|
2993
|
+
if (patch instanceof Error) {
|
|
2994
|
+
results.push({
|
|
2995
|
+
annotObjectNumber: entry.annotObjectNumber,
|
|
2996
|
+
status: "failed",
|
|
2997
|
+
error: patch.message
|
|
2998
|
+
});
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
try {
|
|
3002
|
+
await doc.page(pon).annotations.update(ref, patch);
|
|
3003
|
+
touchedPons.add(pon);
|
|
3004
|
+
results.push({
|
|
3005
|
+
annotObjectNumber: entry.annotObjectNumber,
|
|
3006
|
+
status: "applied"
|
|
3007
|
+
});
|
|
3008
|
+
} catch (error) {
|
|
3009
|
+
failed = true;
|
|
3010
|
+
results.push({
|
|
3011
|
+
annotObjectNumber: entry.annotObjectNumber,
|
|
3012
|
+
status: "failed",
|
|
3013
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3014
|
+
});
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
for (const touched of touchedPons) await reloadPageNow(touched);
|
|
3018
|
+
return { results };
|
|
3019
|
+
},
|
|
3088
3020
|
registerBehavior: (b) => {
|
|
3089
3021
|
behaviors.push(b);
|
|
3090
3022
|
return () => {
|
|
@@ -3095,6 +3027,6 @@ function createAnnotationCapability(ctx, config = {}) {
|
|
|
3095
3027
|
};
|
|
3096
3028
|
}
|
|
3097
3029
|
//#endregion
|
|
3098
|
-
export { fromDTO as a,
|
|
3030
|
+
export { fromDTO as a, isTouchDirect as i, DEFAULT_TOOLS as n, toCreateDraft as o, buildToolRegistry as r, toPatch as s, createAnnotationCapability as t };
|
|
3099
3031
|
|
|
3100
|
-
//# sourceMappingURL=capability-
|
|
3032
|
+
//# sourceMappingURL=capability-DBsr2D-L.js.map
|