@embedpdf/plugin-annotation 3.0.0-next.13 → 3.0.0-next.14

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 (35) hide show
  1. package/dist/{capability-DVx1NmTe.cjs → capability-Bt320iJP.cjs} +211 -26
  2. package/dist/capability-Bt320iJP.cjs.map +1 -0
  3. package/dist/{capability-B_dkoB1K.js → capability-CoL4na7g.js} +213 -28
  4. package/dist/capability-CoL4na7g.js.map +1 -0
  5. package/dist/contract/host.d.cts +2 -2
  6. package/dist/contract/host.d.ts +2 -2
  7. package/dist/{contract-CgAcfAE7.d.cts → contract-C7rcuNp_.d.cts} +2 -2
  8. package/dist/{contract-CiG2_HBq.d.ts → contract-CM2Ovdq_.d.ts} +2 -2
  9. package/dist/contract.cjs +1 -1
  10. package/dist/contract.d.cts +2 -2
  11. package/dist/contract.d.ts +2 -2
  12. package/dist/contract.js +1 -1
  13. package/dist/index.cjs +17 -3
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +2 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +17 -3
  18. package/dist/index.js.map +1 -1
  19. package/dist/internal.cjs +2 -2
  20. package/dist/internal.d.cts +2 -2
  21. package/dist/internal.d.ts +2 -2
  22. package/dist/internal.js +2 -2
  23. package/dist/{tools-0NI3b9z8.cjs → tools-B3i1gjRs.cjs} +54 -1
  24. package/dist/tools-B3i1gjRs.cjs.map +1 -0
  25. package/dist/{tools-DBEYx3-c.js → tools-DsfqBn_a.js} +54 -1
  26. package/dist/tools-DsfqBn_a.js.map +1 -0
  27. package/dist/types-BvB1vUKb.js.map +1 -1
  28. package/dist/{types-ObcPYc3-.d.cts → types-ChRnKozg.d.cts} +52 -6
  29. package/dist/types-Dlhdw2k_.cjs.map +1 -1
  30. package/dist/{types-D5V0TIwk.d.ts → types-Dmz3eRSG.d.ts} +52 -6
  31. package/package.json +9 -9
  32. package/dist/capability-B_dkoB1K.js.map +0 -1
  33. package/dist/capability-DVx1NmTe.cjs.map +0 -1
  34. package/dist/tools-0NI3b9z8.cjs.map +0 -1
  35. package/dist/tools-DBEYx3-c.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  const require_seam = require("./seam-6pJeKOOJ.cjs");
2
- const require_tools = require("./tools-0NI3b9z8.cjs");
2
+ const require_tools = require("./tools-B3i1gjRs.cjs");
3
3
  const require_types = require("./types-Dlhdw2k_.cjs");
4
4
  let _embedpdf_core = require("@embedpdf/core");
5
5
  let _embedpdf_plugin_actions_contract = require("@embedpdf/plugin-actions/contract");
