@embedpdf/react 3.0.0-next.3 → 3.0.0-next.5
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/{AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.cts → AnnotationListSnapshot-CHjkcIaL-CMHGL8-D.d.cts} +19 -2
- package/dist/{AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.ts → AnnotationListSnapshot-CHjkcIaL-CMHGL8-D.d.ts} +19 -2
- package/dist/anchored.cjs +89 -0
- package/dist/anchored.cjs.map +1 -0
- package/dist/anchored.d.cts +45 -0
- package/dist/anchored.d.ts +45 -0
- package/dist/anchored.js +60 -0
- package/dist/anchored.js.map +1 -0
- package/dist/annotation-menu.cjs +33 -84
- package/dist/annotation-menu.cjs.map +1 -1
- package/dist/annotation-menu.d.cts +28 -2
- package/dist/annotation-menu.d.ts +28 -2
- package/dist/annotation-menu.js +27 -78
- package/dist/annotation-menu.js.map +1 -1
- package/dist/annotation.cjs +689 -16
- package/dist/annotation.cjs.map +1 -0
- package/dist/annotation.d.cts +119 -2
- package/dist/annotation.d.ts +119 -2
- package/dist/annotation.js +678 -3
- package/dist/annotation.js.map +1 -0
- package/dist/form.cjs +1 -1
- package/dist/form.d.cts +2 -2
- package/dist/form.d.ts +2 -2
- package/dist/form.js +1 -1
- package/dist/index.cjs +14 -3
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/interaction.cjs +1 -1
- package/dist/interaction.js +1 -1
- package/dist/page-view.cjs +58 -36
- package/dist/page-view.cjs.map +1 -1
- package/dist/page-view.js +54 -34
- package/dist/page-view.js.map +1 -1
- package/dist/search.cjs +36 -19
- package/dist/search.cjs.map +1 -1
- package/dist/search.d.cts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +36 -19
- package/dist/search.js.map +1 -1
- package/dist/selection.cjs +73 -22
- package/dist/selection.cjs.map +1 -1
- package/dist/selection.d.cts +35 -2
- package/dist/selection.d.ts +35 -2
- package/dist/selection.js +66 -23
- package/dist/selection.js.map +1 -1
- package/dist/stage.cjs +33 -1
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.js +33 -1
- package/dist/stage.js.map +1 -1
- package/package.json +27 -23
- package/dist/annotation-B6jwfTCh.d.cts +0 -173
- package/dist/annotation-Ct6dFtzJ.cjs +0 -913
- package/dist/annotation-Ct6dFtzJ.cjs.map +0 -1
- package/dist/annotation-DjGWJljY.js +0 -829
- package/dist/annotation-DjGWJljY.js.map +0 -1
- package/dist/annotation-nUMefyjw.d.ts +0 -173
|
@@ -669,7 +669,7 @@ declare enum ZodFirstPartyTypeKind {
|
|
|
669
669
|
ZodReadonly = "ZodReadonly"
|
|
670
670
|
}
|
|
671
671
|
//#endregion
|
|
672
|
-
//#region ../../engine/core/dist/AnnotationListSnapshot-
|
|
672
|
+
//#region ../../engine/core/dist/AnnotationListSnapshot-CHjkcIaL.d.ts
|
|
673
673
|
//#endregion
|
|
674
674
|
//#region src/dto/PdfAction.d.ts
|
|
675
675
|
/** Normalized values of an action dictionary's `/S` name. */
|
|
@@ -2256,6 +2256,9 @@ interface CaretDraft extends AnnotationDraftBase, ColorStyleDraftFields {
|
|
|
2256
2256
|
rect: PdfRect;
|
|
2257
2257
|
/** `/RD` inset of the drawn caret from `/Rect`. */
|
|
2258
2258
|
rectDifferences?: PdfRectDifferences | null;
|
|
2259
|
+
/** Tri-state box-rotation pair (see the DTO): omitted/`null` = upright. */
|
|
2260
|
+
rotation?: number | null;
|
|
2261
|
+
unrotatedRect?: PdfRect | null;
|
|
2259
2262
|
}
|
|
2260
2263
|
//#endregion
|
|
2261
2264
|
//#region src/annotation/kinds/caret/dto.d.ts
|
|
@@ -2263,6 +2266,12 @@ interface CaretDraft extends AnnotationDraftBase, ColorStyleDraftFields {
|
|
|
2263
2266
|
* Caret annotation — a visual marker for a proposed text insertion or edit
|
|
2264
2267
|
* point. It carries no geometry of its own beyond `/Rect`: just a `/C` color,
|
|
2265
2268
|
* `/CA` opacity, and an optional `/RD` inset of the drawn symbol from `/Rect`.
|
|
2269
|
+
*
|
|
2270
|
+
* A caret anchored to ROTATED text carries the box-family rotation pair:
|
|
2271
|
+
* `rotation` (`/EMBD_Metadata/Rotation`, PDF-convention degrees) tilts the
|
|
2272
|
+
* baked symbol to ride its text's baseline, `unrotatedRect` is the logical
|
|
2273
|
+
* box, and `/Rect` stays the rotated visual AABB — exactly the shape/free-text
|
|
2274
|
+
* contract, so the generic AP machinery bakes it.
|
|
2266
2275
|
*/
|
|
2267
2276
|
type CaretAnnotationDTO = AnnotationBase & ColorStyleFields & {
|
|
2268
2277
|
subtype: 'caret';
|
|
@@ -2270,6 +2279,10 @@ type CaretAnnotationDTO = AnnotationBase & ColorStyleFields & {
|
|
|
2270
2279
|
intent: CaretIntent | null;
|
|
2271
2280
|
/** `/RD` inset of the drawn caret from `/Rect`; `null` when absent. */
|
|
2272
2281
|
rectDifferences: PdfRectDifferences | null;
|
|
2282
|
+
/** `/EMBD_Metadata/Rotation` — degrees, normalized `[0,360)`. */
|
|
2283
|
+
rotation?: number;
|
|
2284
|
+
/** `/EMBD_Metadata/UnrotatedRect` — the logical box (required when rotation != 0). */
|
|
2285
|
+
unrotatedRect?: PdfRect;
|
|
2273
2286
|
};
|
|
2274
2287
|
//#endregion
|
|
2275
2288
|
//#region src/annotation/kinds/caret/patch.d.ts
|
|
@@ -2279,6 +2292,10 @@ interface CaretPatch extends AnnotationPatchBase, ColorStylePatchFields {
|
|
|
2279
2292
|
rect?: PdfRect;
|
|
2280
2293
|
/** Tri-state: omitted preserves, a value sets, `null` removes `/RD`. */
|
|
2281
2294
|
rectDifferences?: PdfRectDifferences | null;
|
|
2295
|
+
/** Tri-state: omitted preserves, `null`/`0` flattens, a value sets (needs the box). */
|
|
2296
|
+
rotation?: number | null;
|
|
2297
|
+
/** Tri-state: omitted preserves, `null` removes, a value sets. */
|
|
2298
|
+
unrotatedRect?: PdfRect | null;
|
|
2282
2299
|
}
|
|
2283
2300
|
//#endregion
|
|
2284
2301
|
//#region src/annotation/kinds/text/draft.d.ts
|
|
@@ -2590,4 +2607,4 @@ type DTOFromKind<K> = K extends AnnotationKindModule<infer _S, infer D, infer _D
|
|
|
2590
2607
|
type AnnotationDTO = DTOFromKind<AnnotationKind>;
|
|
2591
2608
|
//#endregion
|
|
2592
2609
|
export { FormSnapshot as n, SearchQuery as r, AnnotationDTO as t };
|
|
2593
|
-
//# sourceMappingURL=AnnotationListSnapshot-
|
|
2610
|
+
//# sourceMappingURL=AnnotationListSnapshot-CHjkcIaL-CMHGL8-D.d.cts.map
|
|
@@ -669,7 +669,7 @@ declare enum ZodFirstPartyTypeKind {
|
|
|
669
669
|
ZodReadonly = "ZodReadonly"
|
|
670
670
|
}
|
|
671
671
|
//#endregion
|
|
672
|
-
//#region ../../engine/core/dist/AnnotationListSnapshot-
|
|
672
|
+
//#region ../../engine/core/dist/AnnotationListSnapshot-CHjkcIaL.d.ts
|
|
673
673
|
//#endregion
|
|
674
674
|
//#region src/dto/PdfAction.d.ts
|
|
675
675
|
/** Normalized values of an action dictionary's `/S` name. */
|
|
@@ -2256,6 +2256,9 @@ interface CaretDraft extends AnnotationDraftBase, ColorStyleDraftFields {
|
|
|
2256
2256
|
rect: PdfRect;
|
|
2257
2257
|
/** `/RD` inset of the drawn caret from `/Rect`. */
|
|
2258
2258
|
rectDifferences?: PdfRectDifferences | null;
|
|
2259
|
+
/** Tri-state box-rotation pair (see the DTO): omitted/`null` = upright. */
|
|
2260
|
+
rotation?: number | null;
|
|
2261
|
+
unrotatedRect?: PdfRect | null;
|
|
2259
2262
|
}
|
|
2260
2263
|
//#endregion
|
|
2261
2264
|
//#region src/annotation/kinds/caret/dto.d.ts
|
|
@@ -2263,6 +2266,12 @@ interface CaretDraft extends AnnotationDraftBase, ColorStyleDraftFields {
|
|
|
2263
2266
|
* Caret annotation — a visual marker for a proposed text insertion or edit
|
|
2264
2267
|
* point. It carries no geometry of its own beyond `/Rect`: just a `/C` color,
|
|
2265
2268
|
* `/CA` opacity, and an optional `/RD` inset of the drawn symbol from `/Rect`.
|
|
2269
|
+
*
|
|
2270
|
+
* A caret anchored to ROTATED text carries the box-family rotation pair:
|
|
2271
|
+
* `rotation` (`/EMBD_Metadata/Rotation`, PDF-convention degrees) tilts the
|
|
2272
|
+
* baked symbol to ride its text's baseline, `unrotatedRect` is the logical
|
|
2273
|
+
* box, and `/Rect` stays the rotated visual AABB — exactly the shape/free-text
|
|
2274
|
+
* contract, so the generic AP machinery bakes it.
|
|
2266
2275
|
*/
|
|
2267
2276
|
type CaretAnnotationDTO = AnnotationBase & ColorStyleFields & {
|
|
2268
2277
|
subtype: 'caret';
|
|
@@ -2270,6 +2279,10 @@ type CaretAnnotationDTO = AnnotationBase & ColorStyleFields & {
|
|
|
2270
2279
|
intent: CaretIntent | null;
|
|
2271
2280
|
/** `/RD` inset of the drawn caret from `/Rect`; `null` when absent. */
|
|
2272
2281
|
rectDifferences: PdfRectDifferences | null;
|
|
2282
|
+
/** `/EMBD_Metadata/Rotation` — degrees, normalized `[0,360)`. */
|
|
2283
|
+
rotation?: number;
|
|
2284
|
+
/** `/EMBD_Metadata/UnrotatedRect` — the logical box (required when rotation != 0). */
|
|
2285
|
+
unrotatedRect?: PdfRect;
|
|
2273
2286
|
};
|
|
2274
2287
|
//#endregion
|
|
2275
2288
|
//#region src/annotation/kinds/caret/patch.d.ts
|
|
@@ -2279,6 +2292,10 @@ interface CaretPatch extends AnnotationPatchBase, ColorStylePatchFields {
|
|
|
2279
2292
|
rect?: PdfRect;
|
|
2280
2293
|
/** Tri-state: omitted preserves, a value sets, `null` removes `/RD`. */
|
|
2281
2294
|
rectDifferences?: PdfRectDifferences | null;
|
|
2295
|
+
/** Tri-state: omitted preserves, `null`/`0` flattens, a value sets (needs the box). */
|
|
2296
|
+
rotation?: number | null;
|
|
2297
|
+
/** Tri-state: omitted preserves, `null` removes, a value sets. */
|
|
2298
|
+
unrotatedRect?: PdfRect | null;
|
|
2282
2299
|
}
|
|
2283
2300
|
//#endregion
|
|
2284
2301
|
//#region src/annotation/kinds/text/draft.d.ts
|
|
@@ -2590,4 +2607,4 @@ type DTOFromKind<K> = K extends AnnotationKindModule<infer _S, infer D, infer _D
|
|
|
2590
2607
|
type AnnotationDTO = DTOFromKind<AnnotationKind>;
|
|
2591
2608
|
//#endregion
|
|
2592
2609
|
export { FormSnapshot as n, SearchQuery as r, AnnotationDTO as t };
|
|
2593
|
-
//# sourceMappingURL=AnnotationListSnapshot-
|
|
2610
|
+
//# sourceMappingURL=AnnotationListSnapshot-CHjkcIaL-CMHGL8-D.d.ts.map
|
|
@@ -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
|
package/dist/anchored.js
ADDED
|
@@ -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"}
|
package/dist/annotation-menu.cjs
CHANGED
|
@@ -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
|
|
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
|
-
*
|
|
12
|
+
* Annotation menus — thin anchor plumbing over the ONE `<Anchored>` primitive.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
|
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
|
|
31
|
-
return
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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":["
|
|
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 {
|
|
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
|