@embedpdf/react 3.0.0-next.1 → 3.0.0-next.10

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 (104) hide show
  1. package/dist/AnnotationListSnapshot-DDxHpJQU-BG32YXxG.d.cts +347 -0
  2. package/dist/AnnotationListSnapshot-DDxHpJQU-BG32YXxG.d.ts +347 -0
  3. package/dist/anchored.cjs +89 -0
  4. package/dist/anchored.cjs.map +1 -0
  5. package/dist/anchored.d.cts +45 -0
  6. package/dist/anchored.d.ts +45 -0
  7. package/dist/anchored.js +60 -0
  8. package/dist/anchored.js.map +1 -0
  9. package/dist/annotation-menu.cjs +33 -84
  10. package/dist/annotation-menu.cjs.map +1 -1
  11. package/dist/annotation-menu.d.cts +28 -2
  12. package/dist/annotation-menu.d.ts +28 -2
  13. package/dist/annotation-menu.js +27 -78
  14. package/dist/annotation-menu.js.map +1 -1
  15. package/dist/annotation.cjs +752 -16
  16. package/dist/annotation.cjs.map +1 -0
  17. package/dist/annotation.d.cts +159 -2
  18. package/dist/annotation.d.ts +159 -2
  19. package/dist/annotation.js +737 -3
  20. package/dist/annotation.js.map +1 -0
  21. package/dist/commands.js +1 -0
  22. package/dist/commands.js.map +1 -1
  23. package/dist/form.cjs +3 -3
  24. package/dist/form.cjs.map +1 -1
  25. package/dist/form.d.cts +2 -2
  26. package/dist/form.d.ts +2 -2
  27. package/dist/form.js +3 -3
  28. package/dist/form.js.map +1 -1
  29. package/dist/index.cjs +34 -5
  30. package/dist/index.d.cts +14 -8
  31. package/dist/index.d.ts +14 -8
  32. package/dist/index.js +8 -6
  33. package/dist/interaction.cjs +17 -4
  34. package/dist/interaction.cjs.map +1 -1
  35. package/dist/interaction.d.cts +2 -2
  36. package/dist/interaction.d.ts +2 -2
  37. package/dist/interaction.js +7 -5
  38. package/dist/interaction.js.map +1 -1
  39. package/dist/link.cjs +29 -6
  40. package/dist/link.cjs.map +1 -1
  41. package/dist/link.d.cts +12 -3
  42. package/dist/link.d.ts +12 -3
  43. package/dist/link.js +31 -8
  44. package/dist/link.js.map +1 -1
  45. package/dist/metadata.js +1 -0
  46. package/dist/metadata.js.map +1 -1
  47. package/dist/page-edit.js +1 -0
  48. package/dist/page-edit.js.map +1 -1
  49. package/dist/page-view.cjs +62 -38
  50. package/dist/page-view.cjs.map +1 -1
  51. package/dist/page-view.js +59 -37
  52. package/dist/page-view.js.map +1 -1
  53. package/dist/redaction.js +1 -0
  54. package/dist/redaction.js.map +1 -1
  55. package/dist/render.cjs +67 -50
  56. package/dist/render.cjs.map +1 -1
  57. package/dist/render.d.cts +6 -19
  58. package/dist/render.d.ts +6 -19
  59. package/dist/render.js +71 -52
  60. package/dist/render.js.map +1 -1
  61. package/dist/rolldown-runtime-BBjsoOtd.js +27 -0
  62. package/dist/{runtime-DV98q7I0.d.ts → runtime-Cvi0wQ4d.d.cts} +23 -10
  63. package/dist/{runtime-CMxIuF2O.d.cts → runtime-DXxr8T4L.d.ts} +23 -10
  64. package/dist/runtime.cjs +6 -5
  65. package/dist/runtime.cjs.map +1 -1
  66. package/dist/runtime.d.cts +1 -1
  67. package/dist/runtime.d.ts +1 -1
  68. package/dist/runtime.js +7 -5
  69. package/dist/runtime.js.map +1 -1
  70. package/dist/search.cjs +36 -19
  71. package/dist/search.cjs.map +1 -1
  72. package/dist/search.d.cts +1 -1
  73. package/dist/search.d.ts +1 -1
  74. package/dist/search.js +36 -19
  75. package/dist/search.js.map +1 -1
  76. package/dist/selection.cjs +217 -22
  77. package/dist/selection.cjs.map +1 -1
  78. package/dist/selection.d.cts +60 -2
  79. package/dist/selection.d.ts +60 -2
  80. package/dist/selection.js +214 -27
  81. package/dist/selection.js.map +1 -1
  82. package/dist/shell.js +1 -0
  83. package/dist/shell.js.map +1 -1
  84. package/dist/stage.cjs +47 -146
  85. package/dist/stage.cjs.map +1 -1
  86. package/dist/stage.d.cts +18 -5
  87. package/dist/stage.d.ts +18 -5
  88. package/dist/stage.js +50 -148
  89. package/dist/stage.js.map +1 -1
  90. package/dist/stamp.js +1 -0
  91. package/dist/stamp.js.map +1 -1
  92. package/dist/toolbar.js +1 -0
  93. package/dist/toolbar.js.map +1 -1
  94. package/dist/views.js +1 -0
  95. package/dist/views.js.map +1 -1
  96. package/package.json +27 -26
  97. package/dist/AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.cts +0 -2593
  98. package/dist/AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.ts +0 -2593
  99. package/dist/annotation-B6jwfTCh.d.cts +0 -173
  100. package/dist/annotation-Ct6dFtzJ.cjs +0 -913
  101. package/dist/annotation-Ct6dFtzJ.cjs.map +0 -1
  102. package/dist/annotation-DjGWJljY.js +0 -829
  103. package/dist/annotation-DjGWJljY.js.map +0 -1
  104. package/dist/annotation-nUMefyjw.d.ts +0 -173
