@embedpdf/plugin-annotation 3.0.0-next.11 → 3.0.0-next.12

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.
@@ -1,4 +1,5 @@
1
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 { n as previewBucket } from "./types-BvB1vUKb.js";
2
3
  import { CONTINUOUS_RENDER_POLICY, snapAppearanceScale } from "@embedpdf/core";
3
4
  import { ActionsToken, createHoverPump } from "@embedpdf/plugin-actions/contract";
4
5
  import { InteractionToken } from "@embedpdf/plugin-interaction/contract";
@@ -774,6 +775,15 @@ function buildTextItems(m, pon, view) {
774
775
  //#endregion
775
776
  //#region src/tools.ts
776
777
  /**
778
+ * The tool `armStamp` activates — and the only tool an armed payload survives
779
+ * onto (plus the legacy `annotation-stamp` tag, honoured for embedder configs
780
+ * written before the tags were unified). Placement consults the armed payload
781
+ * BEFORE the active tool's own `source` spec, so a payload must not outlive
782
+ * its tool onto a sibling stamp preset: an `image` preset's click has to open
783
+ * its own picker, not silently place whatever the stamp panel last armed.
784
+ */
785
+ const ARMED_STAMP_TOOL_ID = "stamp";
786
+ /**
777
787
  * The creation properties each known authoring kind actually consumes. This is
778
788
  * deliberately separate from the flat internal patch vocabulary: it gives tool
779
789
  * configuration precise compile-time and runtime validation while mixed-selection
@@ -1107,7 +1117,7 @@ const DEFAULT_TOOLS = [
1107
1117
  }
1108
1118
  },
1109
1119
  {
1110
- id: "stamp",
1120
+ id: ARMED_STAMP_TOOL_ID,
1111
1121
  subtype: "stamp",
1112
1122
  cursor: "copy",
1113
1123
  enables: ["annotation-place", "annotation-edit"],
@@ -1565,6 +1575,14 @@ function createAnnotationCapability(ctx, config = {}) {
1565
1575
  * rendered, never synced, and dies with the tool.
1566
1576
  */
1567
1577
  let armedStamp = null;
1578
+ /** Fixed bytes as a provider: the same image at every size. */
1579
+ const fixedPreview = (bytes, mimeType) => {
1580
+ const preview = {
1581
+ bytes,
1582
+ ...mimeType ? { mimeType } : {}
1583
+ };
1584
+ return async () => preview;
1585
+ };
1568
1586
  /**
1569
1587
  * The desired stamp size (PDF points) from sniffed bytes: the image's
1570
1588
  * INTRINSIC pixel dimensions taken 1:1 as points (the v2 rule — keep the
@@ -1593,23 +1611,21 @@ function createAnnotationCapability(ctx, config = {}) {
1593
1611
  const meta = sniffBinaryMetadata(resolved.bytes);
1594
1612
  if (!meta) throw new Error("[annotation] stamp source must be PNG, JPEG, or single-page PDF bytes");
1595
1613
  let preview = null;
1596
- if (input.preview) {
1614
+ if (typeof input.preview === "function") preview = input.preview;
1615
+ else if (input.preview) {
1597
1616
  const p = await resolveBinarySource(input.preview);
1598
- preview = {
1599
- bytes: new Uint8Array(p.bytes),
1600
- mimeType: p.mimeType
1601
- };
1602
- } else if (meta.mimeType !== "application/pdf") preview = {
1603
- bytes: new Uint8Array(resolved.bytes),
1604
- mimeType: meta.mimeType
1605
- };
1617
+ preview = fixedPreview(new Uint8Array(p.bytes), p.mimeType);
1618
+ } else if (meta.mimeType !== "application/pdf") preview = fixedPreview(new Uint8Array(resolved.bytes), meta.mimeType);
1606
1619
  armedStamp = {
1607
1620
  source: input.source,
1608
1621
  ...desiredStampSize(meta, input.targetWidth, input.intrinsicSize),
1609
- preview
1622
+ preview,
1623
+ previewCache: /* @__PURE__ */ new Map(),
1624
+ ...input.name !== void 0 ? { name: input.name } : {},
1625
+ ...input.subject !== void 0 ? { subject: input.subject } : {}
1610
1626
  };
