@embedpdf/react 3.0.0-next.0

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 (141) hide show
  1. package/LICENSE +192 -0
  2. package/dist/AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.cts +2593 -0
  3. package/dist/AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.ts +2593 -0
  4. package/dist/annotation-B6jwfTCh.d.cts +173 -0
  5. package/dist/annotation-Ct6dFtzJ.cjs +913 -0
  6. package/dist/annotation-Ct6dFtzJ.cjs.map +1 -0
  7. package/dist/annotation-DjGWJljY.js +829 -0
  8. package/dist/annotation-DjGWJljY.js.map +1 -0
  9. package/dist/annotation-menu.cjs +115 -0
  10. package/dist/annotation-menu.cjs.map +1 -0
  11. package/dist/annotation-menu.d.cts +7 -0
  12. package/dist/annotation-menu.d.ts +7 -0
  13. package/dist/annotation-menu.js +99 -0
  14. package/dist/annotation-menu.js.map +1 -0
  15. package/dist/annotation-nUMefyjw.d.ts +173 -0
  16. package/dist/annotation.cjs +25 -0
  17. package/dist/annotation.d.cts +3 -0
  18. package/dist/annotation.d.ts +3 -0
  19. package/dist/annotation.js +4 -0
  20. package/dist/commands.cjs +59 -0
  21. package/dist/commands.cjs.map +1 -0
  22. package/dist/commands.d.cts +20 -0
  23. package/dist/commands.d.ts +20 -0
  24. package/dist/commands.js +47 -0
  25. package/dist/commands.js.map +1 -0
  26. package/dist/form.cjs +560 -0
  27. package/dist/form.cjs.map +1 -0
  28. package/dist/form.d.cts +52 -0
  29. package/dist/form.d.ts +52 -0
  30. package/dist/form.js +545 -0
  31. package/dist/form.js.map +1 -0
  32. package/dist/i18n.cjs +52 -0
  33. package/dist/i18n.cjs.map +1 -0
  34. package/dist/i18n.d.cts +30 -0
  35. package/dist/i18n.d.ts +30 -0
  36. package/dist/i18n.js +42 -0
  37. package/dist/i18n.js.map +1 -0
  38. package/dist/index.cjs +240 -0
  39. package/dist/index.d.cts +37 -0
  40. package/dist/index.d.ts +37 -0
  41. package/dist/index.js +37 -0
  42. package/dist/interaction.cjs +152 -0
  43. package/dist/interaction.cjs.map +1 -0
  44. package/dist/interaction.d.cts +46 -0
  45. package/dist/interaction.d.ts +46 -0
  46. package/dist/interaction.js +139 -0
  47. package/dist/interaction.js.map +1 -0
  48. package/dist/link.cjs +108 -0
  49. package/dist/link.cjs.map +1 -0
  50. package/dist/link.d.cts +16 -0
  51. package/dist/link.d.ts +16 -0
  52. package/dist/link.js +98 -0
  53. package/dist/link.js.map +1 -0
  54. package/dist/metadata.cjs +25 -0
  55. package/dist/metadata.cjs.map +1 -0
  56. package/dist/metadata.d.cts +11 -0
  57. package/dist/metadata.d.ts +11 -0
  58. package/dist/metadata.js +16 -0
  59. package/dist/metadata.js.map +1 -0
  60. package/dist/page-edit.cjs +20 -0
  61. package/dist/page-edit.cjs.map +1 -0
  62. package/dist/page-edit.d.cts +7 -0
  63. package/dist/page-edit.d.ts +7 -0
  64. package/dist/page-edit.js +11 -0
  65. package/dist/page-edit.js.map +1 -0
  66. package/dist/page-view.cjs +107 -0
  67. package/dist/page-view.cjs.map +1 -0
  68. package/dist/page-view.d.cts +23 -0
  69. package/dist/page-view.d.ts +23 -0
  70. package/dist/page-view.js +95 -0
  71. package/dist/page-view.js.map +1 -0
  72. package/dist/redaction.cjs +35 -0
  73. package/dist/redaction.cjs.map +1 -0
  74. package/dist/redaction.d.cts +14 -0
  75. package/dist/redaction.d.ts +14 -0
  76. package/dist/redaction.js +25 -0
  77. package/dist/redaction.js.map +1 -0
  78. package/dist/render.cjs +142 -0
  79. package/dist/render.cjs.map +1 -0
  80. package/dist/render.d.cts +32 -0
  81. package/dist/render.d.ts +32 -0
  82. package/dist/render.js +131 -0
  83. package/dist/render.js.map +1 -0
  84. package/dist/rolldown-runtime-DDXJien1.cjs +50 -0
  85. package/dist/runtime-CMxIuF2O.d.cts +195 -0
  86. package/dist/runtime-DV98q7I0.d.ts +195 -0
  87. package/dist/runtime.cjs +314 -0
  88. package/dist/runtime.cjs.map +1 -0
  89. package/dist/runtime.d.cts +3 -0
  90. package/dist/runtime.d.ts +3 -0
  91. package/dist/runtime.js +287 -0
  92. package/dist/runtime.js.map +1 -0
  93. package/dist/scrollbar.cjs +241 -0
  94. package/dist/scrollbar.cjs.map +1 -0
  95. package/dist/scrollbar.d.cts +42 -0
  96. package/dist/scrollbar.d.ts +42 -0
  97. package/dist/scrollbar.js +213 -0
  98. package/dist/scrollbar.js.map +1 -0
  99. package/dist/search.cjs +70 -0
  100. package/dist/search.cjs.map +1 -0
  101. package/dist/search.d.cts +35 -0
  102. package/dist/search.d.ts +35 -0
  103. package/dist/search.js +58 -0
  104. package/dist/search.js.map +1 -0
  105. package/dist/selection.cjs +60 -0
  106. package/dist/selection.cjs.map +1 -0
  107. package/dist/selection.d.cts +12 -0
  108. package/dist/selection.d.ts +12 -0
  109. package/dist/selection.js +49 -0
  110. package/dist/selection.js.map +1 -0
  111. package/dist/shell.cjs +57 -0
  112. package/dist/shell.cjs.map +1 -0
  113. package/dist/shell.d.cts +27 -0
  114. package/dist/shell.d.ts +27 -0
  115. package/dist/shell.js +46 -0
  116. package/dist/shell.js.map +1 -0
  117. package/dist/stage.cjs +343 -0
  118. package/dist/stage.cjs.map +1 -0
  119. package/dist/stage.d.cts +104 -0
  120. package/dist/stage.d.ts +104 -0
  121. package/dist/stage.js +327 -0
  122. package/dist/stage.js.map +1 -0
  123. package/dist/stamp.cjs +76 -0
  124. package/dist/stamp.cjs.map +1 -0
  125. package/dist/stamp.d.cts +28 -0
  126. package/dist/stamp.d.ts +28 -0
  127. package/dist/stamp.js +63 -0
  128. package/dist/stamp.js.map +1 -0
  129. package/dist/toolbar.cjs +515 -0
  130. package/dist/toolbar.cjs.map +1 -0
  131. package/dist/toolbar.d.cts +100 -0
  132. package/dist/toolbar.d.ts +100 -0
  133. package/dist/toolbar.js +505 -0
  134. package/dist/toolbar.js.map +1 -0
  135. package/dist/views.cjs +35 -0
  136. package/dist/views.cjs.map +1 -0
  137. package/dist/views.d.cts +21 -0
  138. package/dist/views.d.ts +21 -0
  139. package/dist/views.js +26 -0
  140. package/dist/views.js.map +1 -0
  141. package/package.json +158 -0
