pdfjs-reader-core 0.5.6 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +208 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -4
- package/dist/index.d.ts +41 -4
- package/dist/index.js +226 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9191,7 +9191,7 @@ var init_DocumentContainer = __esm({
|
|
|
9191
9191
|
const containerRef = (0, import_react37.useRef)(null);
|
|
9192
9192
|
const documentRef = (0, import_react37.useRef)(null);
|
|
9193
9193
|
const baseScaleRef = (0, import_react37.useRef)(scale);
|
|
9194
|
-
const
|
|
9194
|
+
const isTouchDevice2 = useIsTouchDevice();
|
|
9195
9195
|
const documentLoadingState = useViewerStore((s) => s.documentLoadingState);
|
|
9196
9196
|
const { selection, clearSelection, copySelection } = useTextSelection();
|
|
9197
9197
|
const handlePinchZoom = (0, import_react37.useCallback)(
|
|
@@ -9222,7 +9222,7 @@ var init_DocumentContainer = __esm({
|
|
|
9222
9222
|
onSwipeLeft: handleSwipeLeft,
|
|
9223
9223
|
onSwipeRight: handleSwipeRight,
|
|
9224
9224
|
onDoubleTap: handleDoubleTap,
|
|
9225
|
-
enabled: enableTouchGestures &&
|
|
9225
|
+
enabled: enableTouchGestures && isTouchDevice2,
|
|
9226
9226
|
swipeThreshold: 50,
|
|
9227
9227
|
doubleTapInterval: 300
|
|
9228
9228
|
});
|
|
@@ -9466,7 +9466,7 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
9466
9466
|
const pageCache = (0, import_react38.useRef)(/* @__PURE__ */ new Map());
|
|
9467
9467
|
const pageDimensionsCache = (0, import_react38.useRef)(/* @__PURE__ */ new Map());
|
|
9468
9468
|
const baseScaleRef = (0, import_react38.useRef)(scale);
|
|
9469
|
-
const
|
|
9469
|
+
const isTouchDevice2 = useIsTouchDevice();
|
|
9470
9470
|
const [visiblePages, setVisiblePages] = (0, import_react38.useState)([1]);
|
|
9471
9471
|
const [pageObjects, setPageObjects] = (0, import_react38.useState)(/* @__PURE__ */ new Map());
|
|
9472
9472
|
const [totalHeight, setTotalHeight] = (0, import_react38.useState)(0);
|
|
@@ -9669,7 +9669,7 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
9669
9669
|
onPinchZoom: handlePinchZoom,
|
|
9670
9670
|
onSwipeLeft: nextPage,
|
|
9671
9671
|
onSwipeRight: previousPage,
|
|
9672
|
-
enabled: enableTouchGestures &&
|
|
9672
|
+
enabled: enableTouchGestures && isTouchDevice2
|
|
9673
9673
|
});
|
|
9674
9674
|
const setContainerRef = (0, import_react38.useCallback)(
|
|
9675
9675
|
(element) => {
|
|
@@ -9877,7 +9877,7 @@ var init_DualPageContainer = __esm({
|
|
|
9877
9877
|
const containerRef = (0, import_react40.useRef)(null);
|
|
9878
9878
|
const documentRef = (0, import_react40.useRef)(null);
|
|
9879
9879
|
const baseScaleRef = (0, import_react40.useRef)(scale);
|
|
9880
|
-
const
|
|
9880
|
+
const isTouchDevice2 = useIsTouchDevice();
|
|
9881
9881
|
const [leftPage, setLeftPage] = (0, import_react40.useState)(null);
|
|
9882
9882
|
const [rightPage, setRightPage] = (0, import_react40.useState)(null);
|
|
9883
9883
|
const [isLoading, setIsLoading] = (0, import_react40.useState)(false);
|
|
@@ -10020,7 +10020,7 @@ var init_DualPageContainer = __esm({
|
|
|
10020
10020
|
onPinchZoom: handlePinchZoom,
|
|
10021
10021
|
onSwipeLeft: goToNextSpread,
|
|
10022
10022
|
onSwipeRight: goToPreviousSpread,
|
|
10023
|
-
enabled: enableTouchGestures &&
|
|
10023
|
+
enabled: enableTouchGestures && isTouchDevice2
|
|
10024
10024
|
});
|
|
10025
10025
|
const setContainerRef = (0, import_react40.useCallback)(
|
|
10026
10026
|
(element) => {
|
|
@@ -13559,12 +13559,23 @@ function AnimatedUnderline({ bbox, action }) {
|
|
|
13559
13559
|
const blotX = x2 + 4;
|
|
13560
13560
|
const blotY = y;
|
|
13561
13561
|
const strokeWeight = action.style === "wavy" ? 3 : 4;
|
|
13562
|
+
const xPad = 8;
|
|
13563
|
+
const yAbove = 8;
|
|
13564
|
+
const yBelow = 24;
|
|
13565
|
+
const svgX = x1 - xPad;
|
|
13566
|
+
const svgY = y - yAbove;
|
|
13567
|
+
const svgW = x2 - x1 + 2 * xPad;
|
|
13568
|
+
const svgH = yAbove + yBelow;
|
|
13562
13569
|
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
13563
13570
|
"svg",
|
|
13564
13571
|
{
|
|
13572
|
+
width: svgW,
|
|
13573
|
+
height: svgH,
|
|
13574
|
+
viewBox: `${svgX} ${svgY} ${svgW} ${svgH}`,
|
|
13565
13575
|
style: {
|
|
13566
13576
|
position: "absolute",
|
|
13567
|
-
|
|
13577
|
+
left: svgX,
|
|
13578
|
+
top: svgY,
|
|
13568
13579
|
pointerEvents: "none",
|
|
13569
13580
|
overflow: "visible"
|
|
13570
13581
|
},
|
|
@@ -13627,10 +13638,9 @@ function AnimatedUnderline({ bbox, action }) {
|
|
|
13627
13638
|
}
|
|
13628
13639
|
|
|
13629
13640
|
// src/components/TutorMode/AnimatedHighlight.tsx
|
|
13630
|
-
var import_react56 = require("react");
|
|
13631
13641
|
var import_framer_motion4 = require("framer-motion");
|
|
13632
13642
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
13633
|
-
var WASH = "rgba(
|
|
13643
|
+
var WASH = "rgba(195, 145, 10, 0.32)";
|
|
13634
13644
|
function AnimatedHighlight({ bbox, action }) {
|
|
13635
13645
|
const [x1, y1, x2, y2] = bbox;
|
|
13636
13646
|
const h = Math.max(1, y2 - y1);
|
|
@@ -13638,7 +13648,6 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13638
13648
|
const yTop = y1 - bleed;
|
|
13639
13649
|
const yBot = y2 + bleed;
|
|
13640
13650
|
const duration = action.draw_duration_ms / 1e3;
|
|
13641
|
-
const filterId = (0, import_react56.useId)();
|
|
13642
13651
|
const isDefaultColour = !action.color || action.color === "rgba(250, 204, 21, 0.35)" || action.color === "rgba(250,204,21,0.35)";
|
|
13643
13652
|
const fill = isDefaultColour ? WASH : action.color;
|
|
13644
13653
|
const taper = Math.min(6, h * 0.2);
|
|
@@ -13653,49 +13662,42 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13653
13662
|
L ${x1 - 2} ${yBot - taper}
|
|
13654
13663
|
Z
|
|
13655
13664
|
`;
|
|
13656
|
-
|
|
13665
|
+
const pad = 8;
|
|
13666
|
+
const svgX = x1 - pad;
|
|
13667
|
+
const svgY = yTop - pad;
|
|
13668
|
+
const svgW = x2 - x1 + 2 * pad;
|
|
13669
|
+
const svgH = yBot - yTop + 2 * pad;
|
|
13670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
13657
13671
|
"svg",
|
|
13658
13672
|
{
|
|
13673
|
+
width: svgW,
|
|
13674
|
+
height: svgH,
|
|
13675
|
+
viewBox: `${svgX} ${svgY} ${svgW} ${svgH}`,
|
|
13659
13676
|
style: {
|
|
13660
13677
|
position: "absolute",
|
|
13661
|
-
|
|
13678
|
+
left: svgX,
|
|
13679
|
+
top: svgY,
|
|
13662
13680
|
pointerEvents: "none",
|
|
13663
|
-
overflow: "visible"
|
|
13664
|
-
mixBlendMode: "multiply"
|
|
13681
|
+
overflow: "visible"
|
|
13665
13682
|
},
|
|
13666
13683
|
"data-role": "highlight",
|
|
13667
|
-
children:
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
),
|
|
13679
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("feDisplacementMap", { in: "SourceGraphic", in2: "noise", scale: 1 })
|
|
13680
|
-
] }) }),
|
|
13681
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
13682
|
-
import_framer_motion4.motion.path,
|
|
13683
|
-
{
|
|
13684
|
-
d: pathD,
|
|
13685
|
-
fill,
|
|
13686
|
-
initial: { clipPath: `inset(0 100% 0 0)` },
|
|
13687
|
-
animate: { clipPath: `inset(0 0% 0 0)` },
|
|
13688
|
-
exit: { opacity: 0 },
|
|
13689
|
-
filter: `url(#${filterId})`,
|
|
13690
|
-
transition: { duration, ease: EASE_OUT_EXPO }
|
|
13691
|
-
}
|
|
13692
|
-
)
|
|
13693
|
-
]
|
|
13684
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
13685
|
+
import_framer_motion4.motion.path,
|
|
13686
|
+
{
|
|
13687
|
+
d: pathD,
|
|
13688
|
+
fill,
|
|
13689
|
+
initial: { clipPath: `inset(0 100% 0 0)` },
|
|
13690
|
+
animate: { clipPath: `inset(0 0% 0 0)` },
|
|
13691
|
+
exit: { opacity: 0 },
|
|
13692
|
+
transition: { duration, ease: EASE_OUT_EXPO }
|
|
13693
|
+
}
|
|
13694
|
+
)
|
|
13694
13695
|
}
|
|
13695
13696
|
);
|
|
13696
13697
|
}
|
|
13697
13698
|
|
|
13698
13699
|
// src/components/TutorMode/PulseOverlay.tsx
|
|
13700
|
+
var import_react56 = require("react");
|
|
13699
13701
|
var import_framer_motion5 = require("framer-motion");
|
|
13700
13702
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
13701
13703
|
var INTENSITY = {
|
|
@@ -13704,6 +13706,7 @@ var INTENSITY = {
|
|
|
13704
13706
|
strong: { bracketLen: 26, strokeWeight: 3, coreOpacity: 1, ringScale: 1.22 }
|
|
13705
13707
|
};
|
|
13706
13708
|
function PulseOverlay({ bbox, action }) {
|
|
13709
|
+
const pulseId = (0, import_react56.useId)();
|
|
13707
13710
|
const [x1, y1, x2, y2] = bbox;
|
|
13708
13711
|
const w = Math.max(1, x2 - x1);
|
|
13709
13712
|
const h = Math.max(1, y2 - y1);
|
|
@@ -13712,29 +13715,48 @@ function PulseOverlay({ bbox, action }) {
|
|
|
13712
13715
|
const spec = INTENSITY[action.intensity] ?? INTENSITY.normal;
|
|
13713
13716
|
const L = Math.min(spec.bracketLen, Math.min(w, h) / 2.5);
|
|
13714
13717
|
const PAD = 6;
|
|
13718
|
+
const bracketExtent = PAD + L + 8;
|
|
13719
|
+
const glowExtent = (w / 2 + 24) * spec.ringScale - w / 2;
|
|
13720
|
+
const ringExtent = (w / 2 + PAD) * spec.ringScale - w / 2;
|
|
13721
|
+
const glowExtentV = (h / 2 + 24) * spec.ringScale - h / 2;
|
|
13722
|
+
const ringExtentV = (h / 2 + PAD) * spec.ringScale - h / 2;
|
|
13723
|
+
const svgPadX = Math.ceil(Math.max(bracketExtent, glowExtent, ringExtent) + 4);
|
|
13724
|
+
const svgPadY = Math.ceil(Math.max(bracketExtent, glowExtentV, ringExtentV) + 4);
|
|
13725
|
+
const svgX = x1 - svgPadX;
|
|
13726
|
+
const svgY = y1 - svgPadY;
|
|
13727
|
+
const svgW = w + 2 * svgPadX;
|
|
13728
|
+
const svgH = h + 2 * svgPadY;
|
|
13715
13729
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
13716
13730
|
"svg",
|
|
13717
13731
|
{
|
|
13732
|
+
width: svgW,
|
|
13733
|
+
height: svgH,
|
|
13734
|
+
viewBox: `${svgX} ${svgY} ${svgW} ${svgH}`,
|
|
13718
13735
|
style: {
|
|
13719
13736
|
position: "absolute",
|
|
13720
|
-
|
|
13737
|
+
left: svgX,
|
|
13738
|
+
top: svgY,
|
|
13721
13739
|
pointerEvents: "none",
|
|
13722
13740
|
overflow: "visible"
|
|
13723
13741
|
},
|
|
13724
13742
|
"data-role": "pulse",
|
|
13725
13743
|
children: [
|
|
13744
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("radialGradient", { id: `${pulseId}-glow`, cx: "50%", cy: "50%", r: "50%", children: [
|
|
13745
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("stop", { offset: "0%", stopColor: ACCENT_GLOW, stopOpacity: 1 }),
|
|
13746
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("stop", { offset: "60%", stopColor: ACCENT_GLOW, stopOpacity: 0.45 }),
|
|
13747
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("stop", { offset: "100%", stopColor: ACCENT_GLOW, stopOpacity: 0 })
|
|
13748
|
+
] }) }),
|
|
13726
13749
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
13727
13750
|
import_framer_motion5.motion.ellipse,
|
|
13728
13751
|
{
|
|
13729
13752
|
cx,
|
|
13730
13753
|
cy,
|
|
13731
|
-
rx: w / 2 +
|
|
13732
|
-
ry: h / 2 +
|
|
13733
|
-
fill:
|
|
13754
|
+
rx: w / 2 + 24,
|
|
13755
|
+
ry: h / 2 + 24,
|
|
13756
|
+
fill: `url(#${pulseId}-glow)`,
|
|
13734
13757
|
style: {
|
|
13735
13758
|
transformOrigin: `${cx}px ${cy}px`,
|
|
13736
|
-
transformBox: "fill-box"
|
|
13737
|
-
filter: "blur(16px)"
|
|
13759
|
+
transformBox: "fill-box"
|
|
13738
13760
|
},
|
|
13739
13761
|
initial: { opacity: 0, scale: 0.95 },
|
|
13740
13762
|
animate: {
|
|
@@ -13907,12 +13929,27 @@ function CalloutArrow({ fromBbox, toBbox, action }) {
|
|
|
13907
13929
|
const glowId = `${markerId}-glow`;
|
|
13908
13930
|
const { from, to } = edgePoints(fromBbox, toBbox);
|
|
13909
13931
|
const d = arrowPath(from, to, action.curve);
|
|
13932
|
+
const rawMinX = Math.min(from.x, to.x);
|
|
13933
|
+
const rawMinY = Math.min(from.y, to.y);
|
|
13934
|
+
const rawMaxX = Math.max(from.x, to.x);
|
|
13935
|
+
const rawMaxY = Math.max(from.y, to.y);
|
|
13936
|
+
const dist = Math.hypot(to.x - from.x, to.y - from.y);
|
|
13937
|
+
const arcDev = action.curve === "curved" ? dist * 0.12 : 0;
|
|
13938
|
+
const basePad = 16;
|
|
13939
|
+
const svgX = rawMinX - basePad - arcDev;
|
|
13940
|
+
const svgY = rawMinY - basePad - arcDev;
|
|
13941
|
+
const svgW = rawMaxX - rawMinX + 2 * (basePad + arcDev);
|
|
13942
|
+
const svgH = rawMaxY - rawMinY + 2 * (basePad + arcDev);
|
|
13910
13943
|
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
13911
13944
|
"svg",
|
|
13912
13945
|
{
|
|
13946
|
+
width: svgW,
|
|
13947
|
+
height: svgH,
|
|
13948
|
+
viewBox: `${svgX} ${svgY} ${svgW} ${svgH}`,
|
|
13913
13949
|
style: {
|
|
13914
13950
|
position: "absolute",
|
|
13915
|
-
|
|
13951
|
+
left: svgX,
|
|
13952
|
+
top: svgY,
|
|
13916
13953
|
pointerEvents: "none",
|
|
13917
13954
|
overflow: "visible"
|
|
13918
13955
|
},
|
|
@@ -14061,8 +14098,9 @@ function CinemaLayer({
|
|
|
14061
14098
|
page,
|
|
14062
14099
|
index,
|
|
14063
14100
|
overlays,
|
|
14064
|
-
|
|
14101
|
+
coordScale
|
|
14065
14102
|
}) {
|
|
14103
|
+
if (overlays.length === 0) return null;
|
|
14066
14104
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
14067
14105
|
"div",
|
|
14068
14106
|
{
|
|
@@ -14071,7 +14109,7 @@ function CinemaLayer({
|
|
|
14071
14109
|
position: "absolute",
|
|
14072
14110
|
inset: 0,
|
|
14073
14111
|
transformOrigin: "0 0",
|
|
14074
|
-
transform: `scale(${
|
|
14112
|
+
transform: `scale(${coordScale})`,
|
|
14075
14113
|
width: page.page_dimensions.width,
|
|
14076
14114
|
height: page.page_dimensions.height,
|
|
14077
14115
|
pointerEvents: "none",
|
|
@@ -14661,7 +14699,8 @@ function LabelOverlay({
|
|
|
14661
14699
|
index,
|
|
14662
14700
|
currentPage,
|
|
14663
14701
|
camera,
|
|
14664
|
-
viewport
|
|
14702
|
+
viewport,
|
|
14703
|
+
coordScale
|
|
14665
14704
|
}) {
|
|
14666
14705
|
const labels = overlays.filter((o) => o.kind === "label");
|
|
14667
14706
|
const page = index.byPage.get(currentPage);
|
|
@@ -14688,7 +14727,8 @@ function LabelOverlay({
|
|
|
14688
14727
|
a.position,
|
|
14689
14728
|
page,
|
|
14690
14729
|
camera,
|
|
14691
|
-
viewport
|
|
14730
|
+
viewport,
|
|
14731
|
+
coordScale
|
|
14692
14732
|
);
|
|
14693
14733
|
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
14694
14734
|
StickyLabel,
|
|
@@ -14702,7 +14742,7 @@ function LabelOverlay({
|
|
|
14702
14742
|
}
|
|
14703
14743
|
);
|
|
14704
14744
|
}
|
|
14705
|
-
function computeScreenAnchor(bbox, where, page, camera, viewport) {
|
|
14745
|
+
function computeScreenAnchor(bbox, where, page, camera, viewport, coordScale) {
|
|
14706
14746
|
const [x1, y1, x2, y2] = bbox;
|
|
14707
14747
|
const pageCX = page.page_dimensions.width / 2;
|
|
14708
14748
|
const pageCY = page.page_dimensions.height / 2;
|
|
@@ -14728,8 +14768,8 @@ function computeScreenAnchor(bbox, where, page, camera, viewport) {
|
|
|
14728
14768
|
px = (x1 + x2) / 2;
|
|
14729
14769
|
py = y1;
|
|
14730
14770
|
}
|
|
14731
|
-
const screenX = viewport.width / 2 + camera.x + (px - pageCX) * camera.scale;
|
|
14732
|
-
const screenY = viewport.height / 2 + camera.y + (py - pageCY) * camera.scale;
|
|
14771
|
+
const screenX = viewport.width / 2 + camera.x + (px - pageCX) * coordScale * camera.scale;
|
|
14772
|
+
const screenY = viewport.height / 2 + camera.y + (py - pageCY) * coordScale * camera.scale;
|
|
14733
14773
|
return { x: screenX, y: screenY };
|
|
14734
14774
|
}
|
|
14735
14775
|
|
|
@@ -14741,7 +14781,8 @@ function CalloutLabelOverlay({
|
|
|
14741
14781
|
index,
|
|
14742
14782
|
currentPage,
|
|
14743
14783
|
camera,
|
|
14744
|
-
viewport
|
|
14784
|
+
viewport,
|
|
14785
|
+
coordScale
|
|
14745
14786
|
}) {
|
|
14746
14787
|
const callouts = overlays.filter(
|
|
14747
14788
|
(o) => o.kind === "callout" && o.action.label
|
|
@@ -14770,7 +14811,8 @@ function CalloutLabelOverlay({
|
|
|
14770
14811
|
toHit.block.bbox,
|
|
14771
14812
|
page,
|
|
14772
14813
|
camera,
|
|
14773
|
-
viewport
|
|
14814
|
+
viewport,
|
|
14815
|
+
coordScale
|
|
14774
14816
|
);
|
|
14775
14817
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
14776
14818
|
CalloutLabelPill,
|
|
@@ -14785,7 +14827,7 @@ function CalloutLabelOverlay({
|
|
|
14785
14827
|
}
|
|
14786
14828
|
);
|
|
14787
14829
|
}
|
|
14788
|
-
function computePillAnchor(fromBbox, toBbox, page, camera, viewport) {
|
|
14830
|
+
function computePillAnchor(fromBbox, toBbox, page, camera, viewport, coordScale) {
|
|
14789
14831
|
const aCX = (fromBbox[0] + fromBbox[2]) / 2;
|
|
14790
14832
|
const aCY = (fromBbox[1] + fromBbox[3]) / 2;
|
|
14791
14833
|
const bCX = (toBbox[0] + toBbox[2]) / 2;
|
|
@@ -14802,8 +14844,8 @@ function computePillAnchor(fromBbox, toBbox, page, camera, viewport) {
|
|
|
14802
14844
|
const toY = bCY - uy * bOff;
|
|
14803
14845
|
const pageCX = page.page_dimensions.width / 2;
|
|
14804
14846
|
const pageCY = page.page_dimensions.height / 2;
|
|
14805
|
-
const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) * camera.scale;
|
|
14806
|
-
const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) * camera.scale;
|
|
14847
|
+
const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) * coordScale * camera.scale;
|
|
14848
|
+
const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) * coordScale * camera.scale;
|
|
14807
14849
|
const isVertical = Math.abs(dy) >= Math.abs(dx);
|
|
14808
14850
|
const OFFSET = resolvePillOffset(viewport.width);
|
|
14809
14851
|
const MAX_PILL_W = resolveMaxPillW(viewport.width);
|
|
@@ -14946,6 +14988,41 @@ function SubtitleBar({ text }) {
|
|
|
14946
14988
|
) : null });
|
|
14947
14989
|
}
|
|
14948
14990
|
|
|
14991
|
+
// src/utils/render-scale.ts
|
|
14992
|
+
function computeFitScale(input) {
|
|
14993
|
+
const { pageWidthPt, pageHeightPt, viewport, paddingFactor = 0.95 } = input;
|
|
14994
|
+
if (!Number.isFinite(pageWidthPt) || !Number.isFinite(pageHeightPt) || pageWidthPt <= 0 || pageHeightPt <= 0) {
|
|
14995
|
+
return 1;
|
|
14996
|
+
}
|
|
14997
|
+
const w = Math.max(1, viewport.width);
|
|
14998
|
+
const h = Math.max(1, viewport.height);
|
|
14999
|
+
const fit = Math.min(w / pageWidthPt, h / pageHeightPt) * paddingFactor;
|
|
15000
|
+
return Number.isFinite(fit) && fit > 0 ? fit : 1;
|
|
15001
|
+
}
|
|
15002
|
+
function computeCoordScale(input) {
|
|
15003
|
+
const { renderScale, dpi } = input;
|
|
15004
|
+
if (!Number.isFinite(renderScale) || renderScale <= 0) return 0;
|
|
15005
|
+
if (!Number.isFinite(dpi) || dpi <= 0) return 1;
|
|
15006
|
+
return renderScale * 72 / dpi;
|
|
15007
|
+
}
|
|
15008
|
+
function isTouchDevice() {
|
|
15009
|
+
if (typeof window === "undefined") return false;
|
|
15010
|
+
if (typeof window.matchMedia !== "function") return false;
|
|
15011
|
+
try {
|
|
15012
|
+
return window.matchMedia("(pointer: coarse)").matches;
|
|
15013
|
+
} catch {
|
|
15014
|
+
return false;
|
|
15015
|
+
}
|
|
15016
|
+
}
|
|
15017
|
+
function resolveRenderScale(input) {
|
|
15018
|
+
const { renderScaleProp, scaleProp, defaultRenderScale } = input;
|
|
15019
|
+
if (Number.isFinite(renderScaleProp) && renderScaleProp > 0) {
|
|
15020
|
+
return renderScaleProp;
|
|
15021
|
+
}
|
|
15022
|
+
const multiplier = Number.isFinite(scaleProp) && scaleProp > 0 ? scaleProp : 1;
|
|
15023
|
+
return defaultRenderScale * multiplier;
|
|
15024
|
+
}
|
|
15025
|
+
|
|
14949
15026
|
// src/director/storyboard-engine.ts
|
|
14950
15027
|
init_narration_store();
|
|
14951
15028
|
init_camera_math();
|
|
@@ -15036,11 +15113,32 @@ var StoryboardEngine = class {
|
|
|
15036
15113
|
this.pendingStepTimers.clear();
|
|
15037
15114
|
this.deps.narrationStore.getState().setEngineStatus("idle");
|
|
15038
15115
|
}
|
|
15039
|
-
/** Cancel every removal timer (used by resetVisuals
|
|
15116
|
+
/** Cancel every removal timer (used by resetVisuals and destroy). */
|
|
15040
15117
|
cancelAllRemovalTimers() {
|
|
15041
15118
|
for (const t of this.overlayRemovalTimers.values()) clearTimeout(t);
|
|
15042
15119
|
this.overlayRemovalTimers.clear();
|
|
15043
15120
|
}
|
|
15121
|
+
/**
|
|
15122
|
+
* Full destructor — cancels both pending step timers AND overlay removal
|
|
15123
|
+
* timers. Use this in component unmount/cleanup. The per-storyboard
|
|
15124
|
+
* `cancelPending()` deliberately leaves overlay removal timers alone so a
|
|
15125
|
+
* mid-flight overlay doesn't get stranded (see `overlayRemovalTimers` doc),
|
|
15126
|
+
* but at destruction time we must release every timer or their closures
|
|
15127
|
+
* keep `deps` (narrationStore, the full bboxIndex) alive beyond the
|
|
15128
|
+
* lifetime of this engine. On iOS Safari with many engine recreations
|
|
15129
|
+
* this causes cumulative memory pressure and eventual tab reload.
|
|
15130
|
+
*/
|
|
15131
|
+
destroy() {
|
|
15132
|
+
this.cancelPending();
|
|
15133
|
+
this.cancelAllRemovalTimers();
|
|
15134
|
+
}
|
|
15135
|
+
/** Test-only — exposes internal queue sizes for regression tests. */
|
|
15136
|
+
_queueSizesForTest() {
|
|
15137
|
+
return {
|
|
15138
|
+
pending: this.pendingStepTimers.size,
|
|
15139
|
+
removals: this.overlayRemovalTimers.size
|
|
15140
|
+
};
|
|
15141
|
+
}
|
|
15044
15142
|
/** Reset visuals: clear overlays, cancel every removal timer, fit camera. */
|
|
15045
15143
|
resetVisuals() {
|
|
15046
15144
|
this.cancelPending();
|
|
@@ -16181,6 +16279,7 @@ function TutorModeContainer({
|
|
|
16181
16279
|
loadingComponent,
|
|
16182
16280
|
onPageChange,
|
|
16183
16281
|
storyboardProvider,
|
|
16282
|
+
renderScale,
|
|
16184
16283
|
className
|
|
16185
16284
|
}) {
|
|
16186
16285
|
const containerRef = (0, import_react58.useRef)(null);
|
|
@@ -16195,6 +16294,27 @@ function TutorModeContainer({
|
|
|
16195
16294
|
const [viewport, setViewport] = (0, import_react58.useState)({ width: 800, height: 1e3 });
|
|
16196
16295
|
const camera = (0, import_zustand2.useStore)(narrationStore, (s) => s.camera);
|
|
16197
16296
|
const activeOverlays = (0, import_zustand2.useStore)(narrationStore, (s) => s.activeOverlays);
|
|
16297
|
+
const page = index.byPage.get(pageNumber);
|
|
16298
|
+
const pagePointsW = page ? page.page_dimensions.width * 72 / page.page_dimensions.dpi : 0;
|
|
16299
|
+
const pagePointsH = page ? page.page_dimensions.height * 72 / page.page_dimensions.dpi : 0;
|
|
16300
|
+
const touch = isTouchDevice();
|
|
16301
|
+
const defaultRenderScale = page ? touch ? computeFitScale({
|
|
16302
|
+
pageWidthPt: pagePointsW,
|
|
16303
|
+
pageHeightPt: pagePointsH,
|
|
16304
|
+
viewport
|
|
16305
|
+
}) : page.page_dimensions.dpi / 72 : 1;
|
|
16306
|
+
const effectiveRenderScale = resolveRenderScale({
|
|
16307
|
+
renderScaleProp: renderScale,
|
|
16308
|
+
scaleProp: scale,
|
|
16309
|
+
defaultRenderScale
|
|
16310
|
+
});
|
|
16311
|
+
const coordScale = page ? computeCoordScale({
|
|
16312
|
+
renderScale: effectiveRenderScale,
|
|
16313
|
+
dpi: page.page_dimensions.dpi
|
|
16314
|
+
}) : 1;
|
|
16315
|
+
const rasterScale = effectiveRenderScale;
|
|
16316
|
+
const baseW = pagePointsW * effectiveRenderScale;
|
|
16317
|
+
const baseH = pagePointsH * effectiveRenderScale;
|
|
16198
16318
|
(0, import_react58.useEffect)(() => {
|
|
16199
16319
|
if (numPages <= 0) return;
|
|
16200
16320
|
if (pageNumber < 1 || pageNumber > numPages) return;
|
|
@@ -16210,7 +16330,13 @@ function TutorModeContainer({
|
|
|
16210
16330
|
(0, import_react58.useEffect)(() => {
|
|
16211
16331
|
if (!containerRef.current) return;
|
|
16212
16332
|
const el = containerRef.current;
|
|
16213
|
-
const update = () =>
|
|
16333
|
+
const update = () => {
|
|
16334
|
+
const w = el.clientWidth;
|
|
16335
|
+
const h = el.clientHeight;
|
|
16336
|
+
setViewport(
|
|
16337
|
+
(prev) => prev.width === w && prev.height === h ? prev : { width: w, height: h }
|
|
16338
|
+
);
|
|
16339
|
+
};
|
|
16214
16340
|
update();
|
|
16215
16341
|
const ro = new ResizeObserver(update);
|
|
16216
16342
|
ro.observe(el);
|
|
@@ -16238,23 +16364,29 @@ function TutorModeContainer({
|
|
|
16238
16364
|
const page2 = index.byPage.get(pageNumber);
|
|
16239
16365
|
if (!page2) return;
|
|
16240
16366
|
if (viewport.width === 0 || viewport.height === 0) return;
|
|
16367
|
+
if (baseW === 0 || baseH === 0) return;
|
|
16241
16368
|
if (narrationStore.getState().activeOverlays.length > 0) return;
|
|
16242
|
-
const fit = Math.min(
|
|
16243
|
-
viewport.width / page2.page_dimensions.width,
|
|
16244
|
-
viewport.height / page2.page_dimensions.height
|
|
16245
|
-
) * 0.95;
|
|
16369
|
+
const fit = Math.min(viewport.width / baseW, viewport.height / baseH) * 0.95;
|
|
16246
16370
|
narrationStore.getState().setCamera({ scale: fit, x: 0, y: 0 });
|
|
16247
|
-
}, [pageNumber, viewport, index, narrationStore]);
|
|
16371
|
+
}, [pageNumber, viewport, index, narrationStore, baseW, baseH]);
|
|
16372
|
+
const viewportRef = (0, import_react58.useRef)(viewport);
|
|
16373
|
+
(0, import_react58.useEffect)(() => {
|
|
16374
|
+
viewportRef.current = viewport;
|
|
16375
|
+
}, [viewport]);
|
|
16248
16376
|
const engineRef = (0, import_react58.useRef)(null);
|
|
16249
16377
|
(0, import_react58.useEffect)(() => {
|
|
16250
|
-
|
|
16378
|
+
const engine = new StoryboardEngine({
|
|
16251
16379
|
narrationStore,
|
|
16252
16380
|
bboxIndex: index,
|
|
16253
|
-
getViewport: () =>
|
|
16381
|
+
getViewport: () => viewportRef.current,
|
|
16254
16382
|
minOverlayDurationMs
|
|
16255
16383
|
});
|
|
16256
|
-
|
|
16257
|
-
|
|
16384
|
+
engineRef.current = engine;
|
|
16385
|
+
return () => {
|
|
16386
|
+
engine.destroy();
|
|
16387
|
+
if (engineRef.current === engine) engineRef.current = null;
|
|
16388
|
+
};
|
|
16389
|
+
}, [narrationStore, index, minOverlayDurationMs]);
|
|
16258
16390
|
const abortRef = (0, import_react58.useRef)(null);
|
|
16259
16391
|
const debounceRef = (0, import_react58.useRef)(null);
|
|
16260
16392
|
const lastChunkRef = (0, import_react58.useRef)(null);
|
|
@@ -16435,11 +16567,6 @@ function TutorModeContainer({
|
|
|
16435
16567
|
}, idleTimeoutMs + 100);
|
|
16436
16568
|
return () => clearTimeout(t);
|
|
16437
16569
|
}, [currentChunk, idleTimeoutMs, narrationStore]);
|
|
16438
|
-
const page = index.byPage.get(pageNumber);
|
|
16439
|
-
const dpiScale = page ? page.page_dimensions.dpi / 72 : 1;
|
|
16440
|
-
const rasterScale = dpiScale * (scale || 1);
|
|
16441
|
-
const baseW = page ? page.page_dimensions.width * (scale || 1) : 0;
|
|
16442
|
-
const baseH = page ? page.page_dimensions.height * (scale || 1) : 0;
|
|
16443
16570
|
const isReady = !!page && !!pageProxy;
|
|
16444
16571
|
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
|
|
16445
16572
|
"div",
|
|
@@ -16518,7 +16645,7 @@ function TutorModeContainer({
|
|
|
16518
16645
|
page,
|
|
16519
16646
|
index,
|
|
16520
16647
|
overlays: activeOverlays,
|
|
16521
|
-
|
|
16648
|
+
coordScale
|
|
16522
16649
|
}
|
|
16523
16650
|
)
|
|
16524
16651
|
]
|
|
@@ -16531,7 +16658,8 @@ function TutorModeContainer({
|
|
|
16531
16658
|
index,
|
|
16532
16659
|
currentPage: pageNumber,
|
|
16533
16660
|
camera,
|
|
16534
|
-
viewport
|
|
16661
|
+
viewport,
|
|
16662
|
+
coordScale
|
|
16535
16663
|
}
|
|
16536
16664
|
),
|
|
16537
16665
|
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
@@ -16541,7 +16669,8 @@ function TutorModeContainer({
|
|
|
16541
16669
|
index,
|
|
16542
16670
|
currentPage: pageNumber,
|
|
16543
16671
|
camera,
|
|
16544
|
-
viewport
|
|
16672
|
+
viewport,
|
|
16673
|
+
coordScale
|
|
16545
16674
|
}
|
|
16546
16675
|
),
|
|
16547
16676
|
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(GhostReferenceOverlay, { overlays: activeOverlays, index })
|