@@ -0,0 +1,89 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rolldown_runtime = require("./rolldown-runtime-DDXJien1.cjs");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ let react = require("react");
5
+ react = require_rolldown_runtime.__toESM(react, 1);
6
+ let react_dom = require("react-dom");
7
+ let _embedpdf_web = require("@embedpdf/web");
8
+ //#region src/anchored.tsx
9
+ /**
10
+ * Anchored overlays — ONE primitive for every piece of UI that floats over
11
+ * page content (selection menus, draft menus, future popovers).
12
+ *
13
+ * The factoring:
14
+ * - PLUGINS produce anchors (a content-space rect on a page, plus points
15
+ * to dodge) as capability reads.
16
+ * - The projection SNAPSHOT contract and the placement math are shared,
17
+ * framework-neutral, in `@embedpdf/web` ({@link ViewProjector},
18
+ * `projectAnchoredTarget`).
19
+ * - SURFACES (<Stage>, <PageView>) provide a {@link ProjectorBinding}:
20
+ * the snapshot plus REACT's way of knowing when it changed.
21
+ * - <Anchored> renders at the projected position, isolates pointer
22
+ * events, and portals when the space demands it.
23
+ *
24
+ * THE SCHEDULING LAW (this is what keeps menus glued to the content): a
25
+ * state-driven projection change (the Stage camera) reaches consumers as a
26
+ * NEW BINDING IDENTITY through context — surface and overlay re-render in
27
+ * the SAME React commit, so they can never paint a frame apart. No
28
+ * listener sets, no post-commit notifications, no second menu-only render.
29
+ * `subscribe` exists ONLY for genuinely browser-driven invalidation (a
30
+ * PageView moving because the document scrolled), where no state change
31
+ * announces the move.
32
+ */
33
+ const ProjectorContext = (0, react.createContext)(null);
34
+ /** Installed by page surfaces (<Stage>, <PageView>) — not by app code. */
35
+ const ProjectorProvider = ProjectorContext.Provider;
36
+ /** The surface's projector binding. Reading it subscribes the caller to
37
+ * projection changes (the binding's identity IS the revision). */
38
+ function useProjectorBinding() {
39
+ const binding = (0, react.useContext)(ProjectorContext);
40
+ if (!binding) throw new Error("No ViewProjector in scope: mount anchored UI under <Stage> (overlay slot) or <PageView>.");
41
+ return binding;
42
+ }
43
+ /**
44
+ * Position `children` around a content-space anchor, on whichever page
45
+ * surface is in scope. Projection runs during render from the shared pure
46
+ * helper; pointer isolation keeps a click inside anchored UI from reaching
47
+ * the surface's own listener (which would read it as click-outside).
48
+ */
49
+ function Anchored({ anchor, placement = "top", gap = 8, children }) {
50
+ const { projector, subscribe } = useProjectorBinding();
51
+ const [, force] = (0, react.useReducer)((x) => x + 1, 0);
52
+ (0, react.useLayoutEffect)(() => subscribe ? subscribe(force) : void 0, [subscribe]);
53
+ (0, react.useLayoutEffect)(() => {
54
+ if (projector.space === "client") force();
55
+ }, [projector, anchor]);
56
+ const ref = (0, react.useRef)(null);
57
+ (0, react.useEffect)(() => {
58
+ const el = ref.current;
59
+ if (!el) return;
60
+ const stop = (e) => e.stopPropagation();
61
+ el.addEventListener("pointerdown", stop);
62
+ return () => el.removeEventListener("pointerdown", stop);
63
+ });
64
+ if (!anchor) return null;
65
+ const pos = (0, _embedpdf_web.projectAnchoredTarget)(projector, anchor, placement, gap);
66
+ if (!pos) return null;
67
+ const node = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
68
+ ref,
69
+ style: {
70
+ position: projector.space === "client" ? "fixed" : "absolute",
71
+ left: pos.left,
72
+ top: pos.top,
73
+ transform: pos.transform,
74
+ pointerEvents: "auto"
75
+ },
76
+ children
77
+ });
78
+ if (projector.space === "client") {
79
+ if (typeof document === "undefined") return null;
80
+ return (0, react_dom.createPortal)(node, document.body);
81
+ }
82
+ return node;
83
+ }
84
+ //#endregion
85
+ exports.Anchored = Anchored;
86
+ exports.ProjectorProvider = ProjectorProvider;
87
+ exports.useProjectorBinding = useProjectorBinding;
88
+
89
+ //# sourceMappingURL=anchored.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchored.cjs","names":[],"sources":["../src/anchored.tsx"],"sourcesContent":["/**\n * Anchored overlays — ONE primitive for every piece of UI that floats over\n * page content (selection menus, draft menus, future popovers).\n *\n * The factoring:\n * - PLUGINS produce anchors (a content-space rect on a page, plus points\n * to dodge) as capability reads.\n * - The projection SNAPSHOT contract and the placement math are shared,\n * framework-neutral, in `@embedpdf/web` ({@link ViewProjector},\n * `projectAnchoredTarget`).\n * - SURFACES (<Stage>, <PageView>) provide a {@link ProjectorBinding}:\n * the snapshot plus REACT's way of knowing when it changed.\n * - <Anchored> renders at the projected position, isolates pointer\n * events, and portals when the space demands it.\n *\n * THE SCHEDULING LAW (this is what keeps menus glued to the content): a\n * state-driven projection change (the Stage camera) reaches consumers as a\n * NEW BINDING IDENTITY through context — surface and overlay re-render in\n * the SAME React commit, so they can never paint a frame apart. No\n * listener sets, no post-commit notifications, no second menu-only render.\n * `subscribe` exists ONLY for genuinely browser-driven invalidation (a\n * PageView moving because the document scrolled), where no state change\n * announces the move.\n */\nimport * as React from 'react';\nimport { createContext, useContext, useEffect, useLayoutEffect, useReducer, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n projectAnchoredTarget,\n type AnchoredPlacement,\n type AnchorTarget,\n type ViewProjector,\n} from '@embedpdf/web';\n\nexport type { AnchoredPlacement, AnchorTarget, ViewProjector } from '@embedpdf/web';\n\n/**\n * What a page surface provides via context: the pure projection snapshot,\n * bound to React's reactivity.\n */\nexport interface ProjectorBinding {\n projector: ViewProjector;\n /**\n * Changes identity exactly when projection may have changed for\n * STATE-driven reasons — the Stage uses its `visiblePages()` value (a\n * stable reference that already folds camera, viewport, scene and DPR).\n * Consumers re-render because the binding's identity changes with it;\n * nothing reads this field, but it is what makes the memoized binding\n * change, so do not \"optimize\" it away.\n */\n revision: unknown;\n /** Browser-driven invalidation ONLY (PageView scroll/resize — see\n * `observeClientGeometry`). The Stage deliberately provides none. */\n subscribe?: (callback: () => void) => () => void;\n}\n\nconst ProjectorContext = createContext<ProjectorBinding | null>(null);\n\n/** Installed by page surfaces (<Stage>, <PageView>) — not by app code. */\nexport const ProjectorProvider = ProjectorContext.Provider;\n\n/** The surface's projector binding. Reading it subscribes the caller to\n * projection changes (the binding's identity IS the revision). */\nexport function useProjectorBinding(): ProjectorBinding {\n const binding = useContext(ProjectorContext);\n if (!binding) {\n throw new Error(\n 'No ViewProjector in scope: mount anchored UI under <Stage> (overlay slot) or <PageView>.',\n );\n }\n return binding;\n}\n\nexport interface AnchoredProps {\n anchor: AnchorTarget | null;\n /** Which side of the anchor to sit on. Default 'top'. */\n placement?: AnchoredPlacement;\n /** Gap in screen px between the anchor box and the content. Default 8. */\n gap?: number;\n children: React.ReactNode;\n}\n\n/**\n * Position `children` around a content-space anchor, on whichever page\n * surface is in scope. Projection runs during render from the shared pure\n * helper; pointer isolation keeps a click inside anchored UI from reaching\n * the surface's own listener (which would read it as click-outside).\n */\nexport function Anchored({ anchor, placement = 'top', gap = 8, children }: AnchoredProps) {\n const { projector, subscribe } = useProjectorBinding();\n\n // Browser-driven invalidation only (PageView). State-driven changes come\n // through the binding identity — no local bump involved.\n const [, force] = useReducer((x: number) => x + 1, 0);\n useLayoutEffect(() => (subscribe ? subscribe(force) : undefined), [subscribe]);\n // Client-space surfaces measure the DOM, which does not exist during the\n // surface's first render — force one post-commit pass so the position\n // appears as soon as it is measurable. (Solves measurability, not\n // reactivity.)\n useLayoutEffect(() => {\n if (projector.space === 'client') force();\n }, [projector, anchor]);\n\n const ref = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n });\n\n if (!anchor) return null;\n const pos = projectAnchoredTarget(projector, anchor, placement, gap);\n if (!pos) return null;\n\n const node = (\n <div\n ref={ref}\n style={{\n position: projector.space === 'client' ? 'fixed' : 'absolute',\n left: pos.left,\n top: pos.top,\n transform: pos.transform,\n pointerEvents: 'auto',\n }}\n >\n {children}\n </div>\n );\n if (projector.space === 'client') {\n if (typeof document === 'undefined') return null;\n return createPortal(node, document.body);\n }\n return node;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAM,oBAAA,GAAA,MAAA,cAAA,CAA0D,IAAI;;AAGpE,MAAa,oBAAoB,iBAAiB;;;AAIlD,SAAgB,sBAAwC;CACtD,MAAM,WAAA,GAAA,MAAA,WAAA,CAAqB,gBAAgB;CAC3C,IAAI,CAAC,SACH,MAAM,IAAI,MACR,0FACF;CAEF,OAAO;AACT;;;;;;;AAiBA,SAAgB,SAAS,EAAE,QAAQ,YAAY,OAAO,MAAM,GAAG,YAA2B;CACxF,MAAM,EAAE,WAAW,cAAc,oBAAoB;CAIrD,MAAM,GAAG,UAAA,GAAA,MAAA,WAAA,EAAqB,MAAc,IAAI,GAAG,CAAC;CACpD,CAAA,GAAA,MAAA,gBAAA,OAAuB,YAAY,UAAU,KAAK,IAAI,KAAA,GAAY,CAAC,SAAS,CAAC;CAK7E,CAAA,GAAA,MAAA,gBAAA,OAAsB;EACpB,IAAI,UAAU,UAAU,UAAU,MAAM;CAC1C,GAAG,CAAC,WAAW,MAAM,CAAC;CAEtB,MAAM,OAAA,GAAA,MAAA,OAAA,CAA6B,IAAI;CACvC,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,IAAI;EACT,MAAM,QAAQ,MAAa,EAAE,gBAAgB;EAC7C,GAAG,iBAAiB,eAAe,IAAI;EACvC,aAAa,GAAG,oBAAoB,eAAe,IAAI;CACzD,CAAC;CAED,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,OAAA,GAAA,cAAA,sBAAA,CAA4B,WAAW,QAAQ,WAAW,GAAG;CACnE,IAAI,CAAC,KAAK,OAAO;CAEjB,MAAM,OACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EACO;EACL,OAAO;GACL,UAAU,UAAU,UAAU,WAAW,UAAU;GACnD,MAAM,IAAI;GACV,KAAK,IAAI;GACT,WAAW,IAAI;GACf,eAAe;EACjB;EAEC;CACE,CAAA;CAEP,IAAI,UAAU,UAAU,UAAU;EAChC,IAAI,OAAO,aAAa,aAAa,OAAO;EAC5C,QAAA,GAAA,UAAA,aAAA,CAAoB,MAAM,SAAS,IAAI;CACzC;CACA,OAAO;AACT"}
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+ import { AnchorTarget, AnchorTarget as AnchorTarget$1, AnchoredPlacement, AnchoredPlacement as AnchoredPlacement$1, ViewProjector, ViewProjector as ViewProjector$1 } from "@embedpdf/web";
3
+ //#region src/anchored.d.ts
4
+ /**
5
+ * What a page surface provides via context: the pure projection snapshot,
6
+ * bound to React's reactivity.
7
+ */
8
+ interface ProjectorBinding {
9
+ projector: ViewProjector$1;
10
+ /**
11
+ * Changes identity exactly when projection may have changed for
12
+ * STATE-driven reasons — the Stage uses its `visiblePages()` value (a
13
+ * stable reference that already folds camera, viewport, scene and DPR).
14
+ * Consumers re-render because the binding's identity changes with it;
15
+ * nothing reads this field, but it is what makes the memoized binding
16
+ * change, so do not "optimize" it away.
17
+ */
18
+ revision: unknown;
19
+ /** Browser-driven invalidation ONLY (PageView scroll/resize — see
20
+ * `observeClientGeometry`). The Stage deliberately provides none. */
21
+ subscribe?: (callback: () => void) => () => void;
22
+ }
23
+ /** Installed by page surfaces (<Stage>, <PageView>) — not by app code. */
24
+ declare const ProjectorProvider: React.Provider<ProjectorBinding | null>;
25
+ /** The surface's projector binding. Reading it subscribes the caller to
26
+ * projection changes (the binding's identity IS the revision). */
27
+ declare function useProjectorBinding(): ProjectorBinding;
28
+ interface AnchoredProps {
29
+ anchor: AnchorTarget$1 | null;
30
+ /** Which side of the anchor to sit on. Default 'top'. */
31
+ placement?: AnchoredPlacement$1;
32
+ /** Gap in screen px between the anchor box and the content. Default 8. */
33
+ gap?: number;
34
+ children: React.ReactNode;
35
+ }
36
+ /**
37
+ * Position `children` around a content-space anchor, on whichever page
38
+ * surface is in scope. Projection runs during render from the shared pure
39
+ * helper; pointer isolation keeps a click inside anchored UI from reaching
40
+ * the surface's own listener (which would read it as click-outside).
41
+ */
42
+ declare function Anchored({ anchor, placement, gap, children }: AnchoredProps): import("react/jsx-runtime").JSX.Element | null;
43
+ //#endregion
44
+ export { type AnchorTarget, Anchored, type AnchoredPlacement, AnchoredProps, ProjectorBinding, ProjectorProvider, type ViewProjector, useProjectorBinding };
45
+ //# sourceMappingURL=anchored.d.cts.map
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+ import { AnchorTarget, AnchorTarget as AnchorTarget$1, AnchoredPlacement, AnchoredPlacement as AnchoredPlacement$1, ViewProjector, ViewProjector as ViewProjector$1 } from "@embedpdf/web";
3
+ //#region src/anchored.d.ts
4
+ /**
5
+ * What a page surface provides via context: the pure projection snapshot,
6
+ * bound to React's reactivity.
7
+ */
8
+ interface ProjectorBinding {
9
+ projector: ViewProjector$1;
10
+ /**
11
+ * Changes identity exactly when projection may have changed for
12
+ * STATE-driven reasons — the Stage uses its `visiblePages()` value (a
13
+ * stable reference that already folds camera, viewport, scene and DPR).
14
+ * Consumers re-render because the binding's identity changes with it;
15
+ * nothing reads this field, but it is what makes the memoized binding
16
+ * change, so do not "optimize" it away.
17
+ */
18
+ revision: unknown;
19
+ /** Browser-driven invalidation ONLY (PageView scroll/resize — see
20
+ * `observeClientGeometry`). The Stage deliberately provides none. */
21
+ subscribe?: (callback: () => void) => () => void;
22
+ }
23
+ /** Installed by page surfaces (<Stage>, <PageView>) — not by app code. */
24
+ declare const ProjectorProvider: React.Provider<ProjectorBinding | null>;
25
+ /** The surface's projector binding. Reading it subscribes the caller to
26
+ * projection changes (the binding's identity IS the revision). */
27
+ declare function useProjectorBinding(): ProjectorBinding;
28
+ interface AnchoredProps {
29
+ anchor: AnchorTarget$1 | null;
30
+ /** Which side of the anchor to sit on. Default 'top'. */
31
+ placement?: AnchoredPlacement$1;
32
+ /** Gap in screen px between the anchor box and the content. Default 8. */
33
+ gap?: number;
34
+ children: React.ReactNode;
35
+ }
36
+ /**
37
+ * Position `children` around a content-space anchor, on whichever page
38
+ * surface is in scope. Projection runs during render from the shared pure
39
+ * helper; pointer isolation keeps a click inside anchored UI from reaching
40
+ * the surface's own listener (which would read it as click-outside).
41
+ */
42
+ declare function Anchored({ anchor, placement, gap, children }: AnchoredProps): import("react/jsx-runtime").JSX.Element | null;
43
+ //#endregion
44
+ export { type AnchorTarget, Anchored, type AnchoredPlacement, AnchoredProps, ProjectorBinding, ProjectorProvider, type ViewProjector, useProjectorBinding };
45
+ //# sourceMappingURL=anchored.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useLayoutEffect, useReducer, useRef } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { projectAnchoredTarget } from "@embedpdf/web";
5
+ //#region src/anchored.tsx
6
+ const ProjectorContext = createContext(null);
7
+ /** Installed by page surfaces (<Stage>, <PageView>) — not by app code. */
8
+ const ProjectorProvider = ProjectorContext.Provider;
9
+ /** The surface's projector binding. Reading it subscribes the caller to
10
+ * projection changes (the binding's identity IS the revision). */
11
+ function useProjectorBinding() {
12
+ const binding = useContext(ProjectorContext);
13
+ if (!binding) throw new Error("No ViewProjector in scope: mount anchored UI under <Stage> (overlay slot) or <PageView>.");
14
+ return binding;
15
+ }
16
+ /**
17
+ * Position `children` around a content-space anchor, on whichever page
18
+ * surface is in scope. Projection runs during render from the shared pure
19
+ * helper; pointer isolation keeps a click inside anchored UI from reaching
20
+ * the surface's own listener (which would read it as click-outside).
21
+ */
22
+ function Anchored({ anchor, placement = "top", gap = 8, children }) {
23
+ const { projector, subscribe } = useProjectorBinding();
24
+ const [, force] = useReducer((x) => x + 1, 0);
25
+ useLayoutEffect(() => subscribe ? subscribe(force) : void 0, [subscribe]);
26
+ useLayoutEffect(() => {
27
+ if (projector.space === "client") force();
28
+ }, [projector, anchor]);
29
+ const ref = useRef(null);
30
+ useEffect(() => {
31
+ const el = ref.current;
32
+ if (!el) return;
33
+ const stop = (e) => e.stopPropagation();
34
+ el.addEventListener("pointerdown", stop);
35
+ return () => el.removeEventListener("pointerdown", stop);
36
+ });
37
+ if (!anchor) return null;
38
+ const pos = projectAnchoredTarget(projector, anchor, placement, gap);
39
+ if (!pos) return null;
40
+ const node = /* @__PURE__ */ jsx("div", {
41
+ ref,
42
+ style: {
43
+ position: projector.space === "client" ? "fixed" : "absolute",
44
+ left: pos.left,
45
+ top: pos.top,
46
+ transform: pos.transform,
47
+ pointerEvents: "auto"
48
+ },
49
+ children
50
+ });
51
+ if (projector.space === "client") {
52
+ if (typeof document === "undefined") return null;
53
+ return createPortal(node, document.body);
54
+ }
55
+ return node;
56
+ }
57
+ //#endregion
58
+ export { Anchored, ProjectorProvider, useProjectorBinding };
59
+
60
+ //# sourceMappingURL=anchored.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchored.js","names":[],"sources":["../src/anchored.tsx"],"sourcesContent":["/**\n * Anchored overlays — ONE primitive for every piece of UI that floats over\n * page content (selection menus, draft menus, future popovers).\n *\n * The factoring:\n * - PLUGINS produce anchors (a content-space rect on a page, plus points\n * to dodge) as capability reads.\n * - The projection SNAPSHOT contract and the placement math are shared,\n * framework-neutral, in `@embedpdf/web` ({@link ViewProjector},\n * `projectAnchoredTarget`).\n * - SURFACES (<Stage>, <PageView>) provide a {@link ProjectorBinding}:\n * the snapshot plus REACT's way of knowing when it changed.\n * - <Anchored> renders at the projected position, isolates pointer\n * events, and portals when the space demands it.\n *\n * THE SCHEDULING LAW (this is what keeps menus glued to the content): a\n * state-driven projection change (the Stage camera) reaches consumers as a\n * NEW BINDING IDENTITY through context — surface and overlay re-render in\n * the SAME React commit, so they can never paint a frame apart. No\n * listener sets, no post-commit notifications, no second menu-only render.\n * `subscribe` exists ONLY for genuinely browser-driven invalidation (a\n * PageView moving because the document scrolled), where no state change\n * announces the move.\n */\nimport * as React from 'react';\nimport { createContext, useContext, useEffect, useLayoutEffect, useReducer, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n projectAnchoredTarget,\n type AnchoredPlacement,\n type AnchorTarget,\n type ViewProjector,\n} from '@embedpdf/web';\n\nexport type { AnchoredPlacement, AnchorTarget, ViewProjector } from '@embedpdf/web';\n\n/**\n * What a page surface provides via context: the pure projection snapshot,\n * bound to React's reactivity.\n */\nexport interface ProjectorBinding {\n projector: ViewProjector;\n /**\n * Changes identity exactly when projection may have changed for\n * STATE-driven reasons — the Stage uses its `visiblePages()` value (a\n * stable reference that already folds camera, viewport, scene and DPR).\n * Consumers re-render because the binding's identity changes with it;\n * nothing reads this field, but it is what makes the memoized binding\n * change, so do not \"optimize\" it away.\n */\n revision: unknown;\n /** Browser-driven invalidation ONLY (PageView scroll/resize — see\n * `observeClientGeometry`). The Stage deliberately provides none. */\n subscribe?: (callback: () => void) => () => void;\n}\n\nconst ProjectorContext = createContext<ProjectorBinding | null>(null);\n\n/** Installed by page surfaces (<Stage>, <PageView>) — not by app code. */\nexport const ProjectorProvider = ProjectorContext.Provider;\n\n/** The surface's projector binding. Reading it subscribes the caller to\n * projection changes (the binding's identity IS the revision). */\nexport function useProjectorBinding(): ProjectorBinding {\n const binding = useContext(ProjectorContext);\n if (!binding) {\n throw new Error(\n 'No ViewProjector in scope: mount anchored UI under <Stage> (overlay slot) or <PageView>.',\n );\n }\n return binding;\n}\n\nexport interface AnchoredProps {\n anchor: AnchorTarget | null;\n /** Which side of the anchor to sit on. Default 'top'. */\n placement?: AnchoredPlacement;\n /** Gap in screen px between the anchor box and the content. Default 8. */\n gap?: number;\n children: React.ReactNode;\n}\n\n/**\n * Position `children` around a content-space anchor, on whichever page\n * surface is in scope. Projection runs during render from the shared pure\n * helper; pointer isolation keeps a click inside anchored UI from reaching\n * the surface's own listener (which would read it as click-outside).\n */\nexport function Anchored({ anchor, placement = 'top', gap = 8, children }: AnchoredProps) {\n const { projector, subscribe } = useProjectorBinding();\n\n // Browser-driven invalidation only (PageView). State-driven changes come\n // through the binding identity — no local bump involved.\n const [, force] = useReducer((x: number) => x + 1, 0);\n useLayoutEffect(() => (subscribe ? subscribe(force) : undefined), [subscribe]);\n // Client-space surfaces measure the DOM, which does not exist during the\n // surface's first render — force one post-commit pass so the position\n // appears as soon as it is measurable. (Solves measurability, not\n // reactivity.)\n useLayoutEffect(() => {\n if (projector.space === 'client') force();\n }, [projector, anchor]);\n\n const ref = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n });\n\n if (!anchor) return null;\n const pos = projectAnchoredTarget(projector, anchor, placement, gap);\n if (!pos) return null;\n\n const node = (\n <div\n ref={ref}\n style={{\n position: projector.space === 'client' ? 'fixed' : 'absolute',\n left: pos.left,\n top: pos.top,\n transform: pos.transform,\n pointerEvents: 'auto',\n }}\n >\n {children}\n </div>\n );\n if (projector.space === 'client') {\n if (typeof document === 'undefined') return null;\n return createPortal(node, document.body);\n }\n return node;\n}\n"],"mappings":";;;;;AAwDA,MAAM,mBAAmB,cAAuC,IAAI;;AAGpE,MAAa,oBAAoB,iBAAiB;;;AAIlD,SAAgB,sBAAwC;CACtD,MAAM,UAAU,WAAW,gBAAgB;CAC3C,IAAI,CAAC,SACH,MAAM,IAAI,MACR,0FACF;CAEF,OAAO;AACT;;;;;;;AAiBA,SAAgB,SAAS,EAAE,QAAQ,YAAY,OAAO,MAAM,GAAG,YAA2B;CACxF,MAAM,EAAE,WAAW,cAAc,oBAAoB;CAIrD,MAAM,GAAG,SAAS,YAAY,MAAc,IAAI,GAAG,CAAC;CACpD,sBAAuB,YAAY,UAAU,KAAK,IAAI,KAAA,GAAY,CAAC,SAAS,CAAC;CAK7E,sBAAsB;EACpB,IAAI,UAAU,UAAU,UAAU,MAAM;CAC1C,GAAG,CAAC,WAAW,MAAM,CAAC;CAEtB,MAAM,MAAM,OAAuB,IAAI;CACvC,gBAAgB;EACd,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,IAAI;EACT,MAAM,QAAQ,MAAa,EAAE,gBAAgB;EAC7C,GAAG,iBAAiB,eAAe,IAAI;EACvC,aAAa,GAAG,oBAAoB,eAAe,IAAI;CACzD,CAAC;CAED,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,MAAM,sBAAsB,WAAW,QAAQ,WAAW,GAAG;CACnE,IAAI,CAAC,KAAK,OAAO;CAEjB,MAAM,OACJ,oBAAC,OAAD;EACO;EACL,OAAO;GACL,UAAU,UAAU,UAAU,WAAW,UAAU;GACnD,MAAM,IAAI;GACV,KAAK,IAAI;GACT,WAAW,IAAI;GACf,eAAe;EACjB;EAEC;CACE,CAAA;CAEP,IAAI,UAAU,UAAU,UAAU;EAChC,IAAI,OAAO,aAAa,aAAa,OAAO;EAC5C,OAAO,aAAa,MAAM,SAAS,IAAI;CACzC;CACA,OAAO;AACT"}
@@ -1,111 +1,60 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-DDXJien1.cjs");
3
3
  const require_runtime = require("./runtime.cjs");
