@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.
- package/LICENSE +192 -0
- package/dist/AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.cts +2593 -0
- package/dist/AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.d.ts +2593 -0
- package/dist/annotation-B6jwfTCh.d.cts +173 -0
- package/dist/annotation-Ct6dFtzJ.cjs +913 -0
- package/dist/annotation-Ct6dFtzJ.cjs.map +1 -0
- package/dist/annotation-DjGWJljY.js +829 -0
- package/dist/annotation-DjGWJljY.js.map +1 -0
- package/dist/annotation-menu.cjs +115 -0
- package/dist/annotation-menu.cjs.map +1 -0
- package/dist/annotation-menu.d.cts +7 -0
- package/dist/annotation-menu.d.ts +7 -0
- package/dist/annotation-menu.js +99 -0
- package/dist/annotation-menu.js.map +1 -0
- package/dist/annotation-nUMefyjw.d.ts +173 -0
- package/dist/annotation.cjs +25 -0
- package/dist/annotation.d.cts +3 -0
- package/dist/annotation.d.ts +3 -0
- package/dist/annotation.js +4 -0
- package/dist/commands.cjs +59 -0
- package/dist/commands.cjs.map +1 -0
- package/dist/commands.d.cts +20 -0
- package/dist/commands.d.ts +20 -0
- package/dist/commands.js +47 -0
- package/dist/commands.js.map +1 -0
- package/dist/form.cjs +560 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.d.cts +52 -0
- package/dist/form.d.ts +52 -0
- package/dist/form.js +545 -0
- package/dist/form.js.map +1 -0
- package/dist/i18n.cjs +52 -0
- package/dist/i18n.cjs.map +1 -0
- package/dist/i18n.d.cts +30 -0
- package/dist/i18n.d.ts +30 -0
- package/dist/i18n.js +42 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.cjs +240 -0
- package/dist/index.d.cts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +37 -0
- package/dist/interaction.cjs +152 -0
- package/dist/interaction.cjs.map +1 -0
- package/dist/interaction.d.cts +46 -0
- package/dist/interaction.d.ts +46 -0
- package/dist/interaction.js +139 -0
- package/dist/interaction.js.map +1 -0
- package/dist/link.cjs +108 -0
- package/dist/link.cjs.map +1 -0
- package/dist/link.d.cts +16 -0
- package/dist/link.d.ts +16 -0
- package/dist/link.js +98 -0
- package/dist/link.js.map +1 -0
- package/dist/metadata.cjs +25 -0
- package/dist/metadata.cjs.map +1 -0
- package/dist/metadata.d.cts +11 -0
- package/dist/metadata.d.ts +11 -0
- package/dist/metadata.js +16 -0
- package/dist/metadata.js.map +1 -0
- package/dist/page-edit.cjs +20 -0
- package/dist/page-edit.cjs.map +1 -0
- package/dist/page-edit.d.cts +7 -0
- package/dist/page-edit.d.ts +7 -0
- package/dist/page-edit.js +11 -0
- package/dist/page-edit.js.map +1 -0
- package/dist/page-view.cjs +107 -0
- package/dist/page-view.cjs.map +1 -0
- package/dist/page-view.d.cts +23 -0
- package/dist/page-view.d.ts +23 -0
- package/dist/page-view.js +95 -0
- package/dist/page-view.js.map +1 -0
- package/dist/redaction.cjs +35 -0
- package/dist/redaction.cjs.map +1 -0
- package/dist/redaction.d.cts +14 -0
- package/dist/redaction.d.ts +14 -0
- package/dist/redaction.js +25 -0
- package/dist/redaction.js.map +1 -0
- package/dist/render.cjs +142 -0
- package/dist/render.cjs.map +1 -0
- package/dist/render.d.cts +32 -0
- package/dist/render.d.ts +32 -0
- package/dist/render.js +131 -0
- package/dist/render.js.map +1 -0
- package/dist/rolldown-runtime-DDXJien1.cjs +50 -0
- package/dist/runtime-CMxIuF2O.d.cts +195 -0
- package/dist/runtime-DV98q7I0.d.ts +195 -0
- package/dist/runtime.cjs +314 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +3 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.js +287 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scrollbar.cjs +241 -0
- package/dist/scrollbar.cjs.map +1 -0
- package/dist/scrollbar.d.cts +42 -0
- package/dist/scrollbar.d.ts +42 -0
- package/dist/scrollbar.js +213 -0
- package/dist/scrollbar.js.map +1 -0
- package/dist/search.cjs +70 -0
- package/dist/search.cjs.map +1 -0
- package/dist/search.d.cts +35 -0
- package/dist/search.d.ts +35 -0
- package/dist/search.js +58 -0
- package/dist/search.js.map +1 -0
- package/dist/selection.cjs +60 -0
- package/dist/selection.cjs.map +1 -0
- package/dist/selection.d.cts +12 -0
- package/dist/selection.d.ts +12 -0
- package/dist/selection.js +49 -0
- package/dist/selection.js.map +1 -0
- package/dist/shell.cjs +57 -0
- package/dist/shell.cjs.map +1 -0
- package/dist/shell.d.cts +27 -0
- package/dist/shell.d.ts +27 -0
- package/dist/shell.js +46 -0
- package/dist/shell.js.map +1 -0
- package/dist/stage.cjs +343 -0
- package/dist/stage.cjs.map +1 -0
- package/dist/stage.d.cts +104 -0
- package/dist/stage.d.ts +104 -0
- package/dist/stage.js +327 -0
- package/dist/stage.js.map +1 -0
- package/dist/stamp.cjs +76 -0
- package/dist/stamp.cjs.map +1 -0
- package/dist/stamp.d.cts +28 -0
- package/dist/stamp.d.ts +28 -0
- package/dist/stamp.js +63 -0
- package/dist/stamp.js.map +1 -0
- package/dist/toolbar.cjs +515 -0
- package/dist/toolbar.cjs.map +1 -0
- package/dist/toolbar.d.cts +100 -0
- package/dist/toolbar.d.ts +100 -0
- package/dist/toolbar.js +505 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/views.cjs +35 -0
- package/dist/views.cjs.map +1 -0
- package/dist/views.d.cts +21 -0
- package/dist/views.d.ts +21 -0
- package/dist/views.js +26 -0
- package/dist/views.js.map +1 -0
- package/package.json +158 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CapabilityToken } from "@embedpdf/core";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { ScrollMetrics, StageCapability } from "@embedpdf/plugin-stage";
|
|
4
|
+
//#region src/scrollbar.d.ts
|
|
5
|
+
type ScrollbarAxis = 'x' | 'y';
|
|
6
|
+
/** Live scroll metrics for a stage lens (reference-stable; see
|
|
7
|
+
* `StageCapability.scrollMetrics`). The raw material for custom scroll UI. */
|
|
8
|
+
declare function useScrollMetrics(token?: CapabilityToken<StageCapability>): ScrollMetrics;
|
|
9
|
+
interface ScrollbarProps {
|
|
10
|
+
axis: ScrollbarAxis;
|
|
11
|
+
/** The stage lens to scroll (default: the main StageToken). */
|
|
12
|
+
token?: CapabilityToken<StageCapability>;
|
|
13
|
+
/**
|
|
14
|
+
* Overlay auto-hide: fade `autoHide` ms after the camera stops moving
|
|
15
|
+
* (drags and hover pin it visible; a hidden bar ignores the pointer, like
|
|
16
|
+
* macOS). `false` = always visible. Visibility is published as
|
|
17
|
+
* `data-state="visible|hidden"` — the default style fades opacity; replace
|
|
18
|
+
* it in CSS for any other treatment. Default 1200.
|
|
19
|
+
*/
|
|
20
|
+
autoHide?: number | false;
|
|
21
|
+
/** Minimum thumb length in px — native bars never vanish on long documents.
|
|
22
|
+
* Position stays proportional via the standard travel remap. Default 24. */
|
|
23
|
+
minThumbSize?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Pressing the track: 'page' steps by 90% of a viewport toward the pointer,
|
|
26
|
+
* repeats while held, and stops when the thumb reaches the pointer (the
|
|
27
|
+
* native default); 'jump' centers the thumb at the pointer and hands off to
|
|
28
|
+
* a drag (the macOS option-click / Figma feel). Default 'page'.
|
|
29
|
+
*/
|
|
30
|
+
trackPress?: 'page' | 'jump';
|
|
31
|
+
/** Track class/style. The default style pins the bar to the right (y) or
|
|
32
|
+
* bottom (x) edge of the nearest positioned ancestor — the Stage container
|
|
33
|
+
* when rendered in its `overlay`; override to place it anywhere else. */
|
|
34
|
+
className?: string;
|
|
35
|
+
style?: React.CSSProperties;
|
|
36
|
+
thumbClassName?: string;
|
|
37
|
+
thumbStyle?: React.CSSProperties;
|
|
38
|
+
}
|
|
39
|
+
declare function Scrollbar({ axis, token, autoHide, minThumbSize, trackPress, className, style, thumbClassName, thumbStyle }: ScrollbarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { Scrollbar, ScrollbarAxis, ScrollbarProps, useScrollMetrics };
|
|
42
|
+
//# sourceMappingURL=scrollbar.d.ts.map
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { useCapability, useSelector } from "./runtime.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { StageToken } from "@embedpdf/plugin-stage";
|
|
5
|
+
//#region src/scrollbar.tsx
|
|
6
|
+
/** Live scroll metrics for a stage lens (reference-stable; see
|
|
7
|
+
* `StageCapability.scrollMetrics`). The raw material for custom scroll UI. */
|
|
8
|
+
function useScrollMetrics(token = StageToken) {
|
|
9
|
+
return useSelector(token, (c) => c.scrollMetrics());
|
|
10
|
+
}
|
|
11
|
+
const clamp01 = (v) => Math.min(1, Math.max(0, v));
|
|
12
|
+
/** Best-effort pointer capture: an already-released pointer (pen/touch races,
|
|
13
|
+
* synthetic events in tests) throws NotFoundError — the press must still work,
|
|
14
|
+
* just without capture (moves keep arriving while the pointer stays on us). */
|
|
15
|
+
const capturePointer = (el, pointerId) => {
|
|
16
|
+
try {
|
|
17
|
+
el.setPointerCapture(pointerId);
|
|
18
|
+
} catch {}
|
|
19
|
+
};
|
|
20
|
+
/** Thumb geometry from metrics + a measured track. One formula for render,
|
|
21
|
+
* drag capture, and paging — they can never disagree. */
|
|
22
|
+
const geometry = (m, vertical, trackPx, minThumbSize) => {
|
|
23
|
+
const client = vertical ? m.clientHeight : m.clientWidth;
|
|
24
|
+
const total = vertical ? m.scrollHeight : m.scrollWidth;
|
|
25
|
+
const offset = vertical ? m.scrollTop : m.scrollLeft;
|
|
26
|
+
const maxOffset = Math.max(0, total - client);
|
|
27
|
+
const thumbLen = Math.min(trackPx, Math.max(minThumbSize, total > 0 ? client / total * trackPx : 0));
|
|
28
|
+
const travel = Math.max(0, trackPx - thumbLen);
|
|
29
|
+
return {
|
|
30
|
+
client,
|
|
31
|
+
offset,
|
|
32
|
+
maxOffset,
|
|
33
|
+
thumbLen,
|
|
34
|
+
travel,
|
|
35
|
+
thumbPos: maxOffset > 0 ? offset / maxOffset * travel : 0
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
function Scrollbar({ axis, token = StageToken, autoHide = 1200, minThumbSize = 24, trackPress = "page", className, style, thumbClassName, thumbStyle }) {
|
|
39
|
+
const stage = useCapability(token);
|
|
40
|
+
const m = useScrollMetrics(token);
|
|
41
|
+
const vertical = axis === "y";
|
|
42
|
+
const scrollable = vertical ? m.scrollableY : m.scrollableX;
|
|
43
|
+
const trackRef = useRef(null);
|
|
44
|
+
const [trackPx, setTrackPx] = useState(0);
|
|
45
|
+
const [dragging, setDragging] = useState(false);
|
|
46
|
+
const [hovered, setHovered] = useState(false);
|
|
47
|
+
const [active, setActive] = useState(true);
|
|
48
|
+
const g = geometry(m, vertical, trackPx, minThumbSize);
|
|
49
|
+
const hideAfter = autoHide === false ? 0 : autoHide;
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!hideAfter) return;
|
|
52
|
+
setActive(true);
|
|
53
|
+
const t = setTimeout(() => setActive(false), hideAfter);
|
|
54
|
+
return () => clearTimeout(t);
|
|
55
|
+
}, [m, hideAfter]);
|
|
56
|
+
const shown = !hideAfter || active || hovered || dragging;
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const el = trackRef.current;
|
|
59
|
+
if (!el) return;
|
|
60
|
+
const measure = () => setTrackPx(vertical ? el.clientHeight : el.clientWidth);
|
|
61
|
+
const ro = new ResizeObserver(measure);
|
|
62
|
+
ro.observe(el);
|
|
63
|
+
measure();
|
|
64
|
+
return () => ro.disconnect();
|
|
65
|
+
}, [vertical, scrollable]);
|
|
66
|
+
const dragRef = useRef(null);
|
|
67
|
+
const pageRef = useRef(null);
|
|
68
|
+
const lastPtr = useRef(0);
|
|
69
|
+
const ptrPos = (e) => {
|
|
70
|
+
const r = trackRef.current.getBoundingClientRect();
|
|
71
|
+
return vertical ? e.clientY - r.top : e.clientX - r.left;
|
|
72
|
+
};
|
|
73
|
+
/** Fresh geometry for paging steps — read from the capability, never a stale render. */
|
|
74
|
+
const liveGeometry = () => geometry(stage.scrollMetrics(), vertical, trackPx, minThumbSize);
|
|
75
|
+
const stopPaging = () => {
|
|
76
|
+
if (pageRef.current) {
|
|
77
|
+
clearTimeout(pageRef.current.timer);
|
|
78
|
+
clearInterval(pageRef.current.timer);
|
|
79
|
+
pageRef.current = null;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const endDrag = () => {
|
|
83
|
+
dragRef.current = null;
|
|
84
|
+
stopPaging();
|
|
85
|
+
setDragging(false);
|
|
86
|
+
};
|
|
87
|
+
const beginDrag = (grab, applied) => {
|
|
88
|
+
dragRef.current = {
|
|
89
|
+
grab,
|
|
90
|
+
applied,
|
|
91
|
+
max: g.maxOffset,
|
|
92
|
+
travel: g.travel
|
|
93
|
+
};
|
|
94
|
+
setDragging(true);
|
|
95
|
+
};
|
|
96
|
+
const onThumbDown = (e) => {
|
|
97
|
+
if (e.button !== 0) return;
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
e.stopPropagation();
|
|
100
|
+
capturePointer(e.target, e.pointerId);
|
|
101
|
+
beginDrag(ptrPos(e) - g.thumbPos, g.offset);
|
|
102
|
+
};
|
|
103
|
+
const onTrackDown = (e) => {
|
|
104
|
+
if (e.button !== 0 || e.target !== e.currentTarget) return;
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
capturePointer(e.currentTarget, e.pointerId);
|
|
107
|
+
const p = lastPtr.current = ptrPos(e);
|
|
108
|
+
if (trackPress === "jump") {
|
|
109
|
+
const want = g.travel > 0 ? clamp01((p - g.thumbLen / 2) / g.travel) * g.maxOffset : 0;
|
|
110
|
+
stage.scrollTo(vertical ? { top: want } : { left: want });
|
|
111
|
+
beginDrag(g.thumbLen / 2, want);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const dir = p < g.thumbPos ? -1 : 1;
|
|
115
|
+
const step = () => {
|
|
116
|
+
const live = liveGeometry();
|
|
117
|
+
if (dir === 1 ? lastPtr.current <= live.thumbPos + live.thumbLen : lastPtr.current >= live.thumbPos) return stopPaging();
|
|
118
|
+
stage.scrollBy(vertical ? { top: dir * live.client * .9 } : { left: dir * live.client * .9 });
|
|
119
|
+
};
|
|
120
|
+
step();
|
|
121
|
+
const timer = window.setTimeout(() => {
|
|
122
|
+
if (!pageRef.current) return;
|
|
123
|
+
pageRef.current.timer = window.setInterval(step, 80);
|
|
124
|
+
}, 350);
|
|
125
|
+
pageRef.current = {
|
|
126
|
+
dir,
|
|
127
|
+
timer
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
const onMove = (e) => {
|
|
131
|
+
const d = dragRef.current;
|
|
132
|
+
if (d) {
|
|
133
|
+
if (d.travel <= 0) return;
|
|
134
|
+
const want = clamp01((ptrPos(e) - d.grab) / d.travel) * d.max;
|
|
135
|
+
const delta = want - d.applied;
|
|
136
|
+
if (delta) {
|
|
137
|
+
stage.panBy(vertical ? 0 : -delta, vertical ? -delta : 0);
|
|
138
|
+
d.applied = want;
|
|
139
|
+
}
|
|
140
|
+
} else if (pageRef.current) lastPtr.current = ptrPos(e);
|
|
141
|
+
};
|
|
142
|
+
useEffect(() => endDrag, []);
|
|
143
|
+
if (!scrollable) return null;
|
|
144
|
+
const trackDefaults = vertical ? {
|
|
145
|
+
position: "absolute",
|
|
146
|
+
top: 0,
|
|
147
|
+
right: 0,
|
|
148
|
+
bottom: 0,
|
|
149
|
+
width: 12
|
|
150
|
+
} : {
|
|
151
|
+
position: "absolute",
|
|
152
|
+
left: 0,
|
|
153
|
+
right: 0,
|
|
154
|
+
bottom: 0,
|
|
155
|
+
height: 12
|
|
156
|
+
};
|
|
157
|
+
const thumbDefaults = vertical ? {
|
|
158
|
+
position: "absolute",
|
|
159
|
+
left: 2,
|
|
160
|
+
right: 2,
|
|
161
|
+
top: g.thumbPos,
|
|
162
|
+
height: g.thumbLen
|
|
163
|
+
} : {
|
|
164
|
+
position: "absolute",
|
|
165
|
+
top: 2,
|
|
166
|
+
bottom: 2,
|
|
167
|
+
left: g.thumbPos,
|
|
168
|
+
width: g.thumbLen
|
|
169
|
+
};
|
|
170
|
+
return /* @__PURE__ */ jsx("div", {
|
|
171
|
+
ref: trackRef,
|
|
172
|
+
role: "scrollbar",
|
|
173
|
+
"aria-orientation": vertical ? "vertical" : "horizontal",
|
|
174
|
+
"aria-valuemin": 0,
|
|
175
|
+
"aria-valuemax": Math.round(g.maxOffset),
|
|
176
|
+
"aria-valuenow": Math.round(g.offset),
|
|
177
|
+
"data-embedpdf-scrollbar": "",
|
|
178
|
+
"data-axis": axis,
|
|
179
|
+
"data-state": shown ? "visible" : "hidden",
|
|
180
|
+
"data-dragging": dragging ? "" : void 0,
|
|
181
|
+
className,
|
|
182
|
+
style: {
|
|
183
|
+
...trackDefaults,
|
|
184
|
+
touchAction: "none",
|
|
185
|
+
userSelect: "none",
|
|
186
|
+
opacity: shown ? 1 : 0,
|
|
187
|
+
transition: "opacity 200ms",
|
|
188
|
+
pointerEvents: shown ? "auto" : "none",
|
|
189
|
+
...style
|
|
190
|
+
},
|
|
191
|
+
onPointerDown: onTrackDown,
|
|
192
|
+
onPointerMove: onMove,
|
|
193
|
+
onPointerUp: endDrag,
|
|
194
|
+
onPointerCancel: endDrag,
|
|
195
|
+
onPointerEnter: () => setHovered(true),
|
|
196
|
+
onPointerLeave: () => setHovered(false),
|
|
197
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
198
|
+
"data-embedpdf-scrollbar-thumb": "",
|
|
199
|
+
className: thumbClassName,
|
|
200
|
+
style: {
|
|
201
|
+
...thumbDefaults,
|
|
202
|
+
borderRadius: 6,
|
|
203
|
+
background: "var(--epdf-scrollbar-thumb, rgba(0, 0, 0, 0.4))",
|
|
204
|
+
...thumbStyle
|
|
205
|
+
},
|
|
206
|
+
onPointerDown: onThumbDown
|
|
207
|
+
})
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
export { Scrollbar, useScrollMetrics };
|
|
212
|
+
|
|
213
|
+
//# sourceMappingURL=scrollbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollbar.js","names":[],"sources":["../src/scrollbar.tsx"],"sourcesContent":["/**\n * Headless scrollbar for a Stage lens — a pure view of `stage.scrollMetrics()`.\n *\n * The Stage exposes the native scroller contract (scrollTop/scrollHeight/\n * clientHeight, in screen px — see plugin-stage's README); this component turns\n * it into a native-feeling bar: thumb drag with pointer capture and a preserved\n * grab point, track paging with press-and-hold repeat that stops at the\n * pointer, a minimum thumb length on long documents, and macOS-style overlay\n * auto-hide. On an UNBOUNDED stage the metrics already carry the Figma\n * semantics (the range is the union of content and view), so the same bar\n * shrinks toward the edge as you pan away and rides you back — the mapping is\n * FROZEN for the duration of a thumb drag so the thumb never chases itself\n * while the union re-collapses.\n *\n * Headless styling contract: geometry and behavior live here; looks live in\n * your CSS. Style via `className`/`thumbClassName` (or the style props) against\n * [data-embedpdf-scrollbar][data-axis=\"y\"][data-state=\"visible|hidden\"]\n * [data-embedpdf-scrollbar][data-dragging]\n * [data-embedpdf-scrollbar-thumb]\n * The defaults are deliberately minimal: a transparent track pinned to the\n * viewport edge and a `var(--epdf-scrollbar-thumb, …)` pill, so the bar works\n * unstyled and disappears into any theme. Build something else entirely\n * (minimap, progress ring) from `useScrollMetrics()` + `stage.scrollTo()`.\n */\n\nimport * as React from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { StageToken } from '@embedpdf/plugin-stage';\nimport type { ScrollMetrics, StageCapability } from '@embedpdf/plugin-stage';\nimport type { CapabilityToken } from '@embedpdf/core';\nimport { useCapability, useSelector } from './runtime';\n\nexport type ScrollbarAxis = 'x' | 'y';\n\n/** Live scroll metrics for a stage lens (reference-stable; see\n * `StageCapability.scrollMetrics`). The raw material for custom scroll UI. */\nexport function useScrollMetrics(\n token: CapabilityToken<StageCapability> = StageToken,\n): ScrollMetrics {\n return useSelector(token, (c) => c.scrollMetrics());\n}\n\nexport interface ScrollbarProps {\n axis: ScrollbarAxis;\n /** The stage lens to scroll (default: the main StageToken). */\n token?: CapabilityToken<StageCapability>;\n /**\n * Overlay auto-hide: fade `autoHide` ms after the camera stops moving\n * (drags and hover pin it visible; a hidden bar ignores the pointer, like\n * macOS). `false` = always visible. Visibility is published as\n * `data-state=\"visible|hidden\"` — the default style fades opacity; replace\n * it in CSS for any other treatment. Default 1200.\n */\n autoHide?: number | false;\n /** Minimum thumb length in px — native bars never vanish on long documents.\n * Position stays proportional via the standard travel remap. Default 24. */\n minThumbSize?: number;\n /**\n * Pressing the track: 'page' steps by 90% of a viewport toward the pointer,\n * repeats while held, and stops when the thumb reaches the pointer (the\n * native default); 'jump' centers the thumb at the pointer and hands off to\n * a drag (the macOS option-click / Figma feel). Default 'page'.\n */\n trackPress?: 'page' | 'jump';\n /** Track class/style. The default style pins the bar to the right (y) or\n * bottom (x) edge of the nearest positioned ancestor — the Stage container\n * when rendered in its `overlay`; override to place it anywhere else. */\n className?: string;\n style?: React.CSSProperties;\n thumbClassName?: string;\n thumbStyle?: React.CSSProperties;\n}\n\nconst clamp01 = (v: number) => Math.min(1, Math.max(0, v));\n\n/** Best-effort pointer capture: an already-released pointer (pen/touch races,\n * synthetic events in tests) throws NotFoundError — the press must still work,\n * just without capture (moves keep arriving while the pointer stays on us). */\nconst capturePointer = (el: Element, pointerId: number) => {\n try {\n el.setPointerCapture(pointerId);\n } catch {\n /* uncaptured is fine */\n }\n};\n\n/** Thumb geometry from metrics + a measured track. One formula for render,\n * drag capture, and paging — they can never disagree. */\nconst geometry = (m: ScrollMetrics, vertical: boolean, trackPx: number, minThumbSize: number) => {\n const client = vertical ? m.clientHeight : m.clientWidth;\n const total = vertical ? m.scrollHeight : m.scrollWidth;\n const offset = vertical ? m.scrollTop : m.scrollLeft;\n const maxOffset = Math.max(0, total - client);\n const thumbLen = Math.min(\n trackPx,\n Math.max(minThumbSize, total > 0 ? (client / total) * trackPx : 0),\n );\n const travel = Math.max(0, trackPx - thumbLen);\n const thumbPos = maxOffset > 0 ? (offset / maxOffset) * travel : 0;\n return { client, offset, maxOffset, thumbLen, travel, thumbPos };\n};\n\nexport function Scrollbar({\n axis,\n token = StageToken,\n autoHide = 1200,\n minThumbSize = 24,\n trackPress = 'page',\n className,\n style,\n thumbClassName,\n thumbStyle,\n}: ScrollbarProps) {\n const stage = useCapability(token);\n const m = useScrollMetrics(token);\n const vertical = axis === 'y';\n const scrollable = vertical ? m.scrollableY : m.scrollableX;\n\n const trackRef = useRef<HTMLDivElement>(null);\n const [trackPx, setTrackPx] = useState(0);\n const [dragging, setDragging] = useState(false);\n const [hovered, setHovered] = useState(false);\n const [active, setActive] = useState(true); // camera moved recently\n\n const g = geometry(m, vertical, trackPx, minThumbSize);\n\n // ── overlay auto-hide: any metrics change re-arms the fade timer ──────────\n const hideAfter = autoHide === false ? 0 : autoHide;\n useEffect(() => {\n if (!hideAfter) return;\n setActive(true);\n const t = setTimeout(() => setActive(false), hideAfter);\n return () => clearTimeout(t);\n }, [m, hideAfter]);\n const shown = !hideAfter || active || hovered || dragging;\n\n // ── track measurement (px mapping needs real geometry) ────────────────────\n useEffect(() => {\n const el = trackRef.current;\n if (!el) return;\n const measure = () => setTrackPx(vertical ? el.clientHeight : el.clientWidth);\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n measure();\n return () => ro.disconnect();\n }, [vertical, scrollable]);\n\n // ── interactions. Drag state is FROZEN at pointer-down (grab point, travel,\n // max offset) and applied as relative pans — absolute-feeling in bounded\n // mode (the range is static there) and stable in unbounded mode, where\n // the live union would otherwise shift under the pointer mid-drag. ──────\n const dragRef = useRef<{ grab: number; applied: number; max: number; travel: number } | null>(\n null,\n );\n const pageRef = useRef<{ dir: 1 | -1; timer: number } | null>(null);\n const lastPtr = useRef(0);\n\n const ptrPos = (e: React.PointerEvent) => {\n const r = trackRef.current!.getBoundingClientRect();\n return vertical ? e.clientY - r.top : e.clientX - r.left;\n };\n /** Fresh geometry for paging steps — read from the capability, never a stale render. */\n const liveGeometry = () => geometry(stage.scrollMetrics(), vertical, trackPx, minThumbSize);\n\n const stopPaging = () => {\n if (pageRef.current) {\n clearTimeout(pageRef.current.timer);\n clearInterval(pageRef.current.timer);\n pageRef.current = null;\n }\n };\n const endDrag = () => {\n dragRef.current = null;\n stopPaging();\n setDragging(false);\n };\n\n const beginDrag = (grab: number, applied: number) => {\n dragRef.current = { grab, applied, max: g.maxOffset, travel: g.travel };\n setDragging(true);\n };\n\n const onThumbDown = (e: React.PointerEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n capturePointer(e.target as Element, e.pointerId);\n beginDrag(ptrPos(e) - g.thumbPos, g.offset);\n };\n\n const onTrackDown = (e: React.PointerEvent) => {\n if (e.button !== 0 || e.target !== e.currentTarget) return; // thumb handles its own\n e.preventDefault();\n capturePointer(e.currentTarget as Element, e.pointerId);\n const p = (lastPtr.current = ptrPos(e));\n\n if (trackPress === 'jump') {\n // land the thumb centered at the pointer, then it's an ordinary drag\n const want = g.travel > 0 ? clamp01((p - g.thumbLen / 2) / g.travel) * g.maxOffset : 0;\n stage.scrollTo(vertical ? { top: want } : { left: want });\n beginDrag(g.thumbLen / 2, want);\n return;\n }\n\n // 'page': step toward the pointer, repeat while held, stop at the pointer\n const dir: 1 | -1 = p < g.thumbPos ? -1 : 1;\n const step = () => {\n const live = liveGeometry();\n const reached =\n dir === 1\n ? lastPtr.current <= live.thumbPos + live.thumbLen\n : lastPtr.current >= live.thumbPos;\n if (reached) return stopPaging();\n stage.scrollBy(\n vertical ? { top: dir * live.client * 0.9 } : { left: dir * live.client * 0.9 },\n );\n };\n step();\n // native cadence: a beat before the repeat kicks in, then a steady march\n const timer = window.setTimeout(() => {\n if (!pageRef.current) return;\n pageRef.current.timer = window.setInterval(step, 80);\n }, 350);\n pageRef.current = { dir, timer };\n };\n\n // Pointer capture retargets to the pressed element and bubbles here — one\n // move/up pair serves thumb drags, jump-drags, and paging alike.\n const onMove = (e: React.PointerEvent) => {\n const d = dragRef.current;\n if (d) {\n if (d.travel <= 0) return;\n const want = clamp01((ptrPos(e) - d.grab) / d.travel) * d.max;\n const delta = want - d.applied;\n if (delta) {\n stage.panBy(vertical ? 0 : -delta, vertical ? -delta : 0);\n d.applied = want;\n }\n } else if (pageRef.current) {\n lastPtr.current = ptrPos(e);\n }\n };\n\n useEffect(() => endDrag, []); // unmount: no orphaned repeat timers\n\n if (!scrollable) return null;\n\n const trackDefaults: React.CSSProperties = vertical\n ? { position: 'absolute', top: 0, right: 0, bottom: 0, width: 12 }\n : { position: 'absolute', left: 0, right: 0, bottom: 0, height: 12 };\n const thumbDefaults: React.CSSProperties = vertical\n ? { position: 'absolute', left: 2, right: 2, top: g.thumbPos, height: g.thumbLen }\n : { position: 'absolute', top: 2, bottom: 2, left: g.thumbPos, width: g.thumbLen };\n\n return (\n <div\n ref={trackRef}\n role=\"scrollbar\"\n aria-orientation={vertical ? 'vertical' : 'horizontal'}\n aria-valuemin={0}\n aria-valuemax={Math.round(g.maxOffset)}\n aria-valuenow={Math.round(g.offset)}\n data-embedpdf-scrollbar=\"\"\n data-axis={axis}\n data-state={shown ? 'visible' : 'hidden'}\n data-dragging={dragging ? '' : undefined}\n className={className}\n style={{\n ...trackDefaults,\n touchAction: 'none',\n userSelect: 'none',\n opacity: shown ? 1 : 0,\n transition: 'opacity 200ms',\n // a hidden overlay bar must not eat the clicks under it\n pointerEvents: shown ? 'auto' : 'none',\n ...style,\n }}\n onPointerDown={onTrackDown}\n onPointerMove={onMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onPointerEnter={() => setHovered(true)}\n onPointerLeave={() => setHovered(false)}\n >\n <div\n data-embedpdf-scrollbar-thumb=\"\"\n className={thumbClassName}\n style={{\n ...thumbDefaults,\n borderRadius: 6,\n background: 'var(--epdf-scrollbar-thumb, rgba(0, 0, 0, 0.4))',\n ...thumbStyle,\n }}\n onPointerDown={onThumbDown}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
package/dist/search.cjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_rolldown_runtime = require("./rolldown-runtime-DDXJien1.cjs");
|
|
3
|
+
const require_runtime = require("./runtime.cjs");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
react = require_rolldown_runtime.__toESM(react, 1);
|
|
7
|
+
let _embedpdf_plugin_search = require("@embedpdf/plugin-search");
|
|
8
|
+
//#region src/search.tsx
|
|
9
|
+
function SearchLayer({ color = "#ffd500", activeColor = "#ff9632", blendMode = "multiply" }) {
|
|
10
|
+
const page = require_runtime.usePage();
|
|
11
|
+
const hits = require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.hitsForPage(page.pon), require_runtime.shallowArray);
|
|
12
|
+
const active = require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.activeHit());
|
|
13
|
+
if (hits.length === 0) return null;
|
|
14
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15
|
+
style: {
|
|
16
|
+
position: "absolute",
|
|
17
|
+
inset: 0,
|
|
18
|
+
pointerEvents: "none"
|
|
19
|
+
},
|
|
20
|
+
children: hits.map((hit) => hit.rects.map((r, i) => {
|
|
21
|
+
const tl = page.transform.pageToContent({
|
|
22
|
+
x: r.x,
|
|
23
|
+
y: r.y
|
|
24
|
+
});
|
|
25
|
+
const br = page.transform.pageToContent({
|
|
26
|
+
x: r.x + r.width,
|
|
27
|
+
y: r.y + r.height
|
|
28
|
+
});
|
|
29
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
30
|
+
position: "absolute",
|
|
31
|
+
left: tl.x,
|
|
32
|
+
top: tl.y,
|
|
33
|
+
width: br.x - tl.x,
|
|
34
|
+
height: br.y - tl.y,
|
|
35
|
+
background: hit === active ? activeColor : color,
|
|
36
|
+
mixBlendMode: blendMode,
|
|
37
|
+
borderRadius: 2
|
|
38
|
+
} }, `${hit.charStart}:${i}`);
|
|
39
|
+
}))
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** The search capability (search/clear/next/prev/…) for app chrome. */
|
|
43
|
+
function useSearch() {
|
|
44
|
+
return require_runtime.useCapability(_embedpdf_plugin_search.SearchToken);
|
|
45
|
+
}
|
|
46
|
+
/** Reactive search read-model for chrome: the query, status, counts, progress. */
|
|
47
|
+
function useSearchState() {
|
|
48
|
+
return {
|
|
49
|
+
query: require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.query()),
|
|
50
|
+
status: require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.status()),
|
|
51
|
+
hitCount: require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.hitCount()),
|
|
52
|
+
activeIndex: require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.activeIndex()),
|
|
53
|
+
progress: require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.progress(), (a, b) => a.scanned === b.scanned && a.total === b.total),
|
|
54
|
+
error: require_runtime.useSelector(_embedpdf_plugin_search.SearchToken, (c) => c.errorMessage())
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
exports.SearchLayer = SearchLayer;
|
|
59
|
+
exports.useSearch = useSearch;
|
|
60
|
+
exports.useSearchState = useSearchState;
|
|
61
|
+
Object.keys(_embedpdf_plugin_search).forEach(function(k) {
|
|
62
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
get: function() {
|
|
65
|
+
return _embedpdf_plugin_search[k];
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=search.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.cjs","names":["usePage","useSelector","SearchToken","shallowArray","useCapability"],"sources":["../src/search.tsx"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-search.\n *\n * <SearchLayer> is a dumb renderer, the SelectionLayer's twin: it reads\n * the page's content-space hit rects from the capability and paints them\n * through PageContext.pageToContent. The active hit gets its own colour.\n * No pointer handling, no engine calls — search is driven from app chrome\n * via useSearch().\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-search';\nimport * as React from 'react';\nimport { SearchToken } from '@embedpdf/plugin-search';\nimport type { SearchHit } from '@embedpdf/plugin-search';\nimport { shallowArray, useCapability, usePage, useSelector } from './runtime';\n\nexport interface SearchLayerProps {\n /** Highlight colour for hits — SOLID (default: highlighter yellow). */\n color?: string;\n /** Highlight colour for the ACTIVE hit — SOLID (default: orange). */\n activeColor?: string;\n /**\n * How the highlight composites with the page. `'multiply'` (default) is\n * the real-highlighter look: text stays crisp black through the colour,\n * only the paper tints. Pass `'normal'` (with translucent colours) for\n * dark/scanned documents where multiply-on-dark would vanish.\n */\n blendMode?: React.CSSProperties['mixBlendMode'];\n}\n\nexport function SearchLayer({\n color = '#ffd500',\n activeColor = '#ff9632',\n blendMode = 'multiply',\n}: SearchLayerProps) {\n const page = usePage();\n const hits = useSelector(SearchToken, (c) => c.hitsForPage(page.pon), shallowArray);\n const active = useSelector(SearchToken, (c) => c.activeHit());\n\n if (hits.length === 0) return null;\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {hits.map((hit: SearchHit) =>\n hit.rects.map((r, i) => {\n const tl = page.transform.pageToContent({ x: r.x, y: r.y });\n const br = page.transform.pageToContent({ x: r.x + r.width, y: r.y + r.height });\n return (\n <div\n key={`${hit.charStart}:${i}`}\n style={{\n position: 'absolute',\n left: tl.x,\n top: tl.y,\n width: br.x - tl.x,\n height: br.y - tl.y,\n background: hit === active ? activeColor : color,\n mixBlendMode: blendMode,\n borderRadius: 2,\n }}\n />\n );\n }),\n )}\n </div>\n );\n}\n\n/** The search capability (search/clear/next/prev/…) for app chrome. */\nexport function useSearch() {\n return useCapability(SearchToken);\n}\n\n/** Reactive search read-model for chrome: the query, status, counts, progress. */\nexport function useSearchState() {\n const query = useSelector(SearchToken, (c) => c.query());\n const status = useSelector(SearchToken, (c) => c.status());\n const hitCount = useSelector(SearchToken, (c) => c.hitCount());\n const activeIndex = useSelector(SearchToken, (c) => c.activeIndex());\n const progress = useSelector(\n SearchToken,\n (c) => c.progress(),\n (a, b) => a.scanned === b.scanned && a.total === b.total,\n );\n const error = useSelector(SearchToken, (c) => c.errorMessage());\n return { query, status, hitCount, activeIndex, progress, error };\n}\n"],"mappings":";;;;;;;;AA+BA,SAAgB,YAAY,EAC1B,QAAQ,WACR,cAAc,WACd,YAAY,cACO;CACnB,MAAM,OAAOA,gBAAAA,QAAQ;CACrB,MAAM,OAAOC,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,YAAY,KAAK,GAAG,GAAGC,gBAAAA,YAAY;CAClF,MAAM,SAASF,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,UAAU,CAAC;CAE5D,IAAI,KAAK,WAAW,GAAG,OAAO;CAE9B,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,OAAO;GAAE,UAAU;GAAY,OAAO;GAAG,eAAe;EAAO;EACjE,UAAA,KAAK,KAAK,QACT,IAAI,MAAM,KAAK,GAAG,MAAM;GACtB,MAAM,KAAK,KAAK,UAAU,cAAc;IAAE,GAAG,EAAE;IAAG,GAAG,EAAE;GAAE,CAAC;GAC1D,MAAM,KAAK,KAAK,UAAU,cAAc;IAAE,GAAG,EAAE,IAAI,EAAE;IAAO,GAAG,EAAE,IAAI,EAAE;GAAO,CAAC;GAC/E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAEE,OAAO;IACL,UAAU;IACV,MAAM,GAAG;IACT,KAAK,GAAG;IACR,OAAO,GAAG,IAAI,GAAG;IACjB,QAAQ,GAAG,IAAI,GAAG;IAClB,YAAY,QAAQ,SAAS,cAAc;IAC3C,cAAc;IACd,cAAc;GAChB,EACD,GAXM,GAAG,IAAI,UAAU,GAAG,GAW1B;EAEL,CAAC,CACH;CACG,CAAA;AAET;;AAGA,SAAgB,YAAY;CAC1B,OAAOE,gBAAAA,cAAcF,wBAAAA,WAAW;AAClC;;AAGA,SAAgB,iBAAiB;CAW/B,OAAO;EAAE,OAVKD,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,MAAM,CAUzC;EAAG,QATDD,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,OAAO,CASnC;EAAG,UARPD,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,SAAS,CAQ7B;EAAG,aAPdD,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,YAAY,CAOtB;EAAG,UAN9BD,gBAAAA,YACfC,wBAAAA,cACC,MAAM,EAAE,SAAS,IACjB,GAAG,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,KAGC;EAAG,OAD3CD,gBAAAA,YAAYC,wBAAAA,cAAc,MAAM,EAAE,aAAa,CACA;CAAE;AACjE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { r as SearchQuery } from "./AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.cjs";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export * from "@embedpdf/plugin-search";
|
|
4
|
+
//#region src/search.d.ts
|
|
5
|
+
interface SearchLayerProps {
|
|
6
|
+
/** Highlight colour for hits — SOLID (default: highlighter yellow). */
|
|
7
|
+
color?: string;
|
|
8
|
+
/** Highlight colour for the ACTIVE hit — SOLID (default: orange). */
|
|
9
|
+
activeColor?: string;
|
|
10
|
+
/**
|
|
11
|
+
* How the highlight composites with the page. `'multiply'` (default) is
|
|
12
|
+
* the real-highlighter look: text stays crisp black through the colour,
|
|
13
|
+
* only the paper tints. Pass `'normal'` (with translucent colours) for
|
|
14
|
+
* dark/scanned documents where multiply-on-dark would vanish.
|
|
15
|
+
*/
|
|
16
|
+
blendMode?: React.CSSProperties['mixBlendMode'];
|
|
17
|
+
}
|
|
18
|
+
declare function SearchLayer({ color, activeColor, blendMode }: SearchLayerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
19
|
+
/** The search capability (search/clear/next/prev/…) for app chrome. */
|
|
20
|
+
declare function useSearch(): import("@embedpdf/plugin-search").SearchCapability;
|
|
21
|
+
/** Reactive search read-model for chrome: the query, status, counts, progress. */
|
|
22
|
+
declare function useSearchState(): {
|
|
23
|
+
query: SearchQuery | null;
|
|
24
|
+
status: import("@embedpdf/plugin-search").SearchStatus;
|
|
25
|
+
hitCount: number;
|
|
26
|
+
activeIndex: number;
|
|
27
|
+
progress: {
|
|
28
|
+
scanned: number;
|
|
29
|
+
total: number;
|
|
30
|
+
};
|
|
31
|
+
error: string | null;
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { SearchLayer, SearchLayerProps, useSearch, useSearchState };
|
|
35
|
+
//# sourceMappingURL=search.d.cts.map
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { r as SearchQuery } from "./AnnotationListSnapshot-W0RCsyDE-dWna4TTJ.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export * from "@embedpdf/plugin-search";
|
|
4
|
+
//#region src/search.d.ts
|
|
5
|
+
interface SearchLayerProps {
|
|
6
|
+
/** Highlight colour for hits — SOLID (default: highlighter yellow). */
|
|
7
|
+
color?: string;
|
|
8
|
+
/** Highlight colour for the ACTIVE hit — SOLID (default: orange). */
|
|
9
|
+
activeColor?: string;
|
|
10
|
+
/**
|
|
11
|
+
* How the highlight composites with the page. `'multiply'` (default) is
|
|
12
|
+
* the real-highlighter look: text stays crisp black through the colour,
|
|
13
|
+
* only the paper tints. Pass `'normal'` (with translucent colours) for
|
|
14
|
+
* dark/scanned documents where multiply-on-dark would vanish.
|
|
15
|
+
*/
|
|
16
|
+
blendMode?: React.CSSProperties['mixBlendMode'];
|
|
17
|
+
}
|
|
18
|
+
declare function SearchLayer({ color, activeColor, blendMode }: SearchLayerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
19
|
+
/** The search capability (search/clear/next/prev/…) for app chrome. */
|
|
20
|
+
declare function useSearch(): import("@embedpdf/plugin-search").SearchCapability;
|
|
21
|
+
/** Reactive search read-model for chrome: the query, status, counts, progress. */
|
|
22
|
+
declare function useSearchState(): {
|
|
23
|
+
query: SearchQuery | null;
|
|
24
|
+
status: import("@embedpdf/plugin-search").SearchStatus;
|
|
25
|
+
hitCount: number;
|
|
26
|
+
activeIndex: number;
|
|
27
|
+
progress: {
|
|
28
|
+
scanned: number;
|
|
29
|
+
total: number;
|
|
30
|
+
};
|
|
31
|
+
error: string | null;
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { SearchLayer, SearchLayerProps, useSearch, useSearchState };
|
|
35
|
+
//# sourceMappingURL=search.d.ts.map
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { shallowArray, useCapability, usePage, useSelector } from "./runtime.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import "react";
|
|
4
|
+
import { SearchToken } from "@embedpdf/plugin-search";
|
|
5
|
+
export * from "@embedpdf/plugin-search";
|
|
6
|
+
//#region src/search.tsx
|
|
7
|
+
function SearchLayer({ color = "#ffd500", activeColor = "#ff9632", blendMode = "multiply" }) {
|
|
8
|
+
const page = usePage();
|
|
9
|
+
const hits = useSelector(SearchToken, (c) => c.hitsForPage(page.pon), shallowArray);
|
|
10
|
+
const active = useSelector(SearchToken, (c) => c.activeHit());
|
|
11
|
+
if (hits.length === 0) return null;
|
|
12
|
+
return /* @__PURE__ */ jsx("div", {
|
|
13
|
+
style: {
|
|
14
|
+
position: "absolute",
|
|
15
|
+
inset: 0,
|
|
16
|
+
pointerEvents: "none"
|
|
17
|
+
},
|
|
18
|
+
children: hits.map((hit) => hit.rects.map((r, i) => {
|
|
19
|
+
const tl = page.transform.pageToContent({
|
|
20
|
+
x: r.x,
|
|
21
|
+
y: r.y
|
|
22
|
+
});
|
|
23
|
+
const br = page.transform.pageToContent({
|
|
24
|
+
x: r.x + r.width,
|
|
25
|
+
y: r.y + r.height
|
|
26
|
+
});
|
|
27
|
+
return /* @__PURE__ */ jsx("div", { style: {
|
|
28
|
+
position: "absolute",
|
|
29
|
+
left: tl.x,
|
|
30
|
+
top: tl.y,
|
|
31
|
+
width: br.x - tl.x,
|
|
32
|
+
height: br.y - tl.y,
|
|
33
|
+
background: hit === active ? activeColor : color,
|
|
34
|
+
mixBlendMode: blendMode,
|
|
35
|
+
borderRadius: 2
|
|
36
|
+
} }, `${hit.charStart}:${i}`);
|
|
37
|
+
}))
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** The search capability (search/clear/next/prev/…) for app chrome. */
|
|
41
|
+
function useSearch() {
|
|
42
|
+
return useCapability(SearchToken);
|
|
43
|
+
}
|
|
44
|
+
/** Reactive search read-model for chrome: the query, status, counts, progress. */
|
|
45
|
+
function useSearchState() {
|
|
46
|
+
return {
|
|
47
|
+
query: useSelector(SearchToken, (c) => c.query()),
|
|
48
|
+
status: useSelector(SearchToken, (c) => c.status()),
|
|
49
|
+
hitCount: useSelector(SearchToken, (c) => c.hitCount()),
|
|
50
|
+
activeIndex: useSelector(SearchToken, (c) => c.activeIndex()),
|
|
51
|
+
progress: useSelector(SearchToken, (c) => c.progress(), (a, b) => a.scanned === b.scanned && a.total === b.total),
|
|
52
|
+
error: useSelector(SearchToken, (c) => c.errorMessage())
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { SearchLayer, useSearch, useSearchState };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","names":[],"sources":["../src/search.tsx"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-search.\n *\n * <SearchLayer> is a dumb renderer, the SelectionLayer's twin: it reads\n * the page's content-space hit rects from the capability and paints them\n * through PageContext.pageToContent. The active hit gets its own colour.\n * No pointer handling, no engine calls — search is driven from app chrome\n * via useSearch().\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-search';\nimport * as React from 'react';\nimport { SearchToken } from '@embedpdf/plugin-search';\nimport type { SearchHit } from '@embedpdf/plugin-search';\nimport { shallowArray, useCapability, usePage, useSelector } from './runtime';\n\nexport interface SearchLayerProps {\n /** Highlight colour for hits — SOLID (default: highlighter yellow). */\n color?: string;\n /** Highlight colour for the ACTIVE hit — SOLID (default: orange). */\n activeColor?: string;\n /**\n * How the highlight composites with the page. `'multiply'` (default) is\n * the real-highlighter look: text stays crisp black through the colour,\n * only the paper tints. Pass `'normal'` (with translucent colours) for\n * dark/scanned documents where multiply-on-dark would vanish.\n */\n blendMode?: React.CSSProperties['mixBlendMode'];\n}\n\nexport function SearchLayer({\n color = '#ffd500',\n activeColor = '#ff9632',\n blendMode = 'multiply',\n}: SearchLayerProps) {\n const page = usePage();\n const hits = useSelector(SearchToken, (c) => c.hitsForPage(page.pon), shallowArray);\n const active = useSelector(SearchToken, (c) => c.activeHit());\n\n if (hits.length === 0) return null;\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {hits.map((hit: SearchHit) =>\n hit.rects.map((r, i) => {\n const tl = page.transform.pageToContent({ x: r.x, y: r.y });\n const br = page.transform.pageToContent({ x: r.x + r.width, y: r.y + r.height });\n return (\n <div\n key={`${hit.charStart}:${i}`}\n style={{\n position: 'absolute',\n left: tl.x,\n top: tl.y,\n width: br.x - tl.x,\n height: br.y - tl.y,\n background: hit === active ? activeColor : color,\n mixBlendMode: blendMode,\n borderRadius: 2,\n }}\n />\n );\n }),\n )}\n </div>\n );\n}\n\n/** The search capability (search/clear/next/prev/…) for app chrome. */\nexport function useSearch() {\n return useCapability(SearchToken);\n}\n\n/** Reactive search read-model for chrome: the query, status, counts, progress. */\nexport function useSearchState() {\n const query = useSelector(SearchToken, (c) => c.query());\n const status = useSelector(SearchToken, (c) => c.status());\n const hitCount = useSelector(SearchToken, (c) => c.hitCount());\n const activeIndex = useSelector(SearchToken, (c) => c.activeIndex());\n const progress = useSelector(\n SearchToken,\n (c) => c.progress(),\n (a, b) => a.scanned === b.scanned && a.total === b.total,\n );\n const error = useSelector(SearchToken, (c) => c.errorMessage());\n return { query, status, hitCount, activeIndex, progress, error };\n}\n"],"mappings":";;;;;;AA+BA,SAAgB,YAAY,EAC1B,QAAQ,WACR,cAAc,WACd,YAAY,cACO;CACnB,MAAM,OAAO,QAAQ;CACrB,MAAM,OAAO,YAAY,cAAc,MAAM,EAAE,YAAY,KAAK,GAAG,GAAG,YAAY;CAClF,MAAM,SAAS,YAAY,cAAc,MAAM,EAAE,UAAU,CAAC;CAE5D,IAAI,KAAK,WAAW,GAAG,OAAO;CAE9B,OACE,oBAAC,OAAD;EAAK,OAAO;GAAE,UAAU;GAAY,OAAO;GAAG,eAAe;EAAO;EACjE,UAAA,KAAK,KAAK,QACT,IAAI,MAAM,KAAK,GAAG,MAAM;GACtB,MAAM,KAAK,KAAK,UAAU,cAAc;IAAE,GAAG,EAAE;IAAG,GAAG,EAAE;GAAE,CAAC;GAC1D,MAAM,KAAK,KAAK,UAAU,cAAc;IAAE,GAAG,EAAE,IAAI,EAAE;IAAO,GAAG,EAAE,IAAI,EAAE;GAAO,CAAC;GAC/E,OACE,oBAAC,OAAD,EAEE,OAAO;IACL,UAAU;IACV,MAAM,GAAG;IACT,KAAK,GAAG;IACR,OAAO,GAAG,IAAI,GAAG;IACjB,QAAQ,GAAG,IAAI,GAAG;IAClB,YAAY,QAAQ,SAAS,cAAc;IAC3C,cAAc;IACd,cAAc;GAChB,EACD,GAXM,GAAG,IAAI,UAAU,GAAG,GAW1B;EAEL,CAAC,CACH;CACG,CAAA;AAET;;AAGA,SAAgB,YAAY;CAC1B,OAAO,cAAc,WAAW;AAClC;;AAGA,SAAgB,iBAAiB;CAW/B,OAAO;EAAE,OAVK,YAAY,cAAc,MAAM,EAAE,MAAM,CAUzC;EAAG,QATD,YAAY,cAAc,MAAM,EAAE,OAAO,CASnC;EAAG,UARP,YAAY,cAAc,MAAM,EAAE,SAAS,CAQ7B;EAAG,aAPd,YAAY,cAAc,MAAM,EAAE,YAAY,CAOtB;EAAG,UAN9B,YACf,cACC,MAAM,EAAE,SAAS,IACjB,GAAG,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,KAGC;EAAG,OAD3C,YAAY,cAAc,MAAM,EAAE,aAAa,CACA;CAAE;AACjE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_rolldown_runtime = require("./rolldown-runtime-DDXJien1.cjs");
|
|
3
|
+
const require_runtime = require("./runtime.cjs");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
react = require_rolldown_runtime.__toESM(react, 1);
|
|
7
|
+
let _embedpdf_plugin_selection = require("@embedpdf/plugin-selection");
|
|
8
|
+
//#region src/selection.tsx
|
|
9
|
+
function SelectionLayer({ color = "rgba(33, 150, 243, 0.35)" }) {
|
|
10
|
+
const page = require_runtime.usePage();
|
|
11
|
+
const selection = require_runtime.useCapability(_embedpdf_plugin_selection.SelectionToken);
|
|
12
|
+
const rects = require_runtime.useSelector(_embedpdf_plugin_selection.SelectionToken, (c) => c.rectsForPage(page.pon), require_runtime.shallowArray);
|
|
13
|
+
const visible = require_runtime.useSelector(_embedpdf_plugin_selection.SelectionToken, (c) => c.highlightVisible());
|
|
14
|
+
(0, react.useEffect)(() => {
|
|
15
|
+
selection.ensurePage(page.pon);
|
|
16
|
+
}, [selection, page.pon]);
|
|
17
|
+
if (!visible) return null;
|
|
18
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
19
|
+
style: {
|
|
20
|
+
position: "absolute",
|
|
21
|
+
inset: 0,
|
|
22
|
+
pointerEvents: "none"
|
|
23
|
+
},
|
|
24
|
+
children: rects.map((r, i) => {
|
|
25
|
+
const tl = page.transform.pageToContent({
|
|
26
|
+
x: r.x,
|
|
27
|
+
y: r.y
|
|
28
|
+
});
|
|
29
|
+
const br = page.transform.pageToContent({
|
|
30
|
+
x: r.x + r.width,
|
|
31
|
+
y: r.y + r.height
|
|
32
|
+
});
|
|
33
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
34
|
+
position: "absolute",
|
|
35
|
+
left: tl.x,
|
|
36
|
+
top: tl.y,
|
|
37
|
+
width: br.x - tl.x,
|
|
38
|
+
height: br.y - tl.y,
|
|
39
|
+
background: color
|
|
40
|
+
} }, i);
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** The selection capability (clear(), hasSelection(), …) for app chrome. */
|
|
45
|
+
function useSelection() {
|
|
46
|
+
return require_runtime.useCapability(_embedpdf_plugin_selection.SelectionToken);
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
exports.SelectionLayer = SelectionLayer;
|
|
50
|
+
exports.useSelection = useSelection;
|
|
51
|
+
Object.keys(_embedpdf_plugin_selection).forEach(function(k) {
|
|
52
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: function() {
|
|
55
|
+
return _embedpdf_plugin_selection[k];
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=selection.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.cjs","names":["usePage","useCapability","SelectionToken","useSelector","shallowArray"],"sources":["../src/selection.tsx"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-selection.\n *\n * <SelectionLayer> is a dumb renderer: it warms the page's geometry on mount,\n * reads the content-space highlight rects from the capability, and paints them —\n * mapping each rect through PageContext.pageToContent (the same path markers use).\n * Zero pointer handling here; that's the PagePointerSource + the hub.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-selection';\nimport * as React from 'react';\nimport { useEffect } from 'react';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport { shallowArray, useCapability, usePage, useSelector } from './runtime';\n\nexport interface SelectionLayerProps {\n /** Highlight colour (default: translucent blue). */\n color?: string;\n}\n\nexport function SelectionLayer({ color = 'rgba(33, 150, 243, 0.35)' }: SelectionLayerProps) {\n const page = usePage();\n const selection = useCapability(SelectionToken);\n const rects = useSelector(SelectionToken, (c) => c.rectsForPage(page.pon), shallowArray);\n // A consumer (e.g. a markup tool drawing its own preview) can take over the\n // selection visual; when it does, we render nothing so the two never overlap.\n const visible = useSelector(SelectionToken, (c) => c.highlightVisible());\n\n // Warm this page's text geometry as soon as it's on screen, so the first\n // pointer-down can hit-test without waiting on the engine round-trip.\n useEffect(() => {\n selection.ensurePage(page.pon);\n }, [selection, page.pon]);\n\n if (!visible) return null;\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {rects.map((r, i) => {\n // content space → un-rotated content view px (rides the page's CSS rotation)\n const tl = page.transform.pageToContent({ x: r.x, y: r.y });\n const br = page.transform.pageToContent({ x: r.x + r.width, y: r.y + r.height });\n return (\n <div\n key={i}\n style={{\n position: 'absolute',\n left: tl.x,\n top: tl.y,\n width: br.x - tl.x,\n height: br.y - tl.y,\n background: color,\n }}\n />\n );\n })}\n </div>\n );\n}\n\n/** The selection capability (clear(), hasSelection(), …) for app chrome. */\nexport function useSelection() {\n return useCapability(SelectionToken);\n}\n"],"mappings":";;;;;;;;AAqBA,SAAgB,eAAe,EAAE,QAAQ,8BAAmD;CAC1F,MAAM,OAAOA,gBAAAA,QAAQ;CACrB,MAAM,YAAYC,gBAAAA,cAAcC,2BAAAA,cAAc;CAC9C,MAAM,QAAQC,gBAAAA,YAAYD,2BAAAA,iBAAiB,MAAM,EAAE,aAAa,KAAK,GAAG,GAAGE,gBAAAA,YAAY;CAGvF,MAAM,UAAUD,gBAAAA,YAAYD,2BAAAA,iBAAiB,MAAM,EAAE,iBAAiB,CAAC;CAIvE,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,UAAU,WAAW,KAAK,GAAG;CAC/B,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC;CAExB,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,OAAO;GAAE,UAAU;GAAY,OAAO;GAAG,eAAe;EAAO;EACjE,UAAA,MAAM,KAAK,GAAG,MAAM;GAEnB,MAAM,KAAK,KAAK,UAAU,cAAc;IAAE,GAAG,EAAE;IAAG,GAAG,EAAE;GAAE,CAAC;GAC1D,MAAM,KAAK,KAAK,UAAU,cAAc;IAAE,GAAG,EAAE,IAAI,EAAE;IAAO,GAAG,EAAE,IAAI,EAAE;GAAO,CAAC;GAC/E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAEE,OAAO;IACL,UAAU;IACV,MAAM,GAAG;IACT,KAAK,GAAG;IACR,OAAO,GAAG,IAAI,GAAG;IACjB,QAAQ,GAAG,IAAI,GAAG;IAClB,YAAY;GACd,EACD,GATM,CASN;EAEL,CAAC;CACE,CAAA;AAET;;AAGA,SAAgB,eAAe;CAC7B,OAAOD,gBAAAA,cAAcC,2BAAAA,cAAc;AACrC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "@embedpdf/plugin-selection";
|
|
2
|
+
//#region src/selection.d.ts
|
|
3
|
+
interface SelectionLayerProps {
|
|
4
|
+
/** Highlight colour (default: translucent blue). */
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function SelectionLayer({ color }: SelectionLayerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
/** The selection capability (clear(), hasSelection(), …) for app chrome. */
|
|
9
|
+
declare function useSelection(): import("@embedpdf/plugin-selection").SelectionCapability;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { SelectionLayer, SelectionLayerProps, useSelection };
|
|
12
|
+
//# sourceMappingURL=selection.d.cts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "@embedpdf/plugin-selection";
|
|
2
|
+
//#region src/selection.d.ts
|
|
3
|
+
interface SelectionLayerProps {
|
|
4
|
+
/** Highlight colour (default: translucent blue). */
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function SelectionLayer({ color }: SelectionLayerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
/** The selection capability (clear(), hasSelection(), …) for app chrome. */
|
|
9
|
+
declare function useSelection(): import("@embedpdf/plugin-selection").SelectionCapability;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { SelectionLayer, SelectionLayerProps, useSelection };
|
|
12
|
+
//# sourceMappingURL=selection.d.ts.map
|