generated from coulomb/repo-seed
Add Debug text layer toggle for diagnosing PDF selection issues
PDF text selection misbehaviour (some glyphs unselectable, selections
jumping to other positions) is almost always caused by misalignment
between the visible canvas-rendered glyphs and the invisible text
layer that PDF.js overlays for selection. There's no way to see this
without devtools — which makes it hard for end users to tell whether
a specific PDF is OCR-noisy, has bad font fallbacks, or has no text
layer at all.
This adds a developer-facing toggle in the SessionMenu ("Debug text
layer") that:
- paints every text-layer span yellow with a blue outline so it's
obvious where text is selectable and where it isn't, and
- logs every onSelection event to the browser console with the
captured text, page, normalized rects, and the selectors the
pipeline derived from it.
Preference persists in localStorage under
`citation-evidence:debug:textLayer`. Surfaced via a new
`useDebugFlag()` hook in @work so the SessionMenu (app layer) and the
ViewerShell (work layer) can both subscribe without breaching the
boundary plugin.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -22,12 +22,14 @@ import {
|
||||
useScrollToAnnotation,
|
||||
} from "./EngineContext";
|
||||
import { AnnotationToolbar } from "./AnnotationToolbar";
|
||||
import { useDebugFlag } from "./useDebugFlags";
|
||||
|
||||
export function ViewerShell() {
|
||||
const engine = useEngine();
|
||||
const { document, representation } = useActiveDocument();
|
||||
const { set: setPending } = usePendingSelection();
|
||||
const { id: scrollToId, version: scrollVersion } = useScrollToAnnotation();
|
||||
const [debugTextLayer] = useDebugFlag("textLayer");
|
||||
|
||||
// The viewer needs to re-fetch its highlight list whenever annotations
|
||||
// change. The tick is included in the memo deps so the list re-resolves.
|
||||
@@ -86,11 +88,15 @@ export function ViewerShell() {
|
||||
<div style={{ flex: 1, overflow: "hidden", position: "relative" }}>
|
||||
<PdfSpikeViewer
|
||||
// Re-key on scrollVersion so clicking the same item twice still
|
||||
// triggers the viewer's mount-time scroll effect.
|
||||
key={`${document.id}#${scrollVersion}`}
|
||||
// triggers the viewer's mount-time scroll effect. Also re-key on
|
||||
// debugTextLayer so toggling it remounts the viewer (the CSS
|
||||
// class is on a parent, but re-mounting is the simplest way to
|
||||
// make sure the text layer is re-painted with the new style).
|
||||
key={`${document.id}#${scrollVersion}#${debugTextLayer ? "d" : "n"}`}
|
||||
pdfUrl={fileUrl}
|
||||
storedAnnotations={annotations}
|
||||
{...(scrollToId ? { scrollToAnnotationId: scrollToId } : {})}
|
||||
debugTextLayer={debugTextLayer}
|
||||
onSelectionCaptured={(capture, selectors) => {
|
||||
setPending({ capture, selectors });
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user