4
- const require_annotation = require("./annotation-Ct6dFtzJ.cjs");
4
+ const require_anchored = require("./anchored.cjs");
5
+ const require_annotation = require("./annotation.cjs");
5
6
  let react_jsx_runtime = require("react/jsx-runtime");
6
7
  let react = require("react");
7
8
  react = require_rolldown_runtime.__toESM(react, 1);
8
- let _embedpdf_plugin_stage = require("@embedpdf/plugin-stage");
9
9
  let _embedpdf_plugin_annotation_internal = require("@embedpdf/plugin-annotation/internal");
10
10
  //#region src/annotation-menu.tsx
11
11
  /**
12
- * <AnnotationMenu> — the DEFAULT, Stage-bound selection menu.
12
+ * Annotation menus — thin anchor plumbing over the ONE `<Anchored>` primitive.
13
13
  *
14
- * Marker-style: it transforms the selected content rect through the Stage camera
15
- * and renders an upright menu in viewport space. Mount it in the Stage `overlay`
16
- * slot. It re-renders on `visiblePages()`, so it tracks pan/zoom and page
17
- * rotation/layout changes with no DOM measurement, no portal, no scroll listeners.
14
+ * These work identically under `<Stage>` (mount in the overlay slot; the
15
+ * camera projects, no DOM reads) and `<PageView>` (measured + portalled) —
16
+ * the SURFACE provides the projector, the menu doesn't care.
18
17
  *
19
- * This module is the ONLY annotation menu that imports `@embedpdf/plugin-stage`.
20
- * For a Stage-free `<PageView>`, use `<PageAnnotationMenu>` from
21
- * `@embedpdf/react/annotation` instead.
18
+ * No action bags: actions come from the capability hooks (`useAnnotation()`,
19
+ * `useAnnotationSelected()`, …), which subscribe properly and compose across
20
+ * plugins. Render props carry only the ANCHOR'S DATA (the draft menu's
21
+ * progress facts); the annotation-selection menu takes plain children.
22
+ */
23
+ /**
24
+ * Floats over the current annotation selection (one anchor regardless of
25
+ * cross-page selection), dodging the rotate knob. Compose the contents from
26
+ * hooks: `useAnnotation()` for the verbs, `useAnnotationSelected()` /
27
+ * `useSelectionProps()` for the data.
22
28
  */