@@ -0,0 +1,104 @@
1
+ import { o as PageContextValue } from "./runtime-CMxIuF2O.cjs";
2
+ import * as React from "react";
3
+ import { CapabilityToken } from "@embedpdf/core";
4
+ import { StageCapability } from "@embedpdf/plugin-stage";
5
+ export * from "@embedpdf/plugin-stage";
6
+ //#region src/stage.d.ts
7
+ /** Which stage lens to bind to. Defaults to the main StageToken — pass a custom
8
+ * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */
9
+ type StageTokenProp = CapabilityToken<StageCapability>;
10
+ interface StageProps {
11
+ /**
12
+ * PAGE-SPACE content for each visible page (RenderLayer, annotations,
13
+ * markers). Rendered inside the page's content frame, so it ROTATES with the
14
+ * page's display rotation — coordinates are plain PDF points.
15
+ */
16
+ children: (page: PageContextValue) => React.ReactNode;
17
+ /**
18
+ * BOX-SPACE chrome for each visible page (page-number label, selection
19
+ * border, a per-page rotate/delete button). Rendered into the OUTER box
20
+ * (content + reserved `pageFrame`), so it does NOT rotate and the reserved
21
+ * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three
22
+ * coordinate spaces: `children` (page content), `pageChrome` (page box +
23
+ * frame), `overlay` (viewport).
24
+ */
25
+ pageChrome?: (page: PageContextValue) => React.ReactNode;
26
+ /** Viewport-space UI (menus, controls) rendered above the pages. */
27
+ overlay?: React.ReactNode;
28
+ /**
29
+ * Route this Stage's pointer events to the interaction hub (page-resolved via
30
+ * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`
31
+ * tool's job and dragging in `pointer` mode selects text (incl. across pages).
32
+ * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).
33
+ */
34
+ interaction?: boolean;
35
+ /**
36
+ * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch
37
+ * (Safari gesture events included). Default true. Turn OFF for follower
38
+ * lenses with a fixed magnification — a thumbnail rail should scroll under
39
+ * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel
40
+ * pan, and pinches are still swallowed (they never page-zoom the browser).
41
+ */
42
+ zoomGestures?: boolean;
43
+ /** The stage lens to drive (default: the main StageToken). */
44
+ token?: StageTokenProp;
45
+ className?: string;
46
+ style?: React.CSSProperties;
47
+ }
48
+ declare function Stage({ children, pageChrome, overlay, interaction, zoomGestures, token, className, style }: StageProps): import("react/jsx-runtime").JSX.Element;
49
+ declare function useStage(token?: StageTokenProp): StageCapability;
50
+ declare function useZoom(token?: StageTokenProp): {
51
+ zoom: number;
52
+ /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */
53
+ mode: import("@embedpdf/core-stage").ZoomModeValue | "custom";
54
+ zoomIn: () => void;
55
+ zoomOut: () => void;
56
+ fitWidth: () => void;
57
+ fitPage: () => void;
58
+ fitAll: () => void;
59
+ automatic: () => void;
60
+ zoomTo: (spec: import("@embedpdf/core-stage").ZoomSpec) => void;
61
+ };
62
+ declare function usePages(token?: StageTokenProp): {
63
+ currentPage: number;
64
+ pageCount: number;
65
+ goToPage: (pageIndex: number, opts?: import("@embedpdf/plugin-stage").GoToOptions) => void;
66
+ next: (opts?: import("@embedpdf/plugin-stage").GoToOptions) => void;
67
+ prev: (opts?: import("@embedpdf/plugin-stage").GoToOptions) => void;
68
+ reveal: (pageIndex: number, opts?: import("@embedpdf/plugin-stage").RevealOptions) => void;
69
+ };
70
+ declare function useLayout(token?: StageTokenProp): {
71
+ flow: import("@embedpdf/plugin-stage").FlowMode;
72
+ layout: import("@embedpdf/plugin-stage").LayoutKind;
73
+ spread: import("@embedpdf/core-stage").SpreadMode;
74
+ sizing: import("@embedpdf/core-stage").SizingMode;
75
+ bounded: boolean;
76
+ setFlow: (flow: import("@embedpdf/plugin-stage").FlowMode) => void;
77
+ setLayout: (layout: import("@embedpdf/plugin-stage").LayoutKind) => void;
78
+ setSpread: (spread: import("@embedpdf/core-stage").SpreadMode) => void;
79
+ setSizing: (sizing: import("@embedpdf/core-stage").SizingMode) => void;
80
+ setBounded: (bounded: boolean) => void;
81
+ };
82
+ /** The document's page list (with PDF labels) + the current item's pages — the
83
+ * data for page thumbnails / worksheet-style page tabs. */
84
+ declare function usePageList(token?: StageTokenProp): {
85
+ pages: {
86
+ index: number;
87
+ pon: import("@embedpdf/core").PageObjectNumber;
88
+ label: string | null;
89
+ }[];
90
+ currentItemPages: number[];
91
+ };
92
+ /**
93
+ * All Stage settings + the batch `update`. This is the seam for "presets are a
94
+ * customer concern": keep your own `Partial<StageSettings>` objects and apply them
95
+ * with `update(preset)` (one anchor-preserving change).
96
+ */
97
+ declare function useStageSettings(token?: StageTokenProp): {
98
+ settings: import("@embedpdf/plugin-stage").StageSettings;
99
+ update: (patch: Partial<import("@embedpdf/plugin-stage").StageSettings>) => void;
100
+ reset: () => void;
101
+ };
102
+ //#endregion
103
+ export { Stage, StageProps, StageTokenProp, useLayout, usePageList, usePages, useStage, useStageSettings, useZoom };
104
+ //# sourceMappingURL=stage.d.cts.map
@@ -0,0 +1,104 @@
1
+ import { o as PageContextValue } from "./runtime-DV98q7I0.js";
2
+ import { CapabilityToken } from "@embedpdf/core";
3
+ import * as React from "react";
4
+ import { StageCapability } from "@embedpdf/plugin-stage";
5
+ export * from "@embedpdf/plugin-stage";
6
+ //#region src/stage.d.ts
7
+ /** Which stage lens to bind to. Defaults to the main StageToken — pass a custom
8
+ * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */
9
+ type StageTokenProp = CapabilityToken<StageCapability>;
10
+ interface StageProps {
11
+ /**
12
+ * PAGE-SPACE content for each visible page (RenderLayer, annotations,
13
+ * markers). Rendered inside the page's content frame, so it ROTATES with the
14
+ * page's display rotation — coordinates are plain PDF points.
15
+ */
16
+ children: (page: PageContextValue) => React.ReactNode;
17
+ /**
18
+ * BOX-SPACE chrome for each visible page (page-number label, selection
19
+ * border, a per-page rotate/delete button). Rendered into the OUTER box
20
+ * (content + reserved `pageFrame`), so it does NOT rotate and the reserved
21
+ * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three
22
+ * coordinate spaces: `children` (page content), `pageChrome` (page box +
23
+ * frame), `overlay` (viewport).
24
+ */
25
+ pageChrome?: (page: PageContextValue) => React.ReactNode;
26
+ /** Viewport-space UI (menus, controls) rendered above the pages. */
27
+ overlay?: React.ReactNode;
28
+ /**
29
+ * Route this Stage's pointer events to the interaction hub (page-resolved via
30
+ * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`
31
+ * tool's job and dragging in `pointer` mode selects text (incl. across pages).
32
+ * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).
33
+ */
34
+ interaction?: boolean;
35
+ /**
36
+ * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch
37
+ * (Safari gesture events included). Default true. Turn OFF for follower
38
+ * lenses with a fixed magnification — a thumbnail rail should scroll under
39
+ * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel
40
+ * pan, and pinches are still swallowed (they never page-zoom the browser).
41
+ */
42
+ zoomGestures?: boolean;
43
+ /** The stage lens to drive (default: the main StageToken). */
44
+ token?: StageTokenProp;
45
+ className?: string;
46
+ style?: React.CSSProperties;
47
+ }
48
+ declare function Stage({ children, pageChrome, overlay, interaction, zoomGestures, token, className, style }: StageProps): import("react/jsx-runtime").JSX.Element;
49
+ declare function useStage(token?: StageTokenProp): StageCapability;
50
+ declare function useZoom(token?: StageTokenProp): {
51
+ zoom: number;
52
+ /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */
53
+ mode: import("@embedpdf/core-stage").ZoomModeValue | "custom";
54
+ zoomIn: () => void;
55
+ zoomOut: () => void;
56
+ fitWidth: () => void;
57
+ fitPage: () => void;
58
+ fitAll: () => void;
59
+ automatic: () => void;
60
+ zoomTo: (spec: import("@embedpdf/core-stage").ZoomSpec) => void;
61
+ };
62
+ declare function usePages(token?: StageTokenProp): {
63
+ currentPage: number;
64
+ pageCount: number;
65
+ goToPage: (pageIndex: number, opts?: import("@embedpdf/plugin-stage").GoToOptions) => void;
66
+ next: (opts?: import("@embedpdf/plugin-stage").GoToOptions) => void;
67
+ prev: (opts?: import("@embedpdf/plugin-stage").GoToOptions) => void;
68
+ reveal: (pageIndex: number, opts?: import("@embedpdf/plugin-stage").RevealOptions) => void;
69
+ };
70
+ declare function useLayout(token?: StageTokenProp): {
71
+ flow: import("@embedpdf/plugin-stage").FlowMode;
72
+ layout: import("@embedpdf/plugin-stage").LayoutKind;
73
+ spread: import("@embedpdf/core-stage").SpreadMode;
74
+ sizing: import("@embedpdf/core-stage").SizingMode;
75
+ bounded: boolean;
76
+ setFlow: (flow: import("@embedpdf/plugin-stage").FlowMode) => void;
77
+ setLayout: (layout: import("@embedpdf/plugin-stage").LayoutKind) => void;
78
+ setSpread: (spread: import("@embedpdf/core-stage").SpreadMode) => void;
79
+ setSizing: (sizing: import("@embedpdf/core-stage").SizingMode) => void;
80
+ setBounded: (bounded: boolean) => void;
81
+ };
82
+ /** The document's page list (with PDF labels) + the current item's pages — the
83
+ * data for page thumbnails / worksheet-style page tabs. */
84
+ declare function usePageList(token?: StageTokenProp): {
85
+ pages: {
86
+ index: number;
87
+ pon: import("@embedpdf/core").PageObjectNumber;
88
+ label: string | null;
89
+ }[];
90
+ currentItemPages: number[];
91
+ };
92
+ /**
93
+ * All Stage settings + the batch `update`. This is the seam for "presets are a
94
+ * customer concern": keep your own `Partial<StageSettings>` objects and apply them
95
+ * with `update(preset)` (one anchor-preserving change).
96
+ */
97
+ declare function useStageSettings(token?: StageTokenProp): {
98
+ settings: import("@embedpdf/plugin-stage").StageSettings;
99
+ update: (patch: Partial<import("@embedpdf/plugin-stage").StageSettings>) => void;
100
+ reset: () => void;
101
+ };
102
+ //#endregion
103
+ export { Stage, StageProps, StageTokenProp, useLayout, usePageList, usePages, useStage, useStageSettings, useZoom };
104
+ //# sourceMappingURL=stage.d.ts.map
package/dist/stage.js ADDED
@@ -0,0 +1,327 @@
1
+ import { PageProvider, makePageContext, useCapability, useDocumentId, useKernelValue, useOptionalCapability, useSelector } from "./runtime.js";
2
+ import { createClickCounter } from "./interaction.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useEffect, useMemo, useRef } from "react";
5
+ import { StageToken, settingsEqual, wheelZoomFactor } from "@embedpdf/plugin-stage";
6
+ import { InteractionToken } from "@embedpdf/plugin-interaction";
7
+ export * from "@embedpdf/plugin-stage";
8
+ //#region src/stage.tsx
9
+ function PageSurface({ documentId, page, frame, stage, render, chrome }) {
10
+ const ref = useRef(null);
11
+ const t = page.transform;
12
+ const rotation = page.rotation;
13
+ const outerW = t.viewWidth + frame.left + frame.right;
14
+ const outerH = t.viewHeight + frame.top + frame.bottom;
15
+ const left = page.screenX - frame.left;
16
+ const top = page.screenY - frame.top;
17
+ const contentLeft = frame.left + (t.viewWidth - t.contentWidth) / 2;
18
+ const contentTop = frame.top + (t.viewHeight - t.contentHeight) / 2;
19
+ const ctx = useMemo(() => makePageContext(documentId, page.pon, page.pageIndex, frame, t, () => ref.current.getBoundingClientRect(), () => {
20
+ const live = stage.visiblePages().find((p) => p.pon === page.pon);
21
+ return live ? {
22
+ desiredDeviceWidth: live.transform.deviceWidth,
23
+ visibleRect: live.visibleRect
24
+ } : {
25
+ desiredDeviceWidth: t.deviceWidth,
26
+ visibleRect: {
27
+ x: 0,
28
+ y: 0,
29
+ width: 0,
30
+ height: 0
31
+ }
32
+ };
33
+ }), [
34
+ documentId,
35
+ page.pon,
36
+ page.pageIndex,
37
+ frame,
38
+ t,
39
+ stage
40
+ ]);
41
+ return /* @__PURE__ */ jsx("div", {
42
+ style: {
43
+ position: "absolute",
44
+ left,
45
+ top,
46
+ width: outerW,
47
+ height: outerH
48
+ },
49
+ children: /* @__PURE__ */ jsxs(PageProvider, {
50
+ value: ctx,
51
+ children: [
52
+ /* @__PURE__ */ jsx("div", { style: {
53
+ position: "absolute",
54
+ left: frame.left,
55
+ top: frame.top,
56
+ width: t.viewWidth,
57
+ height: t.viewHeight,
58
+ boxShadow: "0 6px 18px rgba(0,0,0,.18)"
59
+ } }),
60
+ /* @__PURE__ */ jsx("div", {
61
+ ref,
62
+ style: {
63
+ position: "absolute",
64
+ left: contentLeft,
65
+ top: contentTop,
66
+ width: t.contentWidth,
67
+ height: t.contentHeight,
68
+ background: "#fff",
69
+ transform: rotation ? `rotate(${rotation}deg)` : void 0,
70
+ userSelect: "none",
71
+ WebkitUserSelect: "none"
72
+ },
73
+ children: render(ctx)
74
+ }),
75
+ chrome?.(ctx)
76
+ ]
77
+ })
78
+ });
79
+ }
80
+ function Stage({ children, pageChrome, overlay, interaction = false, zoomGestures = true, token = StageToken, className, style }) {
81
+ const stage = useCapability(token);
82
+ const ix = useOptionalCapability(InteractionToken);
83
+ const useHub = interaction && !!ix;
84
+ const hubCursor = useKernelValue(() => ix?.cursor() ?? "default");
85
+ const ref = useRef(null);
86
+ const docId = useDocumentId();
87
+ const pages = useSelector(token, (c) => c.visiblePages());
88
+ const frame = useSelector(token, (c) => c.pageFrame(), (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left);
89
+ useEffect(() => {
90
+ const el = ref.current;
91
+ const setVp = () => stage.setViewport({
92
+ width: el.clientWidth,
93
+ height: el.clientHeight
94
+ });
95
+ const ro = new ResizeObserver(setVp);
96
+ ro.observe(el);
97
+ setVp();
98
+ let mq = null;
99
+ const reportDpr = () => {
100
+ stage.setDevicePixelRatio(window.devicePixelRatio || 1);
101
+ mq?.removeEventListener("change", reportDpr);
102
+ mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
103
+ mq.addEventListener("change", reportDpr);
104
+ };
105
+ reportDpr();
106
+ const onWheel = (e) => {
107
+ e.preventDefault();
108
+ const r = el.getBoundingClientRect();
109
+ if (zoomGestures && (e.ctrlKey || e.metaKey)) stage.zoomAround({
110
+ x: e.clientX - r.left,
111
+ y: e.clientY - r.top
112
+ }, wheelZoomFactor(e));
113
+ else {
114
+ const dx = e.shiftKey ? e.deltaY : e.deltaX;
115
+ const dy = e.shiftKey ? e.deltaX : e.deltaY;
116
+ stage.panBy(-dx, -dy);
117
+ }
118
+ };
119
+ el.addEventListener("wheel", onWheel, { passive: false });
120
+ let lastScale = 1;
121
+ const onGestureStart = (e) => {
122
+ e.preventDefault();
123
+ lastScale = e.scale ?? 1;
124
+ };
125
+ const onGestureChange = (e) => {
126
+ e.preventDefault();
127
+ const g = e;
128
+ const scale = g.scale ?? 1;
129
+ if (zoomGestures && scale > 0) {
130
+ const r = el.getBoundingClientRect();
131
+ stage.zoomAround({
132
+ x: g.clientX - r.left,
133
+ y: g.clientY - r.top
134
+ }, scale / lastScale);
135
+ }
136
+ lastScale = scale;
137
+ };
138
+ const hasGestureEvents = "GestureEvent" in window;
139
+ if (hasGestureEvents) {
140
+ el.addEventListener("gesturestart", onGestureStart);
141
+ el.addEventListener("gesturechange", onGestureChange);
142
+ el.addEventListener("gestureend", onGestureStart);
143
+ }
144
+ const cleanups = [];
145
+ if (useHub && ix) {
146
+ const clicks = createClickCounter();
147
+ const forward = (phase, e, clickCount = 1) => {
148
+ const r = el.getBoundingClientRect();
149
+ const vpt = {
150
+ x: e.clientX - r.left,
151
+ y: e.clientY - r.top
152
+ };
153
+ ix.dispatch({
154
+ phase,
155
+ viewport: vpt,
156
+ page: stage.pageAt(vpt) ?? void 0,
157
+ project: (pon) => stage.pointOnPage(pon, vpt),
158
+ modifiers: {
159
+ shift: e.shiftKey,
160
+ alt: e.altKey,
161
+ ctrl: e.ctrlKey,
162
+ meta: e.metaKey
163
+ },
164
+ clickCount
165
+ });
166
+ };
167
+ let dragging = false;
168
+ const down = (e) => {
169
+ if (e.button !== 0) return;
170
+ dragging = true;
171
+ forward("down", e, clicks(Date.now(), e.clientX, e.clientY));
172
+ };
173
+ const hover = (e) => {
174
+ if (!dragging) forward("move", e);
175
+ };
176
+ const winMove = (e) => {
177
+ if (dragging) forward("move", e);
178
+ };
179
+ const up = (e) => {
180
+ if (!dragging) return;
181
+ dragging = false;
182
+ forward("up", e);
183
+ };
184
+ el.addEventListener("pointerdown", down);
185
+ el.addEventListener("pointermove", hover);
186
+ window.addEventListener("pointermove", winMove);
187
+ window.addEventListener("pointerup", up);
188
+ cleanups.push(() => {
189
+ el.removeEventListener("pointerdown", down);
190
+ el.removeEventListener("pointermove", hover);
191
+ window.removeEventListener("pointermove", winMove);
192
+ window.removeEventListener("pointerup", up);
193
+ });
194
+ } else {
195
+ let dragging = false;
196
+ let lx = 0;
197
+ let ly = 0;
198
+ const down = (e) => {
199
+ if (e.button !== 0) return;
200
+ dragging = true;
201
+ lx = e.clientX;
202
+ ly = e.clientY;
203
+ };
204
+ const move = (e) => {
205
+ if (!dragging) return;
206
+ stage.panBy(e.clientX - lx, e.clientY - ly);
207
+ lx = e.clientX;
208
+ ly = e.clientY;
209
+ };
210
+ const up = () => {
211
+ dragging = false;
212
+ };
213
+ el.addEventListener("pointerdown", down);
214
+ window.addEventListener("pointermove", move);
215
+ window.addEventListener("pointerup", up);
216
+ cleanups.push(() => {
217
+ el.removeEventListener("pointerdown", down);
218
+ window.removeEventListener("pointermove", move);
219
+ window.removeEventListener("pointerup", up);
220
+ });
221
+ }
222
+ return () => {
223
+ ro.disconnect();
224
+ mq?.removeEventListener("change", reportDpr);
225
+ el.removeEventListener("wheel", onWheel);
226
+ if (hasGestureEvents) {
227
+ el.removeEventListener("gesturestart", onGestureStart);
228
+ el.removeEventListener("gesturechange", onGestureChange);
229
+ el.removeEventListener("gestureend", onGestureStart);
230
+ }
231
+ cleanups.forEach((fn) => fn());
232
+ };
233
+ }, [
234
+ stage,
235
+ ix,
236
+ useHub,
237
+ zoomGestures
238
+ ]);
239
+ return /* @__PURE__ */ jsxs("div", {
240
+ ref,
241
+ className,
242
+ style: {
243
+ position: "relative",
244
+ overflow: "hidden",
245
+ touchAction: "none",
246
+ ...useHub ? { cursor: hubCursor } : null,
247
+ ...style
248
+ },
249
+ children: [pages.map((p) => /* @__PURE__ */ jsx(PageSurface, {
250
+ documentId: docId ?? "",
251
+ page: p,
252
+ frame,
253
+ stage,
254
+ render: children,
255
+ chrome: pageChrome
256
+ }, p.pageIndex)), overlay]
257
+ });
258
+ }
259
+ function useStage(token = StageToken) {
260
+ return useCapability(token);
261
+ }
262
+ function useZoom(token = StageToken) {
263
+ const s = useCapability(token);
264
+ return {
265
+ zoom: useSelector(token, (c) => c.zoomLevel()),
266
+ /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */
267
+ mode: useSelector(token, (c) => c.zoomMode()),
268
+ zoomIn: s.zoomIn,
269
+ zoomOut: s.zoomOut,
270
+ fitWidth: s.fitWidth,
271
+ fitPage: s.fitPage,
272
+ fitAll: s.fitAll,
273
+ automatic: s.automatic,
274
+ zoomTo: s.zoomTo
275
+ };
276
+ }
277
+ function usePages(token = StageToken) {
278
+ const s = useCapability(token);
279
+ return {
280
+ currentPage: useSelector(token, (c) => c.currentPage()),
281
+ pageCount: useSelector(token, (c) => c.pageCount()),
282
+ goToPage: s.goToPage,
283
+ next: s.next,
284
+ prev: s.prev,
285
+ reveal: s.reveal
286
+ };
287
+ }
288
+ function useLayout(token = StageToken) {
289
+ const s = useCapability(token);
290
+ return {
291
+ flow: useSelector(token, (c) => c.flow()),
292
+ layout: useSelector(token, (c) => c.layout()),
293
+ spread: useSelector(token, (c) => c.spread()),
294
+ sizing: useSelector(token, (c) => c.sizing()),
295
+ bounded: useSelector(token, (c) => c.bounded()),
296
+ setFlow: s.setFlow,
297
+ setLayout: s.setLayout,
298
+ setSpread: s.setSpread,
299
+ setSizing: s.setSizing,
300
+ setBounded: s.setBounded
301
+ };
302
+ }
303
+ /** The document's page list (with PDF labels) + the current item's pages — the
304
+ * data for page thumbnails / worksheet-style page tabs. */
305
+ function usePageList(token = StageToken) {
306
+ return {
307
+ pages: useSelector(token, (c) => c.pages(), (a, b) => a.length === b.length && a.every((p, i) => p.pon === b[i].pon && p.label === b[i].label)),
308
+ currentItemPages: useSelector(token, (c) => c.currentItemPages(), (a, b) => a.length === b.length && a.every((x, i) => x === b[i]))
309
+ };
310
+ }
311
+ /**
312
+ * All Stage settings + the batch `update`. This is the seam for "presets are a
313
+ * customer concern": keep your own `Partial<StageSettings>` objects and apply them
314
+ * with `update(preset)` (one anchor-preserving change).
315
+ */
316
+ function useStageSettings(token = StageToken) {
317
+ const s = useCapability(token);
318
+ return {
319
+ settings: useSelector(token, (c) => c.settings(), settingsEqual),
320
+ update: s.update,
321
+ reset: s.resetView
322
+ };
323
+ }
324
+ //#endregion
325
+ export { Stage, useLayout, usePageList, usePages, useStage, useStageSettings, useZoom };
326
+
327
+ //# sourceMappingURL=stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage.js","names":[],"sources":["../src/stage.tsx"],"sourcesContent":["/**\n * Stage / RenderLayer + facade hooks.\n *\n * <Stage> virtualizes and positions page surfaces by the camera, and hands each\n * one to YOUR render prop — you bring the layers. (The standalone, Stage-free\n * single-page surface lives in `./page-view` so it never pulls the stage plugin.)\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-stage';\nimport * as React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { StageToken, settingsEqual, wheelZoomFactor } from '@embedpdf/plugin-stage';\nimport type { StageCapability, VisiblePage } from '@embedpdf/plugin-stage';\nimport type { CapabilityToken } from '@embedpdf/core';\n\n/** Which stage lens to bind to. Defaults to the main StageToken — pass a custom\n * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */\nexport type StageTokenProp = CapabilityToken<StageCapability>;\nimport type { PageFrame } from '@embedpdf/core-geometry';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport type { PointerSample } from '@embedpdf/plugin-interaction';\nimport { createClickCounter } from './interaction';\nimport {\n makePageContext,\n PageProvider,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n useSelector,\n} from './runtime';\nimport type { PageContextValue } from './runtime';\n\nfunction PageSurface({\n documentId,\n page,\n frame,\n stage,\n render,\n chrome,\n}: {\n documentId: string;\n page: VisiblePage;\n /** Reserved chrome bands around the page (screen px); the layout reserved the\n * matching space, so the outer box tiles into it. */\n frame: PageFrame;\n /** The stage capability — the demand getter reads visibility LIVE off it. */\n stage: StageCapability;\n render: (page: PageContextValue) => React.ReactNode;\n chrome?: (page: PageContextValue) => React.ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const t = page.transform;\n const rotation = page.rotation;\n // All geometry comes from the transform: the DISPLAY footprint (viewWidth/Height,\n // already w↔h-swapped + device-snapped) and the UN-rotated content box\n // (contentWidth/Height). The shell never re-derives `* zoom` / `* dpr` / snapping.\n const outerW = t.viewWidth + frame.left + frame.right;\n const outerH = t.viewHeight + frame.top + frame.bottom;\n // page.screenX/screenY are the device-snapped footprint top-left; the outer box\n // sits one frame further out so the content keeps its scene position.\n const left = page.screenX - frame.left;\n const top = page.screenY - frame.top;\n // Center the (possibly rotated) content box on the display box and rotate about\n // its center — NO translate(), so rotation 0 carries no transform and pixel-snaps\n // like the axis-aligned shadow behind it (no hairline seam).\n const contentLeft = frame.left + (t.viewWidth - t.contentWidth) / 2;\n const contentTop = frame.top + (t.viewHeight - t.contentHeight) / 2;\n // The page-view DEMAND is a PULL: the getter closes over\n // stable references (capability + pon) and reads the stage's live state at\n // call time — visibility is the STAGE's data (`VisiblePage.visibleRect`),\n // not something an adapter re-derives or caches. Absent from the visible\n // set = zero rect (\"want nothing\"), distinct from PageView's undefined\n // getter (\"whole page\").\n const ctx = useMemo(\n () =>\n makePageContext(\n documentId,\n page.pon,\n page.pageIndex,\n frame,\n t,\n () => ref.current!.getBoundingClientRect(),\n () => {\n const live = stage.visiblePages().find((p) => p.pon === page.pon);\n return live\n ? { desiredDeviceWidth: live.transform.deviceWidth, visibleRect: live.visibleRect }\n : {\n desiredDeviceWidth: t.deviceWidth,\n visibleRect: { x: 0, y: 0, width: 0, height: 0 },\n };\n },\n ),\n [documentId, page.pon, page.pageIndex, frame, t, stage],\n );\n return (\n <div style={{ position: 'absolute', left, top, width: outerW, height: outerH }}>\n <PageProvider value={ctx}>\n {/* drop shadow ONLY — axis-aligned at the content box (inset by the frame),\n transparent fill so it can never peek out behind the bitmap, and it\n stays put under rotation. */}\n <div\n style={{\n position: 'absolute',\n left: frame.left,\n top: frame.top,\n width: t.viewWidth,\n height: t.viewHeight,\n boxShadow: '0 6px 18px rgba(0,0,0,.18)',\n }}\n />\n {/* the page: white backing + bitmap as ONE rasterized box, so there is no\n seam between them and nothing white larger than the bitmap to leak.\n The ONLY thing rotation turns; markers/annotations ride it in content\n coordinates. Rotation 0 carries no transform → pixel-snaps cleanly. */}\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: contentLeft,\n top: contentTop,\n width: t.contentWidth,\n height: t.contentHeight,\n background: '#fff',\n transform: rotation ? `rotate(${rotation}deg)` : undefined,\n // We render our own selection highlights — suppress native text/image\n // selection (and the double-click image grab) on the whole page subtree.\n userSelect: 'none',\n WebkitUserSelect: 'none',\n }}\n >\n {render(ctx)}\n </div>\n {/* box-space chrome — labels, selection border, per-page buttons — fills\n the outer box, NEVER rotates. Bands are plain regions: a label is\n `bottom:0; height: frame.bottom`, a button row `top:0; height: frame.top`. */}\n {chrome?.(ctx)}\n </PageProvider>\n </div>\n );\n}\n\nexport interface StageProps {\n /**\n * PAGE-SPACE content for each visible page (RenderLayer, annotations,\n * markers). Rendered inside the page's content frame, so it ROTATES with the\n * page's display rotation — coordinates are plain PDF points.\n */\n children: (page: PageContextValue) => React.ReactNode;\n /**\n * BOX-SPACE chrome for each visible page (page-number label, selection\n * border, a per-page rotate/delete button). Rendered into the OUTER box\n * (content + reserved `pageFrame`), so it does NOT rotate and the reserved\n * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three\n * coordinate spaces: `children` (page content), `pageChrome` (page box +\n * frame), `overlay` (viewport).\n */\n pageChrome?: (page: PageContextValue) => React.ReactNode;\n /** Viewport-space UI (menus, controls) rendered above the pages. */\n overlay?: React.ReactNode;\n /**\n * Route this Stage's pointer events to the interaction hub (page-resolved via\n * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`\n * tool's job and dragging in `pointer` mode selects text (incl. across pages).\n * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).\n */\n interaction?: boolean;\n /**\n * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch\n * (Safari gesture events included). Default true. Turn OFF for follower\n * lenses with a fixed magnification — a thumbnail rail should scroll under\n * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel\n * pan, and pinches are still swallowed (they never page-zoom the browser).\n */\n zoomGestures?: boolean;\n /** The stage lens to drive (default: the main StageToken). */\n token?: StageTokenProp;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport function Stage({\n children,\n pageChrome,\n overlay,\n interaction = false,\n zoomGestures = true,\n token = StageToken,\n className,\n style,\n}: StageProps) {\n const stage = useCapability(token);\n const ix = useOptionalCapability(InteractionToken);\n const useHub = interaction && !!ix;\n // The hub's resolved cursor (text/grab/…), applied to the viewport when driving.\n const hubCursor = useKernelValue(() => ix?.cursor() ?? 'default');\n const ref = useRef<HTMLDivElement>(null);\n const docId = useDocumentId();\n // visiblePages already folds in the camera (each page carries its device-snapped\n // screenX/screenY + transform), so panning re-emits the list — no separate\n // camera subscription needed for positioning.\n const pages = useSelector(token, (c) => c.visiblePages()); // memoized -> stable ref\n // Reserved chrome bands (screen px), uniform across pages — the frame the\n // outer box reserves and `pageChrome` paints into.\n const frame = useSelector(\n token,\n (c) => c.pageFrame(),\n (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left,\n );\n\n useEffect(() => {\n const el = ref.current!;\n // Only report the viewport size. Initial placement (home) is the Stage plugin's\n // job — it watches the viewport and homes once it's ready (and a higher-priority\n // initial-view provider can override that). The shell stays dumb.\n const setVp = () => stage.setViewport({ width: el.clientWidth, height: el.clientHeight });\n const ro = new ResizeObserver(setVp);\n ro.observe(el);\n setVp();\n\n // Report the device pixel ratio so page transforms render crisp. dppx changes\n // (zoom, dragging between monitors) fire the media query; re-subscribe each\n // time since the query value itself moves.\n let mq: MediaQueryList | null = null;\n const reportDpr = () => {\n stage.setDevicePixelRatio(window.devicePixelRatio || 1);\n mq?.removeEventListener('change', reportDpr);\n mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);\n mq.addEventListener('change', reportDpr);\n };\n reportDpr();\n\n // Wheel is ambient navigation in BOTH modes: ctrl/meta zooms (classified\n // per input — synthesized pinch, mouse notch, cmd-scroll scrub — by\n // wheelZoomFactor), else scrolls. With zoom gestures off, a zoom-wheel\n // falls through to ordinary pan (a cmd+scroll over a thumbnail rail\n // scrolls the rail).\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const r = el.getBoundingClientRect();\n if (zoomGestures && (e.ctrlKey || e.metaKey)) {\n stage.zoomAround({ x: e.clientX - r.left, y: e.clientY - r.top }, wheelZoomFactor(e));\n } else {\n const dx = e.shiftKey ? e.deltaY : e.deltaX;\n const dy = e.shiftKey ? e.deltaX : e.deltaY;\n stage.panBy(-dx, -dy);\n }\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n\n // Safari never synthesizes ctrl+wheel for trackpad pinch — it fires\n // proprietary gesture events carrying an ABSOLUTE scale; convert to the\n // per-event ratio the camera physics wants. Feature-detected: Chrome and\n // Firefox don't have GestureEvent, so this wiring costs them nothing.\n // preventDefault runs even with zoom gestures off — a pinch over the\n // stage must never zoom the page itself.\n let lastScale = 1;\n const onGestureStart = (e: Event) => {\n e.preventDefault();\n lastScale = (e as unknown as { scale?: number }).scale ?? 1;\n };\n const onGestureChange = (e: Event) => {\n e.preventDefault();\n const g = e as unknown as { scale?: number; clientX: number; clientY: number };\n const scale = g.scale ?? 1;\n if (zoomGestures && scale > 0) {\n const r = el.getBoundingClientRect();\n stage.zoomAround({ x: g.clientX - r.left, y: g.clientY - r.top }, scale / lastScale);\n }\n lastScale = scale;\n };\n const hasGestureEvents = 'GestureEvent' in window;\n if (hasGestureEvents) {\n el.addEventListener('gesturestart', onGestureStart);\n el.addEventListener('gesturechange', onGestureChange);\n el.addEventListener('gestureend', onGestureStart); // reset the base\n }\n\n const cleanups: Array<() => void> = [];\n if (useHub && ix) {\n // Forward to the hub: pan/select/etc. become tool-gated handlers. `pageAt`\n // resolves the page per event, so a drag can cross pages (text selection).\n const clicks = createClickCounter();\n const forward = (phase: PointerSample['phase'], e: PointerEvent, clickCount = 1) => {\n const r = el.getBoundingClientRect();\n const vpt = { x: e.clientX - r.left, y: e.clientY - r.top };\n ix.dispatch({\n phase,\n viewport: vpt,\n page: stage.pageAt(vpt) ?? undefined,\n // Page-anchored gestures (annotation move/resize) track the origin\n // page's frame through this even when the cursor is off that page.\n project: (pon) => stage.pointOnPage(pon, vpt),\n modifiers: { shift: e.shiftKey, alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey },\n clickCount,\n });\n };\n let dragging = false;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n forward('down', e, clicks(Date.now(), e.clientX, e.clientY));\n };\n const hover = (e: PointerEvent) => {\n if (!dragging) forward('move', e); // cursor feedback, no gesture\n };\n const winMove = (e: PointerEvent) => {\n if (dragging) forward('move', e);\n };\n const up = (e: PointerEvent) => {\n if (!dragging) return;\n dragging = false;\n forward('up', e);\n };\n el.addEventListener('pointerdown', down);\n el.addEventListener('pointermove', hover);\n window.addEventListener('pointermove', winMove);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n el.removeEventListener('pointermove', hover);\n window.removeEventListener('pointermove', winMove);\n window.removeEventListener('pointerup', up);\n });\n } else {\n // Built-in drag-to-pan (no interaction hub) — unchanged behaviour.\n let dragging = false;\n let lx = 0;\n let ly = 0;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n lx = e.clientX;\n ly = e.clientY;\n };\n const move = (e: PointerEvent) => {\n if (!dragging) return;\n stage.panBy(e.clientX - lx, e.clientY - ly);\n lx = e.clientX;\n ly = e.clientY;\n };\n const up = () => {\n dragging = false;\n };\n el.addEventListener('pointerdown', down);\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n });\n }\n\n return () => {\n ro.disconnect();\n mq?.removeEventListener('change', reportDpr);\n el.removeEventListener('wheel', onWheel);\n if (hasGestureEvents) {\n el.removeEventListener('gesturestart', onGestureStart);\n el.removeEventListener('gesturechange', onGestureChange);\n el.removeEventListener('gestureend', onGestureStart);\n }\n cleanups.forEach((fn) => fn());\n };\n }, [stage, ix, useHub, zoomGestures]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'relative',\n overflow: 'hidden',\n touchAction: 'none',\n ...(useHub ? { cursor: hubCursor } : null),\n ...style,\n }}\n >\n {pages.map((p) => (\n <PageSurface\n key={p.pageIndex}\n documentId={docId ?? ''}\n page={p}\n frame={frame}\n stage={stage}\n render={children}\n chrome={pageChrome}\n />\n ))}\n {overlay}\n </div>\n );\n}\n\n// ── Facade hooks — thin sugar over the capability + generic binding ───────────\nexport function useStage(token: StageTokenProp = StageToken) {\n return useCapability(token);\n}\nexport function useZoom(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const zoom = useSelector(token, (c) => c.zoomLevel());\n const mode = useSelector(token, (c) => c.zoomMode());\n return {\n zoom,\n /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */\n mode,\n zoomIn: s.zoomIn,\n zoomOut: s.zoomOut,\n fitWidth: s.fitWidth,\n fitPage: s.fitPage,\n fitAll: s.fitAll,\n automatic: s.automatic,\n zoomTo: s.zoomTo,\n };\n}\nexport function usePages(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const currentPage = useSelector(token, (c) => c.currentPage());\n const pageCount = useSelector(token, (c) => c.pageCount());\n return {\n currentPage,\n pageCount,\n goToPage: s.goToPage,\n next: s.next,\n prev: s.prev,\n reveal: s.reveal,\n };\n}\nexport function useLayout(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const flow = useSelector(token, (c) => c.flow());\n const layout = useSelector(token, (c) => c.layout());\n const spread = useSelector(token, (c) => c.spread());\n const sizing = useSelector(token, (c) => c.sizing());\n const bounded = useSelector(token, (c) => c.bounded());\n return {\n flow,\n layout,\n spread,\n sizing,\n bounded,\n setFlow: s.setFlow,\n setLayout: s.setLayout,\n setSpread: s.setSpread,\n setSizing: s.setSizing,\n setBounded: s.setBounded,\n };\n}\n\n/** The document's page list (with PDF labels) + the current item's pages — the\n * data for page thumbnails / worksheet-style page tabs. */\nexport function usePageList(token: StageTokenProp = StageToken) {\n const pages = useSelector(\n token,\n (c) => c.pages(),\n (a, b) =>\n a.length === b.length && a.every((p, i) => p.pon === b[i].pon && p.label === b[i].label),\n );\n const current = useSelector(\n token,\n (c) => c.currentItemPages(),\n (a, b) => a.length === b.length && a.every((x, i) => x === b[i]),\n );\n return { pages, currentItemPages: current };\n}\n\n/**\n * All Stage settings + the batch `update`. This is the seam for \"presets are a\n * customer concern\": keep your own `Partial<StageSettings>` objects and apply them\n * with `update(preset)` (one anchor-preserving change).\n */\nexport function useStageSettings(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n // settingsEqual derives from the plugin's settings registry — a new setting is\n // covered here automatically, without this package spelling out the shape.\n const settings = useSelector(token, (c) => c.settings(), settingsEqual);\n return { settings, update: s.update, reset: s.resetView };\n}\n"],"mappings":"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"}
package/dist/stamp.cjs ADDED
@@ -0,0 +1,76 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./rolldown-runtime-DDXJien1.cjs");
3
+ const require_runtime = require("./runtime.cjs");
4
+ let react = require("react");
5
+ let _embedpdf_plugin_stamp = require("@embedpdf/plugin-stamp");
6
+ //#region src/stamp.tsx
7
+ /** The stamp capability (workspace-scoped: one library set for every document). */
8
+ function useStamp() {
9
+ return require_runtime.useCapability(_embedpdf_plugin_stamp.StampToken);
10
+ }
11
+ function useStampLibraries() {
12
+ return require_runtime.useSelector(_embedpdf_plugin_stamp.StampToken, (c) => c.libraries(), require_runtime.shallowArray);
13
+ }
14
+ /** Assets of one library, or every asset when `libraryId` is omitted. */
15
+ function useStampAssets(libraryId) {
16
+ return require_runtime.useSelector(_embedpdf_plugin_stamp.StampToken, (c) => c.assets(libraryId), require_runtime.shallowArray);
17
+ }
18
+ /**
19
+ * Object URL for an asset's cached preview (gallery thumbnails). The plugin
20
+ * holds the preview BYTES; the URL — a DOM resource — is created here and
21
+ * revoked on unmount/asset change, mirroring `<AnnotationLayer>`'s rule that
22
+ * object-URL lifetime belongs to the framework layer.
23
+ */
24
+ function useStampAssetPreviewUrl(assetId) {
25
+ const stamp = require_runtime.useCapability(_embedpdf_plugin_stamp.StampToken);
26
+ const [url, setUrl] = (0, react.useState)(null);
27
+ (0, react.useEffect)(() => {
28
+ const preview = assetId ? stamp.assetPreview(assetId) : null;
29
+ if (!preview) {
30
+ setUrl(null);
31
+ return;
32
+ }
33
+ const body = new ArrayBuffer(preview.bytes.byteLength);
34
+ new Uint8Array(body).set(preview.bytes);
35
+ const obj = URL.createObjectURL(new Blob([body], { type: preview.mimeType }));
36
+ setUrl(obj);
37
+ return () => {
38
+ URL.revokeObjectURL(obj);
39
+ setUrl(null);
40
+ };
41
+ }, [stamp, assetId]);
42
+ return url;
43
+ }
44
+ /**
45
+ * Arm/disarm assets against the nearest `<DocumentScope>` (or the active
46
+ * document) — the one-liner a gallery item's onClick needs.
47
+ */
48
+ function useArmStampAsset() {
49
+ const stamp = require_runtime.useCapability(_embedpdf_plugin_stamp.StampToken);
50
+ const documentId = require_runtime.useDocumentId();
51
+ return {
52
+ armAsset: (assetId, opts) => {
53
+ if (!documentId) return Promise.reject(/* @__PURE__ */ new Error("[stamp] no document in scope"));
54
+ return stamp.armAsset(documentId, assetId, opts);
55
+ },
56
+ disarm: () => {
57
+ if (documentId) stamp.disarm(documentId);
58
+ }
59
+ };
60
+ }
61
+ //#endregion
62
+ exports.useArmStampAsset = useArmStampAsset;
63
+ exports.useStamp = useStamp;
64
+ exports.useStampAssetPreviewUrl = useStampAssetPreviewUrl;
65
+ exports.useStampAssets = useStampAssets;
66
+ exports.useStampLibraries = useStampLibraries;
67
+ Object.keys(_embedpdf_plugin_stamp).forEach(function(k) {
68
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
69
+ enumerable: true,
70
+ get: function() {
71
+ return _embedpdf_plugin_stamp[k];
72
+ }
73
+ });
74
+ });
75
+
76
+ //# sourceMappingURL=stamp.cjs.map