1611
1627
  ctx.dispatch({ type: "STAMP_ARM_CHANGED" });
1612
- ctx.tryGet(InteractionToken)?.activateTool("stamp");
1628
+ ctx.tryGet(InteractionToken)?.activateTool(ARMED_STAMP_TOOL_ID);
1613
1629
  };
1614
1630
  const disarmStamp = () => {
1615
1631
  if (!armedStamp) return;
@@ -1736,28 +1752,49 @@ function createAnnotationCapability(ctx, config = {}) {
1736
1752
  * emits the repository's box rotation fields — the engine bakes the tilted
1737
1753
  * /AP exactly as an interactively rotated stamp round-trips, and the fit uses
1738
1754
  * the ROTATED footprint. Returns false when the page/document isn't ready. */
1739
- const createStampAt = (pon, point, source, desired, rotCW = 0) => {
1755
+ const createStampAt = (pon, point, source, desired, rotCW = 0, identity = {}) => {
1740
1756
  const doc = ctx.doc;
1741
1757
  const crop = cropOf(pon);
1742
- if (!doc || !crop) return false;
1758
+ if (!doc || !crop) return null;
1743
1759
  const box = fitStampBox(point, desired, {
1744
1760
  width: crop.right - crop.left,
1745
1761
  height: crop.top - crop.bottom
1746
1762
  }, rotCW);
1747
- doc.page(pon).annotations.create({
1763
+ return doc.page(pon).annotations.create({
1748
1764
  subtype: "stamp",
1749
1765
  ...boxGeomFields(box, rotCW, crop),
1750
1766
  source,
1751
- fit: "contain"
1767
+ fit: "contain",
1768
+ ...identity.name !== void 0 ? { name: identity.name } : {},
1769
+ ...identity.subject !== void 0 ? { subject: identity.subject } : {}
1752
1770
  }).then((res) => {
1753
1771
  syncDTO(res.created, "baked");
1754
1772
  apply({
1755
1773
  t: "select",
1756
1774
  ids: [refKey(res.created.ref)]
1757
1775
  });
1758
- }, (err) => console.error("[annotation] stamp placement failed:", err));
1776
+ return res.created.ref;
1777
+ });
1778
+ };
1779
+ /** The click path's fire-and-forget wrapper: a rejected placement is logged,
1780
+ * never thrown into the gesture. */
1781
+ const createStampAtSync = (pon, point, source, desired, rotCW = 0, identity = {}) => {
1782
+ const placed = createStampAt(pon, point, source, desired, rotCW, identity);
1783
+ if (!placed) return false;
1784
+ placed.catch((err) => console.error("[annotation] stamp placement failed:", err));
1759
1785
  return true;
1760
1786
  };
1787
+ /** Programmatic placement — the same law as a click, awaited. */
1788
+ const placeStamp = async (input, placement) => {
1789
+ const meta = sniffBinaryMetadata((await resolveBinarySource(input.source)).bytes);
1790
+ if (!meta) throw new Error("[annotation] stamp source must be PNG, JPEG, or single-page PDF bytes");
1791
+ const placed = createStampAt(placement.pageObjectNumber, placement.at, input.source, desiredStampSize(meta, placement.targetWidth ?? input.targetWidth, input.intrinsicSize), placement.rotation ?? 0, {
1792
+ ...input.name !== void 0 ? { name: input.name } : {},
1793
+ ...input.subject !== void 0 ? { subject: input.subject } : {}
1794
+ });
1795
+ if (!placed) throw new Error(`[annotation] cannot place a stamp on page ${placement.pageObjectNumber}: document or page not ready`);
1796
+ return placed;
1797
+ };
1761
1798
  /** The active tool's upright counter-rotation for a click at `displayRotation`
1762
1799
  * (0 when the tool doesn't ask for upright, or the display isn't rotated). */
1763
1800
  const uprightRotFor = (displayRotation) => {
@@ -1768,10 +1805,13 @@ function createAnnotationCapability(ctx, config = {}) {
1768
1805
  const placeArmedStamp = (pon, point, displayRotation) => {
1769
1806
  const armed = armedStamp;
1770
1807
  if (!armed) return false;
1771
- return createStampAt(pon, point, armed.source, {
1808
+ return createStampAtSync(pon, point, armed.source, {
1772
1809
  width: armed.width,
1773
1810
  height: armed.height
1774
- }, uprightRotFor(displayRotation));
1811
+ }, uprightRotFor(displayRotation), {
1812
+ ...armed.name !== void 0 ? { name: armed.name } : {},
1813
+ ...armed.subject !== void 0 ? { subject: armed.subject } : {}
1814
+ });
1775
1815
  };
1776
1816
  /** Sniff a stamp source (rejecting non-image bytes) and place it at its
1777
1817
  * intrinsic size (fit to the page in {@link createStampAt}); `targetWidth`
@@ -1782,7 +1822,7 @@ function createAnnotationCapability(ctx, config = {}) {
1782
1822
  console.error("[annotation] stamp source must be PNG, JPEG, or single-page PDF bytes");
1783
1823
  return;
1784
1824
  }
1785
- createStampAt(pon, point, source, desiredStampSize(meta, targetWidth), rotCW);
1825
+ createStampAtSync(pon, point, source, desiredStampSize(meta, targetWidth), rotCW);
1786
1826
  };
1787
1827
  /**
1788
1828
  * Click-to-place: resolve the ACTIVE tool's source spec. Fixed `bytes` place
@@ -2532,6 +2572,7 @@ function createAnnotationCapability(ctx, config = {}) {
2532
2572
  return res.created.ref;
2533
2573
  },
2534
2574
  armStamp,
2575
+ placeStamp,
2535
2576
  disarmStamp,
2536
2577
  placeArmedStamp,
2537
2578
  requestStampAt,
@@ -2545,7 +2586,20 @@ function createAnnotationCapability(ctx, config = {}) {
2545
2586
  const g = ctx.getState().toolGhost;
2546
2587
  return g && g.pon === pon ? g : null;
2547
2588
  },
2548
- armedStampPreview: () => armedStamp?.preview ?? null,
2589
+ armedStampPreview: (devicePixelWidth) => {
2590
+ const armed = armedStamp;
2591
+ if (!armed?.preview) return Promise.resolve(null);
2592
+ const bucket = previewBucket(devicePixelWidth ?? 0);
2593
+ let pending = armed.previewCache.get(bucket);
2594
+ if (!pending) {
2595
+ pending = armed.preview(bucket).catch((error) => {
2596
+ console.error("[annotation] stamp ghost preview failed:", error);
2597
+ return null;
2598
+ });
2599
+ armed.previewCache.set(bucket, pending);
2600
+ }
2601
+ return pending;
2602
+ },
2549
2603
  stampArmEpoch: () => ctx.getState().stampArmEpoch,
2550
2604
  setFilePickerProvider: (provider) => {
2551
2605
  filePickerProvider = provider;
@@ -3027,6 +3081,6 @@ function createAnnotationCapability(ctx, config = {}) {
3027
3081
  };
3028
3082
  }
3029
3083
  //#endregion
3030
- export { fromDTO as a, isTouchDirect as i, DEFAULT_TOOLS as n, toCreateDraft as o, buildToolRegistry as r, toPatch as s, createAnnotationCapability as t };
3084
+ export { isTouchDirect as a, toPatch as c, buildToolRegistry as i, ARMED_STAMP_TOOL_ID as n, fromDTO as o, DEFAULT_TOOLS as r, toCreateDraft as s, createAnnotationCapability as t };
3031
3085
 
3032
- //# sourceMappingURL=capability-DBsr2D-L.js.map
3086
+ //# sourceMappingURL=capability-Bh_1PL5v.js.map