23
29
  function AnnotationMenu({ children, gap = 15, placement = "top" }) {
24
- const stage = require_runtime.useCapability(_embedpdf_plugin_stage.StageToken);
25
- const anno = require_runtime.useCapability(_embedpdf_plugin_annotation_internal.AnnotationToken);
26
- require_runtime.useSelector(_embedpdf_plugin_stage.StageToken, (c) => c.visiblePages());
30
+ const { projector } = require_anchored.useProjectorBinding();
27
31
  const anchor = require_runtime.useSelector(_embedpdf_plugin_annotation_internal.AnnotationToken, (c) => {
28
32
  const a = c.selectionAnchor();
29
33
  if (!a) return null;
30
- const t = stage.pageRect(a.pon)?.transform;
31
- return t?.viewScale ? c.selectionAnchor(t.viewScale, t.rotation, t.zoom) : a;
34
+ const env = projector.viewEnv(a.pon);
35
+ return env ? c.selectionAnchor(env.scale, env.rotation, env.zoom) : a;
32
36
  }, require_annotation.sameAnchor);
33
- const selected = require_annotation.useAnnotationSelected();
34
- const ref = (0, react.useRef)(null);
35
- (0, react.useEffect)(() => {
36
- const el = ref.current;
37
- if (!el) return;
38
- const stop = (e) => e.stopPropagation();
39
- el.addEventListener("pointerdown", stop);
40
- return () => el.removeEventListener("pointerdown", stop);
41
- });
42
37
  if (!anchor) return null;
43
- const box = stage.pageRectToScreen(anchor.pon, anchor.bounds);
44
- if (!box) return null;
45
- const kr = anchor.knob ? stage.pageRectToScreen(anchor.pon, {
46
- x: anchor.knob.x,
47
- y: anchor.knob.y,
48
- width: 0,
49
- height: 0
50
- }) : null;
51
- const pos = require_annotation.positionMenuAroundRect(box, placement, gap, kr ? {
52
- x: kr.x,
53
- y: kr.y
54
- } : null);
55
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
56
- ref,
57
- style: {
58
- position: "absolute",
59
- left: pos.left,
60
- top: pos.top,
61
- transform: pos.transform,
62
- pointerEvents: "auto"
38
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_anchored.Anchored, {
39
+ anchor: {
40
+ pon: anchor.pon,
41
+ bounds: anchor.bounds,
42
+ ...anchor.knob ? { avoid: [anchor.knob] } : {}
63
43
  },
64
- children: children({
65
- selected,
66
- deleteSelection: anno.deleteSelection,
67
- deselect: anno.deselect,
68
- updateSelection: anno.updateSelection,
69
- rotate90: anno.rotateSelection90,
70
- resetRotation: anno.resetSelectionRotation,
71
- group: anno.group,
72
- ungroup: anno.ungroup,
73
- canGroup: anno.canGroup(),
74
- canUngroup: anno.canUngroup()
75
- })
44
+ placement,
45
+ gap,
46
+ children
76
47
  });
77
48
  }
