pdfjs-reader-core 0.5.7 → 0.5.8
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 +98 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -31
- package/dist/index.d.ts +14 -31
- package/dist/index.js +80 -147
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1858,40 +1858,19 @@ interface TutorModeContainerProps {
|
|
|
1858
1858
|
* Added in v0.4.2.
|
|
1859
1859
|
*/
|
|
1860
1860
|
onPageChange?: (page: number) => void;
|
|
1861
|
-
/**
|
|
1862
|
-
* PDF-points → CSS-pixels scale factor. Direct override: when set, the
|
|
1863
|
-
* tutor renders the PDF at exactly this scale regardless of source DPI.
|
|
1864
|
-
* Takes precedence over `scale` when both are passed.
|
|
1865
|
-
*
|
|
1866
|
-
* If neither `renderScale` nor `scale` is passed:
|
|
1867
|
-
* - Desktop (`pointer: fine`): defaults to `page.dpi / 72` — identical
|
|
1868
|
-
* to pre-v0.6 behavior.
|
|
1869
|
-
* - Touch (`pointer: coarse`): defaults to fit-to-viewport — much
|
|
1870
|
-
* smaller canvas on mobile, sidesteps the iOS Safari crash root
|
|
1871
|
-
* cause even when bbox data ships at very high source DPI.
|
|
1872
|
-
*
|
|
1873
|
-
* Added in v0.6.0.
|
|
1874
|
-
*/
|
|
1875
|
-
renderScale?: number;
|
|
1876
1861
|
className?: string;
|
|
1877
1862
|
}
|
|
1878
1863
|
/** Build a cross-page/block index from the raw bbox list. */
|
|
1879
1864
|
declare function buildBBoxIndex(bboxData: PageBBoxData[]): BBoxIndex;
|
|
1880
|
-
declare function TutorModeContainer({ pageNumber, bboxData, narrationStore, scale, rotation, currentChunk, llm, idleTimeoutMs, llmTimeoutMs, embeddingProvider, showSubtitles, showExitButton, onExitTutorMode, minOverlayDurationMs, backgroundColor, loadingComponent, onPageChange, storyboardProvider,
|
|
1865
|
+
declare function TutorModeContainer({ pageNumber, bboxData, narrationStore, scale, rotation, currentChunk, llm, idleTimeoutMs, llmTimeoutMs, embeddingProvider, showSubtitles, showExitButton, onExitTutorMode, minOverlayDurationMs, backgroundColor, loadingComponent, onPageChange, storyboardProvider, className, }: TutorModeContainerProps): react_jsx_runtime.JSX.Element;
|
|
1881
1866
|
|
|
1882
1867
|
interface CinemaLayerProps {
|
|
1883
1868
|
page: PageBBoxData;
|
|
1884
1869
|
index: BBoxIndex;
|
|
1885
1870
|
overlays: ActiveOverlay[];
|
|
1886
|
-
|
|
1887
|
-
* Factor converting source-DPI pixel coords (the bbox space every
|
|
1888
|
-
* overlay primitive uses internally) into CSS-pixel coords. Applied
|
|
1889
|
-
* as `transform: scale(coordScale)` on the outer element so individual
|
|
1890
|
-
* overlay components don't need to know about CSS vs DPI space.
|
|
1891
|
-
*/
|
|
1892
|
-
coordScale: number;
|
|
1871
|
+
scale: number;
|
|
1893
1872
|
}
|
|
1894
|
-
declare function CinemaLayer({ page, index, overlays,
|
|
1873
|
+
declare function CinemaLayer({ page, index, overlays, scale, }: CinemaLayerProps): react_jsx_runtime.JSX.Element;
|
|
1895
1874
|
|
|
1896
1875
|
interface CameraViewProps {
|
|
1897
1876
|
camera: CameraState;
|
|
@@ -2086,14 +2065,18 @@ declare class StoryboardEngine {
|
|
|
2086
2065
|
/** Cancel every removal timer (used by resetVisuals and destroy). */
|
|
2087
2066
|
private cancelAllRemovalTimers;
|
|
2088
2067
|
/**
|
|
2089
|
-
* Full destructor — cancels
|
|
2090
|
-
* timers. Use this in component unmount/cleanup.
|
|
2091
|
-
*
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
2068
|
+
* Full destructor — cancels BOTH pending step timers AND overlay
|
|
2069
|
+
* removal timers. Use this in component unmount / cleanup.
|
|
2070
|
+
*
|
|
2071
|
+
* The per-storyboard `cancelPending()` deliberately leaves overlay
|
|
2072
|
+
* removal timers alone so a mid-flight overlay doesn't get stranded
|
|
2073
|
+
* when a new storyboard arrives (see `overlayRemovalTimers` doc).
|
|
2074
|
+
* That invariant is correct inside a session, but at teardown we
|
|
2075
|
+
* must release every timer — otherwise their setTimeout closures
|
|
2094
2076
|
* keep `deps` (narrationStore, the full bboxIndex) alive beyond the
|
|
2095
|
-
* lifetime of this engine.
|
|
2096
|
-
*
|
|
2077
|
+
* lifetime of this engine. Over many component recreations on iOS
|
|
2078
|
+
* Safari (viewport state churns during address-bar scroll
|
|
2079
|
+
* animation), that cumulative retention contributes to tab reloads.
|
|
2097
2080
|
*/
|
|
2098
2081
|
destroy(): void;
|
|
2099
2082
|
/** Test-only — exposes internal queue sizes for regression tests. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1858,40 +1858,19 @@ interface TutorModeContainerProps {
|
|
|
1858
1858
|
* Added in v0.4.2.
|
|
1859
1859
|
*/
|
|
1860
1860
|
onPageChange?: (page: number) => void;
|
|
1861
|
-
/**
|
|
1862
|
-
* PDF-points → CSS-pixels scale factor. Direct override: when set, the
|
|
1863
|
-
* tutor renders the PDF at exactly this scale regardless of source DPI.
|
|
1864
|
-
* Takes precedence over `scale` when both are passed.
|
|
1865
|
-
*
|
|
1866
|
-
* If neither `renderScale` nor `scale` is passed:
|
|
1867
|
-
* - Desktop (`pointer: fine`): defaults to `page.dpi / 72` — identical
|
|
1868
|
-
* to pre-v0.6 behavior.
|
|
1869
|
-
* - Touch (`pointer: coarse`): defaults to fit-to-viewport — much
|
|
1870
|
-
* smaller canvas on mobile, sidesteps the iOS Safari crash root
|
|
1871
|
-
* cause even when bbox data ships at very high source DPI.
|
|
1872
|
-
*
|
|
1873
|
-
* Added in v0.6.0.
|
|
1874
|
-
*/
|
|
1875
|
-
renderScale?: number;
|
|
1876
1861
|
className?: string;
|
|
1877
1862
|
}
|
|
1878
1863
|
/** Build a cross-page/block index from the raw bbox list. */
|
|
1879
1864
|
declare function buildBBoxIndex(bboxData: PageBBoxData[]): BBoxIndex;
|
|
1880
|
-
declare function TutorModeContainer({ pageNumber, bboxData, narrationStore, scale, rotation, currentChunk, llm, idleTimeoutMs, llmTimeoutMs, embeddingProvider, showSubtitles, showExitButton, onExitTutorMode, minOverlayDurationMs, backgroundColor, loadingComponent, onPageChange, storyboardProvider,
|
|
1865
|
+
declare function TutorModeContainer({ pageNumber, bboxData, narrationStore, scale, rotation, currentChunk, llm, idleTimeoutMs, llmTimeoutMs, embeddingProvider, showSubtitles, showExitButton, onExitTutorMode, minOverlayDurationMs, backgroundColor, loadingComponent, onPageChange, storyboardProvider, className, }: TutorModeContainerProps): react_jsx_runtime.JSX.Element;
|
|
1881
1866
|
|
|
1882
1867
|
interface CinemaLayerProps {
|
|
1883
1868
|
page: PageBBoxData;
|
|
1884
1869
|
index: BBoxIndex;
|
|
1885
1870
|
overlays: ActiveOverlay[];
|
|
1886
|
-
|
|
1887
|
-
* Factor converting source-DPI pixel coords (the bbox space every
|
|
1888
|
-
* overlay primitive uses internally) into CSS-pixel coords. Applied
|
|
1889
|
-
* as `transform: scale(coordScale)` on the outer element so individual
|
|
1890
|
-
* overlay components don't need to know about CSS vs DPI space.
|
|
1891
|
-
*/
|
|
1892
|
-
coordScale: number;
|
|
1871
|
+
scale: number;
|
|
1893
1872
|
}
|
|
1894
|
-
declare function CinemaLayer({ page, index, overlays,
|
|
1873
|
+
declare function CinemaLayer({ page, index, overlays, scale, }: CinemaLayerProps): react_jsx_runtime.JSX.Element;
|
|
1895
1874
|
|
|
1896
1875
|
interface CameraViewProps {
|
|
1897
1876
|
camera: CameraState;
|
|
@@ -2086,14 +2065,18 @@ declare class StoryboardEngine {
|
|
|
2086
2065
|
/** Cancel every removal timer (used by resetVisuals and destroy). */
|
|
2087
2066
|
private cancelAllRemovalTimers;
|
|
2088
2067
|
/**
|
|
2089
|
-
* Full destructor — cancels
|
|
2090
|
-
* timers. Use this in component unmount/cleanup.
|
|
2091
|
-
*
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
2068
|
+
* Full destructor — cancels BOTH pending step timers AND overlay
|
|
2069
|
+
* removal timers. Use this in component unmount / cleanup.
|
|
2070
|
+
*
|
|
2071
|
+
* The per-storyboard `cancelPending()` deliberately leaves overlay
|
|
2072
|
+
* removal timers alone so a mid-flight overlay doesn't get stranded
|
|
2073
|
+
* when a new storyboard arrives (see `overlayRemovalTimers` doc).
|
|
2074
|
+
* That invariant is correct inside a session, but at teardown we
|
|
2075
|
+
* must release every timer — otherwise their setTimeout closures
|
|
2094
2076
|
* keep `deps` (narrationStore, the full bboxIndex) alive beyond the
|
|
2095
|
-
* lifetime of this engine.
|
|
2096
|
-
*
|
|
2077
|
+
* lifetime of this engine. Over many component recreations on iOS
|
|
2078
|
+
* Safari (viewport state churns during address-bar scroll
|
|
2079
|
+
* animation), that cumulative retention contributes to tab reloads.
|
|
2097
2080
|
*/
|
|
2098
2081
|
destroy(): void;
|
|
2099
2082
|
/** Test-only — exposes internal queue sizes for regression tests. */
|
package/dist/index.js
CHANGED
|
@@ -9154,7 +9154,7 @@ var init_DocumentContainer = __esm({
|
|
|
9154
9154
|
const containerRef = useRef16(null);
|
|
9155
9155
|
const documentRef = useRef16(null);
|
|
9156
9156
|
const baseScaleRef = useRef16(scale);
|
|
9157
|
-
const
|
|
9157
|
+
const isTouchDevice = useIsTouchDevice();
|
|
9158
9158
|
const documentLoadingState = useViewerStore((s) => s.documentLoadingState);
|
|
9159
9159
|
const { selection, clearSelection, copySelection } = useTextSelection();
|
|
9160
9160
|
const handlePinchZoom = useCallback29(
|
|
@@ -9185,7 +9185,7 @@ var init_DocumentContainer = __esm({
|
|
|
9185
9185
|
onSwipeLeft: handleSwipeLeft,
|
|
9186
9186
|
onSwipeRight: handleSwipeRight,
|
|
9187
9187
|
onDoubleTap: handleDoubleTap,
|
|
9188
|
-
enabled: enableTouchGestures &&
|
|
9188
|
+
enabled: enableTouchGestures && isTouchDevice,
|
|
9189
9189
|
swipeThreshold: 50,
|
|
9190
9190
|
doubleTapInterval: 300
|
|
9191
9191
|
});
|
|
@@ -9429,7 +9429,7 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
9429
9429
|
const pageCache = useRef17(/* @__PURE__ */ new Map());
|
|
9430
9430
|
const pageDimensionsCache = useRef17(/* @__PURE__ */ new Map());
|
|
9431
9431
|
const baseScaleRef = useRef17(scale);
|
|
9432
|
-
const
|
|
9432
|
+
const isTouchDevice = useIsTouchDevice();
|
|
9433
9433
|
const [visiblePages, setVisiblePages] = useState19([1]);
|
|
9434
9434
|
const [pageObjects, setPageObjects] = useState19(/* @__PURE__ */ new Map());
|
|
9435
9435
|
const [totalHeight, setTotalHeight] = useState19(0);
|
|
@@ -9632,7 +9632,7 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
9632
9632
|
onPinchZoom: handlePinchZoom,
|
|
9633
9633
|
onSwipeLeft: nextPage,
|
|
9634
9634
|
onSwipeRight: previousPage,
|
|
9635
|
-
enabled: enableTouchGestures &&
|
|
9635
|
+
enabled: enableTouchGestures && isTouchDevice
|
|
9636
9636
|
});
|
|
9637
9637
|
const setContainerRef = useCallback30(
|
|
9638
9638
|
(element) => {
|
|
@@ -9840,7 +9840,7 @@ var init_DualPageContainer = __esm({
|
|
|
9840
9840
|
const containerRef = useRef18(null);
|
|
9841
9841
|
const documentRef = useRef18(null);
|
|
9842
9842
|
const baseScaleRef = useRef18(scale);
|
|
9843
|
-
const
|
|
9843
|
+
const isTouchDevice = useIsTouchDevice();
|
|
9844
9844
|
const [leftPage, setLeftPage] = useState20(null);
|
|
9845
9845
|
const [rightPage, setRightPage] = useState20(null);
|
|
9846
9846
|
const [isLoading, setIsLoading] = useState20(false);
|
|
@@ -9983,7 +9983,7 @@ var init_DualPageContainer = __esm({
|
|
|
9983
9983
|
onPinchZoom: handlePinchZoom,
|
|
9984
9984
|
onSwipeLeft: goToNextSpread,
|
|
9985
9985
|
onSwipeRight: goToPreviousSpread,
|
|
9986
|
-
enabled: enableTouchGestures &&
|
|
9986
|
+
enabled: enableTouchGestures && isTouchDevice
|
|
9987
9987
|
});
|
|
9988
9988
|
const setContainerRef = useCallback31(
|
|
9989
9989
|
(element) => {
|
|
@@ -13374,13 +13374,13 @@ function AnimatedUnderline({ bbox, action }) {
|
|
|
13374
13374
|
const blotX = x2 + 4;
|
|
13375
13375
|
const blotY = y;
|
|
13376
13376
|
const strokeWeight = action.style === "wavy" ? 3 : 4;
|
|
13377
|
-
const
|
|
13378
|
-
const
|
|
13379
|
-
const
|
|
13380
|
-
const svgX = x1 -
|
|
13381
|
-
const svgY = y -
|
|
13382
|
-
const svgW = x2 - x1 + 2 *
|
|
13383
|
-
const svgH =
|
|
13377
|
+
const uxPad = 8;
|
|
13378
|
+
const uAbove = 8;
|
|
13379
|
+
const uBelow = 24;
|
|
13380
|
+
const svgX = x1 - uxPad;
|
|
13381
|
+
const svgY = y - uAbove;
|
|
13382
|
+
const svgW = x2 - x1 + 2 * uxPad;
|
|
13383
|
+
const svgH = uAbove + uBelow;
|
|
13384
13384
|
return /* @__PURE__ */ jsxs36(
|
|
13385
13385
|
"svg",
|
|
13386
13386
|
{
|
|
@@ -13455,7 +13455,12 @@ function AnimatedUnderline({ bbox, action }) {
|
|
|
13455
13455
|
// src/components/TutorMode/AnimatedHighlight.tsx
|
|
13456
13456
|
import { motion as motion4 } from "framer-motion";
|
|
13457
13457
|
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
13458
|
-
var
|
|
13458
|
+
var DEFAULT_HUE = "rgb(230, 180, 34)";
|
|
13459
|
+
var WASH_OPACITY = 0.28;
|
|
13460
|
+
function stripAlpha(color) {
|
|
13461
|
+
const m = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
|
|
13462
|
+
return m ? `rgb(${m[1]}, ${m[2]}, ${m[3]})` : color;
|
|
13463
|
+
}
|
|
13459
13464
|
function AnimatedHighlight({ bbox, action }) {
|
|
13460
13465
|
const [x1, y1, x2, y2] = bbox;
|
|
13461
13466
|
const h = Math.max(1, y2 - y1);
|
|
@@ -13464,7 +13469,7 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13464
13469
|
const yBot = y2 + bleed;
|
|
13465
13470
|
const duration = action.draw_duration_ms / 1e3;
|
|
13466
13471
|
const isDefaultColour = !action.color || action.color === "rgba(250, 204, 21, 0.35)" || action.color === "rgba(250,204,21,0.35)";
|
|
13467
|
-
const fill = isDefaultColour ?
|
|
13472
|
+
const fill = stripAlpha(isDefaultColour ? DEFAULT_HUE : action.color);
|
|
13468
13473
|
const taper = Math.min(6, h * 0.2);
|
|
13469
13474
|
const pathD = `
|
|
13470
13475
|
M ${x1 - 2} ${yTop + taper}
|
|
@@ -13477,11 +13482,11 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13477
13482
|
L ${x1 - 2} ${yBot - taper}
|
|
13478
13483
|
Z
|
|
13479
13484
|
`;
|
|
13480
|
-
const
|
|
13481
|
-
const svgX = x1 -
|
|
13482
|
-
const svgY = yTop -
|
|
13483
|
-
const svgW = x2 - x1 + 2 *
|
|
13484
|
-
const svgH = yBot - yTop + 2 *
|
|
13485
|
+
const svgPad = 8;
|
|
13486
|
+
const svgX = x1 - svgPad;
|
|
13487
|
+
const svgY = yTop - svgPad;
|
|
13488
|
+
const svgW = x2 - x1 + 2 * svgPad;
|
|
13489
|
+
const svgH = yBot - yTop + 2 * svgPad;
|
|
13485
13490
|
return /* @__PURE__ */ jsx44(
|
|
13486
13491
|
"svg",
|
|
13487
13492
|
{
|
|
@@ -13501,6 +13506,7 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13501
13506
|
{
|
|
13502
13507
|
d: pathD,
|
|
13503
13508
|
fill,
|
|
13509
|
+
fillOpacity: WASH_OPACITY,
|
|
13504
13510
|
initial: { clipPath: `inset(0 100% 0 0)` },
|
|
13505
13511
|
animate: { clipPath: `inset(0 0% 0 0)` },
|
|
13506
13512
|
exit: { opacity: 0 },
|
|
@@ -13512,7 +13518,6 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13512
13518
|
}
|
|
13513
13519
|
|
|
13514
13520
|
// src/components/TutorMode/PulseOverlay.tsx
|
|
13515
|
-
import { useId as useId2 } from "react";
|
|
13516
13521
|
import { motion as motion5 } from "framer-motion";
|
|
13517
13522
|
import { jsx as jsx45, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
13518
13523
|
var INTENSITY = {
|
|
@@ -13521,7 +13526,6 @@ var INTENSITY = {
|
|
|
13521
13526
|
strong: { bracketLen: 26, strokeWeight: 3, coreOpacity: 1, ringScale: 1.22 }
|
|
13522
13527
|
};
|
|
13523
13528
|
function PulseOverlay({ bbox, action }) {
|
|
13524
|
-
const pulseId = useId2();
|
|
13525
13529
|
const [x1, y1, x2, y2] = bbox;
|
|
13526
13530
|
const w = Math.max(1, x2 - x1);
|
|
13527
13531
|
const h = Math.max(1, y2 - y1);
|
|
@@ -13530,13 +13534,13 @@ function PulseOverlay({ bbox, action }) {
|
|
|
13530
13534
|
const spec = INTENSITY[action.intensity] ?? INTENSITY.normal;
|
|
13531
13535
|
const L = Math.min(spec.bracketLen, Math.min(w, h) / 2.5);
|
|
13532
13536
|
const PAD = 6;
|
|
13537
|
+
const ringExtentX = (w / 2 + PAD) * spec.ringScale - w / 2;
|
|
13538
|
+
const ringExtentY = (h / 2 + PAD) * spec.ringScale - h / 2;
|
|
13539
|
+
const glowExtentX = (w / 2 + 10) * spec.ringScale - w / 2 + 24;
|
|
13540
|
+
const glowExtentY = (h / 2 + 10) * spec.ringScale - h / 2 + 24;
|
|
13533
13541
|
const bracketExtent = PAD + L + 8;
|
|
13534
|
-
const
|
|
13535
|
-
const
|
|
13536
|
-
const glowExtentV = (h / 2 + 24) * spec.ringScale - h / 2;
|
|
13537
|
-
const ringExtentV = (h / 2 + PAD) * spec.ringScale - h / 2;
|
|
13538
|
-
const svgPadX = Math.ceil(Math.max(bracketExtent, glowExtent, ringExtent) + 4);
|
|
13539
|
-
const svgPadY = Math.ceil(Math.max(bracketExtent, glowExtentV, ringExtentV) + 4);
|
|
13542
|
+
const svgPadX = Math.ceil(Math.max(40, ringExtentX, glowExtentX, bracketExtent));
|
|
13543
|
+
const svgPadY = Math.ceil(Math.max(40, ringExtentY, glowExtentY, bracketExtent));
|
|
13540
13544
|
const svgX = x1 - svgPadX;
|
|
13541
13545
|
const svgY = y1 - svgPadY;
|
|
13542
13546
|
const svgW = w + 2 * svgPadX;
|
|
@@ -13556,22 +13560,18 @@ function PulseOverlay({ bbox, action }) {
|
|
|
13556
13560
|
},
|
|
13557
13561
|
"data-role": "pulse",
|
|
13558
13562
|
children: [
|
|
13559
|
-
/* @__PURE__ */ jsx45("defs", { children: /* @__PURE__ */ jsxs37("radialGradient", { id: `${pulseId}-glow`, cx: "50%", cy: "50%", r: "50%", children: [
|
|
13560
|
-
/* @__PURE__ */ jsx45("stop", { offset: "0%", stopColor: ACCENT_GLOW, stopOpacity: 1 }),
|
|
13561
|
-
/* @__PURE__ */ jsx45("stop", { offset: "60%", stopColor: ACCENT_GLOW, stopOpacity: 0.45 }),
|
|
13562
|
-
/* @__PURE__ */ jsx45("stop", { offset: "100%", stopColor: ACCENT_GLOW, stopOpacity: 0 })
|
|
13563
|
-
] }) }),
|
|
13564
13563
|
/* @__PURE__ */ jsx45(
|
|
13565
13564
|
motion5.ellipse,
|
|
13566
13565
|
{
|
|
13567
13566
|
cx,
|
|
13568
13567
|
cy,
|
|
13569
|
-
rx: w / 2 +
|
|
13570
|
-
ry: h / 2 +
|
|
13571
|
-
fill:
|
|
13568
|
+
rx: w / 2 + 10,
|
|
13569
|
+
ry: h / 2 + 10,
|
|
13570
|
+
fill: ACCENT_GLOW,
|
|
13572
13571
|
style: {
|
|
13573
13572
|
transformOrigin: `${cx}px ${cy}px`,
|
|
13574
|
-
transformBox: "fill-box"
|
|
13573
|
+
transformBox: "fill-box",
|
|
13574
|
+
filter: "blur(16px)"
|
|
13575
13575
|
},
|
|
13576
13576
|
initial: { opacity: 0, scale: 0.95 },
|
|
13577
13577
|
animate: {
|
|
@@ -13702,7 +13702,7 @@ function Bracket({
|
|
|
13702
13702
|
}
|
|
13703
13703
|
|
|
13704
13704
|
// src/components/TutorMode/CalloutArrow.tsx
|
|
13705
|
-
import { useId as
|
|
13705
|
+
import { useId as useId2 } from "react";
|
|
13706
13706
|
import { motion as motion6 } from "framer-motion";
|
|
13707
13707
|
import { jsx as jsx46, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
13708
13708
|
function centerOf(b) {
|
|
@@ -13740,7 +13740,7 @@ function arrowPath(from, to, curve) {
|
|
|
13740
13740
|
return `M ${from.x} ${from.y} Q ${cx} ${cy} ${to.x} ${to.y}`;
|
|
13741
13741
|
}
|
|
13742
13742
|
function CalloutArrow({ fromBbox, toBbox, action }) {
|
|
13743
|
-
const markerId =
|
|
13743
|
+
const markerId = useId2();
|
|
13744
13744
|
const glowId = `${markerId}-glow`;
|
|
13745
13745
|
const { from, to } = edgePoints(fromBbox, toBbox);
|
|
13746
13746
|
const d = arrowPath(from, to, action.curve);
|
|
@@ -13913,9 +13913,8 @@ function CinemaLayer({
|
|
|
13913
13913
|
page,
|
|
13914
13914
|
index,
|
|
13915
13915
|
overlays,
|
|
13916
|
-
|
|
13916
|
+
scale
|
|
13917
13917
|
}) {
|
|
13918
|
-
if (overlays.length === 0) return null;
|
|
13919
13918
|
return /* @__PURE__ */ jsx48(
|
|
13920
13919
|
"div",
|
|
13921
13920
|
{
|
|
@@ -13924,7 +13923,7 @@ function CinemaLayer({
|
|
|
13924
13923
|
position: "absolute",
|
|
13925
13924
|
inset: 0,
|
|
13926
13925
|
transformOrigin: "0 0",
|
|
13927
|
-
transform: `scale(${
|
|
13926
|
+
transform: `scale(${scale})`,
|
|
13928
13927
|
width: page.page_dimensions.width,
|
|
13929
13928
|
height: page.page_dimensions.height,
|
|
13930
13929
|
pointerEvents: "none",
|
|
@@ -14514,8 +14513,7 @@ function LabelOverlay({
|
|
|
14514
14513
|
index,
|
|
14515
14514
|
currentPage,
|
|
14516
14515
|
camera,
|
|
14517
|
-
viewport
|
|
14518
|
-
coordScale
|
|
14516
|
+
viewport
|
|
14519
14517
|
}) {
|
|
14520
14518
|
const labels = overlays.filter((o) => o.kind === "label");
|
|
14521
14519
|
const page = index.byPage.get(currentPage);
|
|
@@ -14542,8 +14540,7 @@ function LabelOverlay({
|
|
|
14542
14540
|
a.position,
|
|
14543
14541
|
page,
|
|
14544
14542
|
camera,
|
|
14545
|
-
viewport
|
|
14546
|
-
coordScale
|
|
14543
|
+
viewport
|
|
14547
14544
|
);
|
|
14548
14545
|
return /* @__PURE__ */ jsx52(
|
|
14549
14546
|
StickyLabel,
|
|
@@ -14557,7 +14554,7 @@ function LabelOverlay({
|
|
|
14557
14554
|
}
|
|
14558
14555
|
);
|
|
14559
14556
|
}
|
|
14560
|
-
function computeScreenAnchor(bbox, where, page, camera, viewport
|
|
14557
|
+
function computeScreenAnchor(bbox, where, page, camera, viewport) {
|
|
14561
14558
|
const [x1, y1, x2, y2] = bbox;
|
|
14562
14559
|
const pageCX = page.page_dimensions.width / 2;
|
|
14563
14560
|
const pageCY = page.page_dimensions.height / 2;
|
|
@@ -14583,8 +14580,8 @@ function computeScreenAnchor(bbox, where, page, camera, viewport, coordScale) {
|
|
|
14583
14580
|
px = (x1 + x2) / 2;
|
|
14584
14581
|
py = y1;
|
|
14585
14582
|
}
|
|
14586
|
-
const screenX = viewport.width / 2 + camera.x + (px - pageCX) *
|
|
14587
|
-
const screenY = viewport.height / 2 + camera.y + (py - pageCY) *
|
|
14583
|
+
const screenX = viewport.width / 2 + camera.x + (px - pageCX) * camera.scale;
|
|
14584
|
+
const screenY = viewport.height / 2 + camera.y + (py - pageCY) * camera.scale;
|
|
14588
14585
|
return { x: screenX, y: screenY };
|
|
14589
14586
|
}
|
|
14590
14587
|
|
|
@@ -14596,8 +14593,7 @@ function CalloutLabelOverlay({
|
|
|
14596
14593
|
index,
|
|
14597
14594
|
currentPage,
|
|
14598
14595
|
camera,
|
|
14599
|
-
viewport
|
|
14600
|
-
coordScale
|
|
14596
|
+
viewport
|
|
14601
14597
|
}) {
|
|
14602
14598
|
const callouts = overlays.filter(
|
|
14603
14599
|
(o) => o.kind === "callout" && o.action.label
|
|
@@ -14626,8 +14622,7 @@ function CalloutLabelOverlay({
|
|
|
14626
14622
|
toHit.block.bbox,
|
|
14627
14623
|
page,
|
|
14628
14624
|
camera,
|
|
14629
|
-
viewport
|
|
14630
|
-
coordScale
|
|
14625
|
+
viewport
|
|
14631
14626
|
);
|
|
14632
14627
|
return /* @__PURE__ */ jsx53(
|
|
14633
14628
|
CalloutLabelPill,
|
|
@@ -14642,7 +14637,7 @@ function CalloutLabelOverlay({
|
|
|
14642
14637
|
}
|
|
14643
14638
|
);
|
|
14644
14639
|
}
|
|
14645
|
-
function computePillAnchor(fromBbox, toBbox, page, camera, viewport
|
|
14640
|
+
function computePillAnchor(fromBbox, toBbox, page, camera, viewport) {
|
|
14646
14641
|
const aCX = (fromBbox[0] + fromBbox[2]) / 2;
|
|
14647
14642
|
const aCY = (fromBbox[1] + fromBbox[3]) / 2;
|
|
14648
14643
|
const bCX = (toBbox[0] + toBbox[2]) / 2;
|
|
@@ -14659,8 +14654,8 @@ function computePillAnchor(fromBbox, toBbox, page, camera, viewport, coordScale)
|
|
|
14659
14654
|
const toY = bCY - uy * bOff;
|
|
14660
14655
|
const pageCX = page.page_dimensions.width / 2;
|
|
14661
14656
|
const pageCY = page.page_dimensions.height / 2;
|
|
14662
|
-
const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) *
|
|
14663
|
-
const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) *
|
|
14657
|
+
const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) * camera.scale;
|
|
14658
|
+
const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) * camera.scale;
|
|
14664
14659
|
const isVertical = Math.abs(dy) >= Math.abs(dx);
|
|
14665
14660
|
const OFFSET = resolvePillOffset(viewport.width);
|
|
14666
14661
|
const MAX_PILL_W = resolveMaxPillW(viewport.width);
|
|
@@ -14803,41 +14798,6 @@ function SubtitleBar({ text }) {
|
|
|
14803
14798
|
) : null });
|
|
14804
14799
|
}
|
|
14805
14800
|
|
|
14806
|
-
// src/utils/render-scale.ts
|
|
14807
|
-
function computeFitScale(input) {
|
|
14808
|
-
const { pageWidthPt, pageHeightPt, viewport, paddingFactor = 0.95 } = input;
|
|
14809
|
-
if (!Number.isFinite(pageWidthPt) || !Number.isFinite(pageHeightPt) || pageWidthPt <= 0 || pageHeightPt <= 0) {
|
|
14810
|
-
return 1;
|
|
14811
|
-
}
|
|
14812
|
-
const w = Math.max(1, viewport.width);
|
|
14813
|
-
const h = Math.max(1, viewport.height);
|
|
14814
|
-
const fit = Math.min(w / pageWidthPt, h / pageHeightPt) * paddingFactor;
|
|
14815
|
-
return Number.isFinite(fit) && fit > 0 ? fit : 1;
|
|
14816
|
-
}
|
|
14817
|
-
function computeCoordScale(input) {
|
|
14818
|
-
const { renderScale, dpi } = input;
|
|
14819
|
-
if (!Number.isFinite(renderScale) || renderScale <= 0) return 0;
|
|
14820
|
-
if (!Number.isFinite(dpi) || dpi <= 0) return 1;
|
|
14821
|
-
return renderScale * 72 / dpi;
|
|
14822
|
-
}
|
|
14823
|
-
function isTouchDevice() {
|
|
14824
|
-
if (typeof window === "undefined") return false;
|
|
14825
|
-
if (typeof window.matchMedia !== "function") return false;
|
|
14826
|
-
try {
|
|
14827
|
-
return window.matchMedia("(pointer: coarse)").matches;
|
|
14828
|
-
} catch {
|
|
14829
|
-
return false;
|
|
14830
|
-
}
|
|
14831
|
-
}
|
|
14832
|
-
function resolveRenderScale(input) {
|
|
14833
|
-
const { renderScaleProp, scaleProp, defaultRenderScale } = input;
|
|
14834
|
-
if (Number.isFinite(renderScaleProp) && renderScaleProp > 0) {
|
|
14835
|
-
return renderScaleProp;
|
|
14836
|
-
}
|
|
14837
|
-
const multiplier = Number.isFinite(scaleProp) && scaleProp > 0 ? scaleProp : 1;
|
|
14838
|
-
return defaultRenderScale * multiplier;
|
|
14839
|
-
}
|
|
14840
|
-
|
|
14841
14801
|
// src/director/storyboard-engine.ts
|
|
14842
14802
|
init_narration_store();
|
|
14843
14803
|
init_camera_math();
|
|
@@ -14934,14 +14894,18 @@ var StoryboardEngine = class {
|
|
|
14934
14894
|
this.overlayRemovalTimers.clear();
|
|
14935
14895
|
}
|
|
14936
14896
|
/**
|
|
14937
|
-
* Full destructor — cancels
|
|
14938
|
-
* timers. Use this in component unmount/cleanup.
|
|
14939
|
-
*
|
|
14940
|
-
*
|
|
14941
|
-
*
|
|
14897
|
+
* Full destructor — cancels BOTH pending step timers AND overlay
|
|
14898
|
+
* removal timers. Use this in component unmount / cleanup.
|
|
14899
|
+
*
|
|
14900
|
+
* The per-storyboard `cancelPending()` deliberately leaves overlay
|
|
14901
|
+
* removal timers alone so a mid-flight overlay doesn't get stranded
|
|
14902
|
+
* when a new storyboard arrives (see `overlayRemovalTimers` doc).
|
|
14903
|
+
* That invariant is correct inside a session, but at teardown we
|
|
14904
|
+
* must release every timer — otherwise their setTimeout closures
|
|
14942
14905
|
* keep `deps` (narrationStore, the full bboxIndex) alive beyond the
|
|
14943
|
-
* lifetime of this engine.
|
|
14944
|
-
*
|
|
14906
|
+
* lifetime of this engine. Over many component recreations on iOS
|
|
14907
|
+
* Safari (viewport state churns during address-bar scroll
|
|
14908
|
+
* animation), that cumulative retention contributes to tab reloads.
|
|
14945
14909
|
*/
|
|
14946
14910
|
destroy() {
|
|
14947
14911
|
this.cancelPending();
|
|
@@ -16094,7 +16058,6 @@ function TutorModeContainer({
|
|
|
16094
16058
|
loadingComponent,
|
|
16095
16059
|
onPageChange,
|
|
16096
16060
|
storyboardProvider,
|
|
16097
|
-
renderScale,
|
|
16098
16061
|
className
|
|
16099
16062
|
}) {
|
|
16100
16063
|
const containerRef = useRef27(null);
|
|
@@ -16109,27 +16072,6 @@ function TutorModeContainer({
|
|
|
16109
16072
|
const [viewport, setViewport] = useState30({ width: 800, height: 1e3 });
|
|
16110
16073
|
const camera = useStore2(narrationStore, (s) => s.camera);
|
|
16111
16074
|
const activeOverlays = useStore2(narrationStore, (s) => s.activeOverlays);
|
|
16112
|
-
const page = index.byPage.get(pageNumber);
|
|
16113
|
-
const pagePointsW = page ? page.page_dimensions.width * 72 / page.page_dimensions.dpi : 0;
|
|
16114
|
-
const pagePointsH = page ? page.page_dimensions.height * 72 / page.page_dimensions.dpi : 0;
|
|
16115
|
-
const touch = isTouchDevice();
|
|
16116
|
-
const defaultRenderScale = page ? touch ? computeFitScale({
|
|
16117
|
-
pageWidthPt: pagePointsW,
|
|
16118
|
-
pageHeightPt: pagePointsH,
|
|
16119
|
-
viewport
|
|
16120
|
-
}) : page.page_dimensions.dpi / 72 : 1;
|
|
16121
|
-
const effectiveRenderScale = resolveRenderScale({
|
|
16122
|
-
renderScaleProp: renderScale,
|
|
16123
|
-
scaleProp: scale,
|
|
16124
|
-
defaultRenderScale
|
|
16125
|
-
});
|
|
16126
|
-
const coordScale = page ? computeCoordScale({
|
|
16127
|
-
renderScale: effectiveRenderScale,
|
|
16128
|
-
dpi: page.page_dimensions.dpi
|
|
16129
|
-
}) : 1;
|
|
16130
|
-
const rasterScale = effectiveRenderScale;
|
|
16131
|
-
const baseW = pagePointsW * effectiveRenderScale;
|
|
16132
|
-
const baseH = pagePointsH * effectiveRenderScale;
|
|
16133
16075
|
useEffect28(() => {
|
|
16134
16076
|
if (numPages <= 0) return;
|
|
16135
16077
|
if (pageNumber < 1 || pageNumber > numPages) return;
|
|
@@ -16145,13 +16087,7 @@ function TutorModeContainer({
|
|
|
16145
16087
|
useEffect28(() => {
|
|
16146
16088
|
if (!containerRef.current) return;
|
|
16147
16089
|
const el = containerRef.current;
|
|
16148
|
-
const update = () => {
|
|
16149
|
-
const w = el.clientWidth;
|
|
16150
|
-
const h = el.clientHeight;
|
|
16151
|
-
setViewport(
|
|
16152
|
-
(prev) => prev.width === w && prev.height === h ? prev : { width: w, height: h }
|
|
16153
|
-
);
|
|
16154
|
-
};
|
|
16090
|
+
const update = () => setViewport({ width: el.clientWidth, height: el.clientHeight });
|
|
16155
16091
|
update();
|
|
16156
16092
|
const ro = new ResizeObserver(update);
|
|
16157
16093
|
ro.observe(el);
|
|
@@ -16179,29 +16115,23 @@ function TutorModeContainer({
|
|
|
16179
16115
|
const page2 = index.byPage.get(pageNumber);
|
|
16180
16116
|
if (!page2) return;
|
|
16181
16117
|
if (viewport.width === 0 || viewport.height === 0) return;
|
|
16182
|
-
if (baseW === 0 || baseH === 0) return;
|
|
16183
16118
|
if (narrationStore.getState().activeOverlays.length > 0) return;
|
|
16184
|
-
const fit = Math.min(
|
|
16119
|
+
const fit = Math.min(
|
|
16120
|
+
viewport.width / page2.page_dimensions.width,
|
|
16121
|
+
viewport.height / page2.page_dimensions.height
|
|
16122
|
+
) * 0.95;
|
|
16185
16123
|
narrationStore.getState().setCamera({ scale: fit, x: 0, y: 0 });
|
|
16186
|
-
}, [pageNumber, viewport, index, narrationStore
|
|
16187
|
-
const viewportRef = useRef27(viewport);
|
|
16188
|
-
useEffect28(() => {
|
|
16189
|
-
viewportRef.current = viewport;
|
|
16190
|
-
}, [viewport]);
|
|
16124
|
+
}, [pageNumber, viewport, index, narrationStore]);
|
|
16191
16125
|
const engineRef = useRef27(null);
|
|
16192
16126
|
useEffect28(() => {
|
|
16193
|
-
|
|
16127
|
+
engineRef.current = new StoryboardEngine({
|
|
16194
16128
|
narrationStore,
|
|
16195
16129
|
bboxIndex: index,
|
|
16196
|
-
getViewport: () =>
|
|
16130
|
+
getViewport: () => viewport,
|
|
16197
16131
|
minOverlayDurationMs
|
|
16198
16132
|
});
|
|
16199
|
-
engineRef.current
|
|
16200
|
-
|
|
16201
|
-
engine.destroy();
|
|
16202
|
-
if (engineRef.current === engine) engineRef.current = null;
|
|
16203
|
-
};
|
|
16204
|
-
}, [narrationStore, index, minOverlayDurationMs]);
|
|
16133
|
+
return () => engineRef.current?.destroy();
|
|
16134
|
+
}, [narrationStore, index, viewport, minOverlayDurationMs]);
|
|
16205
16135
|
const abortRef = useRef27(null);
|
|
16206
16136
|
const debounceRef = useRef27(null);
|
|
16207
16137
|
const lastChunkRef = useRef27(null);
|
|
@@ -16382,6 +16312,11 @@ function TutorModeContainer({
|
|
|
16382
16312
|
}, idleTimeoutMs + 100);
|
|
16383
16313
|
return () => clearTimeout(t);
|
|
16384
16314
|
}, [currentChunk, idleTimeoutMs, narrationStore]);
|
|
16315
|
+
const page = index.byPage.get(pageNumber);
|
|
16316
|
+
const dpiScale = page ? page.page_dimensions.dpi / 72 : 1;
|
|
16317
|
+
const rasterScale = dpiScale * (scale || 1);
|
|
16318
|
+
const baseW = page ? page.page_dimensions.width * (scale || 1) : 0;
|
|
16319
|
+
const baseH = page ? page.page_dimensions.height * (scale || 1) : 0;
|
|
16385
16320
|
const isReady = !!page && !!pageProxy;
|
|
16386
16321
|
return /* @__PURE__ */ jsxs41(
|
|
16387
16322
|
"div",
|
|
@@ -16460,7 +16395,7 @@ function TutorModeContainer({
|
|
|
16460
16395
|
page,
|
|
16461
16396
|
index,
|
|
16462
16397
|
overlays: activeOverlays,
|
|
16463
|
-
|
|
16398
|
+
scale: scale || 1
|
|
16464
16399
|
}
|
|
16465
16400
|
)
|
|
16466
16401
|
]
|
|
@@ -16473,8 +16408,7 @@ function TutorModeContainer({
|
|
|
16473
16408
|
index,
|
|
16474
16409
|
currentPage: pageNumber,
|
|
16475
16410
|
camera,
|
|
16476
|
-
viewport
|
|
16477
|
-
coordScale
|
|
16411
|
+
viewport
|
|
16478
16412
|
}
|
|
16479
16413
|
),
|
|
16480
16414
|
/* @__PURE__ */ jsx55(
|
|
@@ -16484,8 +16418,7 @@ function TutorModeContainer({
|
|
|
16484
16418
|
index,
|
|
16485
16419
|
currentPage: pageNumber,
|
|
16486
16420
|
camera,
|
|
16487
|
-
viewport
|
|
16488
|
-
coordScale
|
|
16421
|
+
viewport
|
|
16489
16422
|
}
|
|
16490
16423
|
),
|
|
16491
16424
|
/* @__PURE__ */ jsx55(GhostReferenceOverlay, { overlays: activeOverlays, index })
|