@@ -107,6 +107,15 @@ const polyCloudy = (a) => a.geom.t === "poly" && a.geom.closed ? { cloudyIntensi
107
107
  /** The visual-bounds `/Rect` (stroke + border included) of a stroke geom. */
108
108
  const visualRect = (a, crop) => {
109
109
  const g = a.geom;
110
+ if (a.measure) {
111
+ const bounds = (0, _embedpdf_core_annotation.measurementLayout)(g, a.measure, a.style)?.visualBounds;
112
+ if (bounds) return { rect: {
113
+ left: crop.left + bounds.x,
114
+ right: crop.left + bounds.x + bounds.width,
115
+ top: crop.top - bounds.y,
116
+ bottom: crop.top - bounds.y - bounds.height
117
+ } };
118
+ }
110
119
  if (g.t === "line" || g.t === "ink") return { rect: (0, _embedpdf_core_annotation.geomPdfBounds)(g, a.style.strokeWidth, crop) };
111
120
  if (g.t === "poly") return { rect: (0, _embedpdf_core_annotation.geomPdfBounds)(g, a.style.strokeWidth, crop, a.style.border) };
112
121
  return {};
@@ -138,18 +147,29 @@ const strokeProps = {
138
147
  const line = {
139
148
  ingest: (dto, crop) => {
140
149
  const d = dto;
141
- return { geom: {
142
- t: "line",
143
- a: (0, _embedpdf_core_annotation.pdfToContentPoint)(d.linePoints.start, crop),
144
- b: (0, _embedpdf_core_annotation.pdfToContentPoint)(d.linePoints.end, crop),
145
- ends: d.lineEndings,
146
- ...require_seam.rotFromDTO(d.rotation)
147
- } };
150
+ return {
151
+ ...d.intent === "LineDimension" ? { measure: {
152
+ intent: d.intent,
153
+ measure: d.measure ?? null,
154
+ caption: d.caption ?? { enabled: false },
155
+ leader: d.leader ?? void 0,
156
+ crop,
157
+ text: d.contents ?? ""
158
+ } } : {},
159
+ geom: {
160
+ t: "line",
161
+ a: (0, _embedpdf_core_annotation.pdfToContentPoint)(d.linePoints.start, crop),
162
+ b: (0, _embedpdf_core_annotation.pdfToContentPoint)(d.linePoints.end, crop),
163
+ ends: d.lineEndings,
164
+ ...require_seam.rotFromDTO(d.rotation)
165
+ }
166
+ };
148
167
  },
149
168
  geometry: (a, crop) => {
150
169
  const g = a.geom;
151
170
  if (g.t !== "line") return null;
152
171
  return {
172
+ ...a.measure?.intent === "LineDimension" ? { contents: (0, _embedpdf_core_annotation.distanceLabel)(g, a.measure) } : {},
153
173
  linePoints: {
154
174
  start: (0, _embedpdf_core_annotation.contentToPdfPoint)(g.a, crop),
155
175
  end: (0, _embedpdf_core_annotation.contentToPdfPoint)(g.b, crop)
@@ -158,29 +178,55 @@ const line = {
158
178
  ...advisoryRotation(g)
159
179
  };
160
180
  },
161
- prop: strokeProps
181
+ prop: strokeProps,
182
+ draftExtras: (a) => a.measure?.intent === "LineDimension" ? {
183
+ intent: a.measure.intent,
184
+ measure: a.measure.measure?.subtype === "RL" ? a.measure.measure : null,
185
+ caption: a.measure.caption,
186
+ leader: a.measure.leader,
187
+ subject: "Distance"
188
+ } : {}
162
189
  };
163
190
  const polyProjection = (closed) => ({
164
191
  ingest: (dto, crop) => {
165
192
  const d = dto;
166
- return { geom: {
167
- t: "poly",
168
- points: d.vertices.map((p) => (0, _embedpdf_core_annotation.pdfToContentPoint)(p, crop)),
169
- closed,
170
- ..."lineEndings" in d ? { ends: d.lineEndings } : {},
171
- ...require_seam.rotFromDTO(d.rotation)
172
- } };
193
+ return {
194
+ ...d.intent === "PolygonDimension" || d.intent === "PolyLineDimension" ? { measure: {
195
+ intent: d.intent,
196
+ measure: d.measure ?? null,
197
+ caption: d.caption ?? { enabled: false },
198
+ crop,
199
+ text: d.contents ?? ""
200
+ } } : {},
201
+ geom: {
202
+ t: "poly",
203
+ points: d.vertices.map((p) => (0, _embedpdf_core_annotation.pdfToContentPoint)(p, crop)),
204
+ closed,
205
+ ..."lineEndings" in d ? { ends: d.lineEndings } : {},
206
+ ...require_seam.rotFromDTO(d.rotation)
207
+ }
208
+ };
173
209
  },
174
210
  geometry: (a, crop) => {
175
211
  const g = a.geom;
176
212
  if (g.t !== "poly") return null;
177
213
  return {
214
+ ...a.measure && a.measure.intent !== "LineDimension" ? {
215
+ contents: (0, _embedpdf_core_annotation.shapeMeasurementLabel)(g, a.measure),
216
+ caption: a.measure.caption
217
+ } : {},
178
218
  vertices: g.points.map((p) => (0, _embedpdf_core_annotation.contentToPdfPoint)(p, crop)),
179
219
  ...visualRect(a, crop),
180
220
  ...advisoryRotation(g)
181
221
  };
182
222
  },
183
- prop: strokeProps
223
+ prop: strokeProps,
224
+ draftExtras: (a) => a.measure && a.measure.intent !== "LineDimension" ? {
225
+ intent: a.measure.intent,
226
+ measure: a.measure.measure?.subtype === "RL" ? a.measure.measure : null,
227
+ caption: a.measure.caption,
228
+ subject: closed ? "Area" : "Perimeter"
229
+ } : {}
184
230
  });
185
231
  const polygon = polyProjection(true);
186
232
  const polyline = polyProjection(false);
@@ -1025,6 +1071,14 @@ function toPatch(a, crop) {
1025
1071
  */
1026
1072
  function toScopedPatch(a, scope, crop) {
1027
1073
  const kind = projectionOf(a.subtype);
1074
+ if (scope.kind === "caption") return a.measure ? {
1075
+ subtype: wireSubtypeOf(a),
1076
+ caption: a.measure.caption
1077
+ } : null;
1078
+ if (scope.kind === "leader") return a.measure?.intent === "LineDimension" ? {
1079
+ subtype: "line",
1080
+ leader: a.measure.leader
1081
+ } : null;
1028
1082
  if (scope.kind === "geometry") {
1029
1083
  const geo = kind.geometry(a, crop);
1030
1084
  return geo ? {
@@ -1215,6 +1269,12 @@ function createAnnotationCapability(ctx, config = {}) {
1215
1269
  * adapter), or null — every click-then-pick tool resolves through this ONE
1216
1270
  * slot. See {@link FilePickerProvider}. */
1217
1271
  let filePickerProvider = null;
1272
+ const pageViewports = /* @__PURE__ */ new Map();
1273
+ const captured = /* @__PURE__ */ new Set();
1274
+ ctx.cleanup(() => {
1275
+ captured.clear();
1276
+ pageViewports.clear();
1277
+ });
1218
1278
  const model = () => ctx.getState().model;
1219
1279
  const actionsForHover = ctx.tryGet(_embedpdf_plugin_actions_contract.ActionsToken);
1220
1280
  const hoverFeed = actionsForHover ? createAnnotationHoverFeed(actionsForHover, (id) => model().byId[id] ?? null) : null;
@@ -1811,8 +1871,8 @@ function createAnnotationCapability(ctx, config = {}) {
1811
1871
  * changed the appearance (create / restyle / resize), `'baked'` when the AP is
1812
1872
  * still authoritative (a move, which preserves it, or a remote edit).
1813
1873
  * `bumpAp` marks the upsert as confirming an engine /AP re-bake with new
1814
- * content, so the annotation's `apVersion` — and with it the page's
1815
- * appearance epoch — advances and the shell fetches the fresh raster.
1874
+ * content, advancing the annotation's `apVersion`. Only baked annotations
1875
+ * contribute to the page's appearance epoch and trigger a raster fetch.
1816
1876
  */
1817
1877
  const syncDTO = (dto, source, bumpAp = false) => {
1818
1878
  const crop = cropOf(dto.pageObjectNumber);
@@ -1830,7 +1890,7 @@ function createAnnotationCapability(ctx, config = {}) {
1830
1890
  const pon = ponForRef(ref);
1831
1891
  if (pon == null) throw new Error("[annotation] cannot resolve page for ref");
1832
1892
  const res = await doc.page(pon).annotations.update(ref, patch);
1833
- syncDTO(res.updated, "vector");
1893
+ syncDTO(res.updated, "vector", res.appearance?.changed);
1834
1894
  };
1835
1895
  const commitText = (ref) => {
1836
1896
  const key = require_seam.refKey(ref);
@@ -2131,7 +2191,9 @@ function createAnnotationCapability(ctx, config = {}) {
2131
2191
  })).ref;
2132
2192
  },
2133
2193
  edit: async (ref, text) => {
2134
- const subtype = model().byId[require_seam.refKey(ref)]?.data?.subtype;
2194
+ const data = model().byId[require_seam.refKey(ref)]?.data;
2195
+ if (data && (0, _embedpdf_engine_core_runtime.isDimension)(data)) throw new Error("[annotation] measurement contents are derived");
2196
+ const subtype = data?.subtype;
2135
2197
  if (!subtype) throw new Error("[annotation] cannot edit an uncommitted annotation");
2136
2198
  await updateOne(ref, {
2137
2199
  subtype,
@@ -2201,7 +2263,7 @@ function createAnnotationCapability(ctx, config = {}) {
2201
2263
  canSetStatus: allowsCreate(),
2202
2264
  canEditText: (() => {
2203
2265
  const a = model().byId[require_seam.refKey(ref)];
2204
- return !!a && (0, _embedpdf_core_annotation.annotContentsEditable)(a);
2266
+ return !!a && !(a.data && (0, _embedpdf_engine_core_runtime.isDimension)(a.data)) && (0, _embedpdf_core_annotation.annotContentsEditable)(a);
2205
2267
  })(),
2206
2268
  canDelete: deletableOne(ref),
2207
2269
  canDeleteThread: t !== null && threadMemberRefs(t).every(deletableOne)
@@ -2312,7 +2374,21 @@ function createAnnotationCapability(ctx, config = {}) {
2312
2374
  function perform(fx, m) {
2313
2375
  const doc = ctx.doc;
2314
2376
  if (!doc) return;
2315
- if (fx.fx === "createGroup") {
2377
+ if (fx.fx === "captured") {
2378
+ const crop = cropOf(fx.pon);
2379
+ if (crop && fx.geom.t === "line") {
2380
+ const pdf = (p) => ({
2381
+ x: p.x + crop.left,
2382
+ y: crop.top - p.y
2383
+ });
2384
+ for (const cb of captured) cb({
2385
+ tool: fx.tool,
2386
+ pon: fx.pon,
2387
+ from: pdf(fx.geom.a),
2388
+ to: pdf(fx.geom.b)
2389
+ });
2390
+ }
2391
+ } else if (fx.fx === "createGroup") {
2316
2392
  const ids = [fx.primary, ...fx.members];
2317
2393
  const annots = ids.map((id) => m.byId[id]);
2318
2394
  const primary = annots[0];
@@ -2507,6 +2583,61 @@ function createAnnotationCapability(ctx, config = {}) {
2507
2583
  });
2508
2584
  };
2509
2585
  return {
2586
+ setPageViewports: (pon, viewports, fallback) => {
2587
+ pageViewports.set(pon, {
2588
+ viewports,
2589
+ fallback
2590
+ });
2591
+ },
2592
+ onDraftCaptured: (cb) => {
2593
+ captured.add(cb);
2594
+ return () => {
2595
+ captured.delete(cb);
2596
+ };
2597
+ },
2598
+ remeasurePage: async (pon, scale) => {
2599
+ await rehydrate();
2600
+ const report = {
2601
+ pon,
2602
+ scale,
2603
+ updated: [],
2604
+ skipped: [],
2605
+ failed: []
2606
+ };
2607
+ const hydration = ctx.getState().hydration;
2608
+ if (hydration.status !== "complete") {
2609
+ report.error = (0, _embedpdf_engine_core_runtime.serializeError)(hydration.status === "error" ? hydration.error : /* @__PURE__ */ new Error("Annotation hydration is incomplete"));
2610
+ return report;
2611
+ }
2612
+ const candidates = Object.values(model().byId).filter((a) => a.pon === pon && a.data && (0, _embedpdf_engine_core_runtime.isDimension)(a.data));
2613
+ for (const a of candidates) {
2614
+ const dto = a.data, ref = dto.ref;
2615
+ const reason = a.authority?.update === false ? "no-authority" : !(0, _embedpdf_core_annotation.annotTransformable)(a) || !(0, _embedpdf_core_annotation.annotContentsEditable)(a) ? "locked" : "measure" in dto && dto.measure && dto.measure.subtype !== "RL" ? "foreign-measure" : !(0, _embedpdf_engine_core_runtime.isReadout)((0, _embedpdf_engine_core_runtime.measurementReadout)({
2616
+ ...dto,
2617
+ measure: scale
2618
+ })) ? "unavailable" : null;
2619
+ if (reason) {
2620
+ report.skipped.push({
2621
+ ref,
2622
+ reason
2623
+ });
2624
+ continue;
2625
+ }
2626
+ try {
2627
+ await updateOne(ref, {
2628
+ subtype: dto.subtype,
2629
+ measure: scale
2630
+ });
2631
+ report.updated.push(ref);
2632
+ } catch (error) {
2633
+ report.failed.push({
2634
+ ref,
2635
+ error: (0, _embedpdf_engine_core_runtime.serializeError)(error)
2636
+ });
2637
+ }
2638
+ }
2639
+ return report;
2640
+ },
2510
2641
  create: async (pon, draft) => {
2511
2642
  const doc = ctx.doc;
2512
2643
  if (!doc) throw new Error("[annotation] no document bound");
@@ -2644,6 +2775,10 @@ function createAnnotationCapability(ctx, config = {}) {
2644
2775
  chrome: (pon, scale, rotation, zoom) => memoChrome(pon, scale, rotation, zoom),
2645
2776
  selectionAnchor: (scale, rotation, zoom) => memoAnchor(scale, rotation, zoom),
2646
2777
  creationDraftAnchor: () => memoDraftAnchor(),
2778
+ distanceCreationPage: () => {
2779
+ const draft = model().draft;
2780
+ return draft?.g === "create-distance" && draft.step === "offset" ? draft.pon : null;
2781
+ },
2647
2782
  selection: () => model().selected,
2648
2783
  hitKind: (pon, point, scale, rotation, zoom, touch) => (0, _embedpdf_core_annotation.hitTest)(model(), pon, point, chromeGeomAt(scale, grabBoost(touch)), model().hitMargin, pageBoxOf(pon), inertIdsAt(pon), viewEnv(zoom, rotation)).t,
2649
2784
  claimsTouchAt: (pon, point, scale, rotation, zoom) => {
@@ -2723,14 +2858,63 @@ function createAnnotationCapability(ctx, config = {}) {
2723
2858
  }
2724
2859
  }),
2725
2860
  createPointer: (tool, phase, pon, point, finish = false, displayRotation) => {
2726
- if (!allowsCreate()) return;
2727
2861
  const t = registry.get(tool);
2862
+ if (t?.meta?.capture === true ? !ctx.doc?.security.allows("doc.annotate.modify") : !allowsCreate()) return;
2863
+ const crop = cropOf(pon);
2864
+ const cache = pageViewports.get(pon);
2865
+ const draft = model().draft;
2866
+ const continuingMeasurement = (draft?.g === "create-distance" || draft?.g === "create-poly") && draft.pon === pon && draft.preset === (t?.preset ?? tool);
2867
+ const dimension = t && (0, _embedpdf_engine_core_runtime.isDimension)(t);
2868
+ if (dimension && phase === "down" && !continuingMeasurement && (!crop || !cache?.viewports)) return;
2869
+ const viewport = crop && cache?.viewports ? (0, _embedpdf_engine_core_runtime.viewportForPoint)(cache.viewports, {
2870
+ x: point.x + crop.left,
2871
+ y: crop.top - point.y
2872
+ }) : void 0;
2873
+ const measure = dimension && crop && cache ? {
2874
+ intent: t.intent,
2875
+ measure: viewport ? viewport.measure ?? null : cache.fallback,
2876
+ caption: t.measurement?.caption ?? { enabled: true },
2877
+ ...t.intent === "LineDimension" ? { leader: t.measurement?.leader } : {},
2878
+ crop,
2879
+ text: ""
2880
+ } : void 0;
2881
+ if (measure && phase === "down" && !continuingMeasurement && !(0, _embedpdf_engine_core_runtime.isReadout)((0, _embedpdf_engine_core_runtime.measurementReadout)({
2882
+ subtype: t.subtype,
2883
+ intent: measure.intent,
2884
+ measure: measure.measure,
2885
+ linePoints: {
2886
+ start: {
2887
+ x: 0,
2888
+ y: 0
2889
+ },
2890
+ end: {
2891
+ x: 1,
2892
+ y: 0
2893
+ }
2894
+ },
2895
+ vertices: [
2896
+ {
2897
+ x: 0,
2898
+ y: 0
2899
+ },
2900
+ {
2901
+ x: 1,
2902
+ y: 0
2903
+ },
2904
+ {
2905
+ x: 1,
2906
+ y: 1
2907
+ }
2908
+ ]
2909
+ }))) return;
2728
2910
  apply({
2729
2911
  t: "createPointer",
2912
+ measure,
2913
+ capture: t?.meta?.capture === true ? tool : void 0,
2730
2914
  phase,
2731
2915
  subtype: t?.subtype ?? tool,
2732
2916
  preset: t?.preset ?? tool,
2733
- intent: t?.intent,
2917
+ intent: t?.intent === "ink-highlight" ? t.intent : void 0,
2734
2918
  clickCreate: t?.clickCreate,
2735
2919
  flags: t?.flags,
2736
2920
  deferInkCommit: (t?.ink?.groupStrokesMs ?? 0) > 0,
@@ -2746,6 +2930,7 @@ function createAnnotationCapability(ctx, config = {}) {
2746
2930
  }
2747
2931
  });
2748
2932
  },
2933
+ hasCreationDraft: () => model().draft?.g.startsWith("create-") ?? false,
2749
2934
  finishCreationDraft: () => apply({ t: "finishCreationDraft" }),
2750
2935
  finishInkDraft: () => apply({ t: "finishInkDraft" }),
2751
2936
  cancelCreationDraft: () => apply({ t: "cancel" }),
@@ -3061,4 +3246,4 @@ Object.defineProperty(exports, "toPatch", {
3061
3246
  }
3062
3247
  });
3063
3248
 
3064
- //# sourceMappingURL=capability-DVx1NmTe.cjs.map
3249
+ //# sourceMappingURL=capability-Bt320iJP.cjs.map