49
+ /** Floats over a live multi-click creation draft (polygon, polyline, …). */
78
50
  function AnnotationDraftMenu({ children, gap = 8, placement = "top" }) {
79
- const stage = require_runtime.useCapability(_embedpdf_plugin_stage.StageToken);
80
- const anno = require_runtime.useCapability(_embedpdf_plugin_annotation_internal.AnnotationToken);
81
- require_runtime.useSelector(_embedpdf_plugin_stage.StageToken, (c) => c.visiblePages());
82
51
  const anchor = require_runtime.useSelector(_embedpdf_plugin_annotation_internal.AnnotationToken, (c) => c.creationDraftAnchor(), require_annotation.sameCreationDraftAnchor);
83
- const ref = (0, react.useRef)(null);
84
- (0, react.useEffect)(() => {
85
- const el = ref.current;
86
- if (!el) return;
87
- const stop = (e) => e.stopPropagation();
88
- el.addEventListener("pointerdown", stop);
89
- return () => el.removeEventListener("pointerdown", stop);
90
- });
91
52
  if (!anchor) return null;
92
- const box = stage.pageRectToScreen(anchor.pon, anchor.bounds);
93
- if (!box) return null;
94
- const pos = require_annotation.positionMenuAroundRect(box, placement, gap);
95
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
96
- ref,
97
- style: {
98
- position: "absolute",
99
- left: pos.left,
100
- top: pos.top,
101
- transform: pos.transform,
102
- pointerEvents: "auto"
103
- },
104
- children: children({
105
- ...anchor,
106
- finish: anno.finishCreationDraft,
107
- cancel: anno.cancelCreationDraft
108
- })
53
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_anchored.Anchored, {
54
+ anchor,
55
+ placement,
56
+ gap,
57
+ children: children(anchor)
109
58
  });
110
59
  }
111
60
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"annotation-menu.cjs","names":["useCapability","StageToken","AnnotationHostToken","useSelector","sameAnchor","useAnnotationSelected","positionMenuAroundRect","sameCreationDraftAnchor"],"sources":["../src/annotation-menu.tsx"],"sourcesContent":["/**\n * <AnnotationMenu> — the DEFAULT, Stage-bound selection menu.\n *\n * Marker-style: it transforms the selected content rect through the Stage camera\n * and renders an upright menu in viewport space. Mount it in the Stage `overlay`\n * slot. It re-renders on `visiblePages()`, so it tracks pan/zoom and page\n * rotation/layout changes with no DOM measurement, no portal, no scroll listeners.\n *\n * This module is the ONLY annotation menu that imports `@embedpdf/plugin-stage`.\n * For a Stage-free `<PageView>`, use `<PageAnnotationMenu>` from\n * `@embedpdf/react/annotation` instead.\n */\nimport * as React from 'react';\nimport { useEffect, useRef } from 'react';\nimport { StageToken } from '@embedpdf/plugin-stage';\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/internal';\nimport { useCapability, useSelector } from './runtime';\nimport {\n sameAnchor,\n sameCreationDraftAnchor,\n useAnnotationSelected,\n type AnnotationDraftMenuProps,\n type AnnotationMenuProps,\n} from './annotation';\nimport { positionMenuAroundRect } from './internal/annotation-menu-position';\n\nexport function AnnotationMenu({ children, gap = 15, placement = 'top' }: AnnotationMenuProps) {\n const stage = useCapability(StageToken);\n const anno = useCapability(AnnotationHostToken);\n // Reposition on pan/zoom AND rotation/layout changes. `visiblePages()` folds in\n // the scene key, camera, viewport, and DPR, while staying referentially stable.\n useSelector(StageToken, (c) => c.visiblePages());\n // Two-step anchor resolve: the pon comes from the scale-less anchor, then the\n // knob is re-projected with THAT page's view scale so the menu dodges the knob\n // where it actually renders (screen-constant stalk).\n const anchor = useSelector(\n AnnotationHostToken,\n (c) => {\n const a = c.selectionAnchor();\n if (!a) return null;\n const t = stage.pageRect(a.pon)?.transform;\n return t?.viewScale ? c.selectionAnchor(t.viewScale, t.rotation, t.zoom) : a;\n },\n sameAnchor,\n );\n const selected = useAnnotationSelected();\n\n // Isolate the menu from the Stage's pointer forwarding: a pointerdown inside it\n // must NOT bubble up to the Stage container's NATIVE listener, which would\n // forward to the interaction hub and read it as a click-outside → deselect (and\n // unmount this menu). Native listener (not React's) so it runs during real DOM\n // bubbling, before the Stage's own native listener on the ancestor. Inner button\n // `onClick` still fires — `click` is a separate event that reaches React's root.\n const ref = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n });\n\n if (!anchor) return null;\n const box = stage.pageRectToScreen(anchor.pon, anchor.bounds);\n if (!box) return null;\n // Transform the knob via a zero-size rect so page rotation is respected; the\n // menu then nudges only the edge it sits on (and only if the knob protrudes).\n const kr = anchor.knob\n ? stage.pageRectToScreen(anchor.pon, {\n x: anchor.knob.x,\n y: anchor.knob.y,\n width: 0,\n height: 0,\n })\n : null;\n const pos = positionMenuAroundRect(box, placement, gap, kr ? { x: kr.x, y: kr.y } : null);\n return (\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: pos.left,\n top: pos.top,\n transform: pos.transform,\n pointerEvents: 'auto',\n }}\n >\n {children({\n selected,\n deleteSelection: anno.deleteSelection,\n deselect: anno.deselect,\n updateSelection: anno.updateSelection,\n rotate90: anno.rotateSelection90,\n resetRotation: anno.resetSelectionRotation,\n group: anno.group,\n ungroup: anno.ungroup,\n canGroup: anno.canGroup(),\n canUngroup: anno.canUngroup(),\n })}\n </div>\n );\n}\n\nexport function AnnotationDraftMenu({\n children,\n gap = 8,\n placement = 'top',\n}: AnnotationDraftMenuProps) {\n const stage = useCapability(StageToken);\n const anno = useCapability(AnnotationHostToken);\n useSelector(StageToken, (c) => c.visiblePages());\n const anchor = useSelector(\n AnnotationHostToken,\n (c) => c.creationDraftAnchor(),\n sameCreationDraftAnchor,\n );\n\n const ref = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n });\n\n if (!anchor) return null;\n const box = stage.pageRectToScreen(anchor.pon, anchor.bounds);\n if (!box) return null;\n const pos = positionMenuAroundRect(box, placement, gap);\n return (\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: pos.left,\n top: pos.top,\n transform: pos.transform,\n pointerEvents: 'auto',\n }}\n >\n {children({\n ...anchor,\n finish: anno.finishCreationDraft,\n cancel: anno.cancelCreationDraft,\n })}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"annotation-menu.cjs","names":["useProjectorBinding","useSelector","AnnotationHostToken","sameAnchor","Anchored","sameCreationDraftAnchor"],"sources":["../src/annotation-menu.tsx"],"sourcesContent":["/**\n * Annotation menus — thin anchor plumbing over the ONE `<Anchored>` primitive.\n *\n * These work identically under `<Stage>` (mount in the overlay slot; the\n * camera projects, no DOM reads) and `<PageView>` (measured + portalled) —\n * the SURFACE provides the projector, the menu doesn't care.\n *\n * No action bags: actions come from the capability hooks (`useAnnotation()`,\n * `useAnnotationSelected()`, …), which subscribe properly and compose across\n * plugins. Render props carry only the ANCHOR'S DATA (the draft menu's\n * progress facts); the annotation-selection menu takes plain children.\n */\nimport * as React from 'react';\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/internal';\nimport type { CreationDraftAnchor } from '@embedpdf/core-annotation';\nimport { Anchored, useProjectorBinding, type AnchoredPlacement } from './anchored';\nimport { useSelector } from './runtime';\nimport { sameAnchor, sameCreationDraftAnchor } from './annotation';\n\nexport interface AnnotationMenuProps {\n children: React.ReactNode;\n /** Gap in screen px between the selection box and the menu (default 15). */\n gap?: number;\n /** Where to place the menu relative to the selection box. Default 'top'. */\n placement?: AnchoredPlacement;\n}\n\n/**\n * Floats over the current annotation selection (one anchor regardless of\n * cross-page selection), dodging the rotate knob. Compose the contents from\n * hooks: `useAnnotation()` for the verbs, `useAnnotationSelected()` /\n * `useSelectionProps()` for the data.\n */\nexport function AnnotationMenu({ children, gap = 15, placement = 'top' }: AnnotationMenuProps) {\n // Reading the binding subscribes this component to projection changes\n // (its identity IS the revision), so the anchor read below re-runs with\n // fresh view facts in the SAME commit as the surface — the knob offset is\n // screen-constant, so its content-space position depends on the page's\n // live view scale.\n const { projector } = useProjectorBinding();\n const anchor = useSelector(\n AnnotationHostToken,\n (c) => {\n const a = c.selectionAnchor();\n if (!a) return null;\n const env = projector.viewEnv(a.pon);\n return env ? c.selectionAnchor(env.scale, env.rotation, env.zoom) : a;\n },\n sameAnchor,\n );\n if (!anchor) return null;\n return (\n <Anchored\n anchor={{\n pon: anchor.pon,\n bounds: anchor.bounds,\n ...(anchor.knob ? { avoid: [anchor.knob] } : {}),\n }}\n placement={placement}\n gap={gap}\n >\n {children}\n </Anchored>\n );\n}\n\nexport interface AnnotationDraftMenuProps {\n /** Render prop receiving the DRAFT ANCHOR'S DATA (subtype, pointCount,\n * minPoints, canFinish, …). The verbs are capability calls:\n * `useAnnotation().finishCreationDraft()` / `.cancelCreationDraft()`. */\n children: (anchor: CreationDraftAnchor) => React.ReactNode;\n /** Gap in screen px between the draft anchor and the menu (default 8). */\n gap?: number;\n /** Where to place the menu relative to the draft anchor. Default 'top'. */\n placement?: AnchoredPlacement;\n}\n\n/** Floats over a live multi-click creation draft (polygon, polyline, …). */\nexport function AnnotationDraftMenu({\n children,\n gap = 8,\n placement = 'top',\n}: AnnotationDraftMenuProps) {\n const anchor = useSelector(\n AnnotationHostToken,\n (c) => c.creationDraftAnchor(),\n sameCreationDraftAnchor,\n );\n if (!anchor) return null;\n return (\n <Anchored anchor={anchor} placement={placement} gap={gap}>\n {children(anchor)}\n </Anchored>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,SAAgB,eAAe,EAAE,UAAU,MAAM,IAAI,YAAY,SAA8B;CAM7F,MAAM,EAAE,cAAcA,iBAAAA,oBAAoB;CAC1C,MAAM,SAASC,gBAAAA,YACbC,qCAAAA,kBACC,MAAM;EACL,MAAM,IAAI,EAAE,gBAAgB;EAC5B,IAAI,CAAC,GAAG,OAAO;EACf,MAAM,MAAM,UAAU,QAAQ,EAAE,GAAG;EACnC,OAAO,MAAM,EAAE,gBAAgB,IAAI,OAAO,IAAI,UAAU,IAAI,IAAI,IAAI;CACtE,GACAC,mBAAAA,UACF;CACA,IAAI,CAAC,QAAQ,OAAO;CACpB,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,iBAAAA,UAAD;EACE,QAAQ;GACN,KAAK,OAAO;GACZ,QAAQ,OAAO;GACf,GAAI,OAAO,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE,IAAI,CAAC;EAChD;EACW;EACN;EAEJ;CACO,CAAA;AAEd;;AAcA,SAAgB,oBAAoB,EAClC,UACA,MAAM,GACN,YAAY,SACe;CAC3B,MAAM,SAASH,gBAAAA,YACbC,qCAAAA,kBACC,MAAM,EAAE,oBAAoB,GAC7BG,mBAAAA,uBACF;CACA,IAAI,CAAC,QAAQ,OAAO;CACpB,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACD,iBAAAA,UAAD;EAAkB;EAAmB;EAAgB;EAClD,UAAA,SAAS,MAAM;CACR,CAAA;AAEd"}
@@ -1,7 +1,33 @@
1
- import { o as AnnotationMenuProps, t as AnnotationDraftMenuProps } from "./annotation-B6jwfTCh.cjs";
1
+ import { AnchoredPlacement } from "./anchored.cjs";
2
+ import * as React from "react";
3
+ import { CreationDraftAnchor } from "@embedpdf/core-annotation";
2
4
  //#region src/annotation-menu.d.ts
5
+ interface AnnotationMenuProps {
6
+ children: React.ReactNode;
7
+ /** Gap in screen px between the selection box and the menu (default 15). */
8
+ gap?: number;
9
+ /** Where to place the menu relative to the selection box. Default 'top'. */
10
+ placement?: AnchoredPlacement;
11
+ }
12
+ /**
13
+ * Floats over the current annotation selection (one anchor regardless of
14
+ * cross-page selection), dodging the rotate knob. Compose the contents from
15
+ * hooks: `useAnnotation()` for the verbs, `useAnnotationSelected()` /
16
+ * `useSelectionProps()` for the data.
17
+ */
3
18
  declare function AnnotationMenu({ children, gap, placement }: AnnotationMenuProps): import("react/jsx-runtime").JSX.Element | null;
19
+ interface AnnotationDraftMenuProps {
20
+ /** Render prop receiving the DRAFT ANCHOR'S DATA (subtype, pointCount,
21
+ * minPoints, canFinish, …). The verbs are capability calls:
22
+ * `useAnnotation().finishCreationDraft()` / `.cancelCreationDraft()`. */
23
+ children: (anchor: CreationDraftAnchor) => React.ReactNode;
24
+ /** Gap in screen px between the draft anchor and the menu (default 8). */
25
+ gap?: number;
26
+ /** Where to place the menu relative to the draft anchor. Default 'top'. */
27
+ placement?: AnchoredPlacement;
28
+ }
29
+ /** Floats over a live multi-click creation draft (polygon, polyline, …). */
4
30
  declare function AnnotationDraftMenu({ children, gap, placement }: AnnotationDraftMenuProps): import("react/jsx-runtime").JSX.Element | null;
5
31
  //#endregion
6
- export { AnnotationDraftMenu, AnnotationMenu };
32
+ export { AnnotationDraftMenu, AnnotationDraftMenuProps, AnnotationMenu, AnnotationMenuProps };
7
33
  //# sourceMappingURL=annotation-menu.d.cts.map
@@ -1,7 +1,33 @@
1
- import { o as AnnotationMenuProps, t as AnnotationDraftMenuProps } from "./annotation-nUMefyjw.js";
1
+ import { AnchoredPlacement } from "./anchored.js";
2
+ import * as React from "react";
3
+ import { CreationDraftAnchor } from "@embedpdf/core-annotation";
2
4
  //#region src/annotation-menu.d.ts
5
+ interface AnnotationMenuProps {
6
+ children: React.ReactNode;
7
+ /** Gap in screen px between the selection box and the menu (default 15). */
8
+ gap?: number;
9
+ /** Where to place the menu relative to the selection box. Default 'top'. */
10
+ placement?: AnchoredPlacement;
11
+ }
12
+ /**
13
+ * Floats over the current annotation selection (one anchor regardless of
14
+ * cross-page selection), dodging the rotate knob. Compose the contents from
15
+ * hooks: `useAnnotation()` for the verbs, `useAnnotationSelected()` /
16
+ * `useSelectionProps()` for the data.
17
+ */
3
18
  declare function AnnotationMenu({ children, gap, placement }: AnnotationMenuProps): import("react/jsx-runtime").JSX.Element | null;
19
+ interface AnnotationDraftMenuProps {
20
+ /** Render prop receiving the DRAFT ANCHOR'S DATA (subtype, pointCount,
21
+ * minPoints, canFinish, …). The verbs are capability calls:
22
+ * `useAnnotation().finishCreationDraft()` / `.cancelCreationDraft()`. */
23
+ children: (anchor: CreationDraftAnchor) => React.ReactNode;
24
+ /** Gap in screen px between the draft anchor and the menu (default 8). */
25
+ gap?: number;
26
+ /** Where to place the menu relative to the draft anchor. Default 'top'. */
27
+ placement?: AnchoredPlacement;
28
+ }
29
+ /** Floats over a live multi-click creation draft (polygon, polyline, …). */
4
30
  declare function AnnotationDraftMenu({ children, gap, placement }: AnnotationDraftMenuProps): import("react/jsx-runtime").JSX.Element | null;
5
31
  //#endregion
6
- export { AnnotationDraftMenu, AnnotationMenu };
32
+ export { AnnotationDraftMenu, AnnotationDraftMenuProps, AnnotationMenu, AnnotationMenuProps };
7
33
  //# sourceMappingURL=annotation-menu.d.ts.map