a11y(desktop/pdf): struct-tree text layer + annotation tool shortcuts (#316)#342
Merged
Merged
Conversation
# Conflicts: # desktop/src/i18n/index.ts
physercoe
approved these changes
Jul 20, 2026
physercoe
left a comment
Owner
There was a problem hiding this comment.
APPROVE. Struct-tree/markedContent positioning faithfully mirrors pdf.js, overlay-bleed guard preserved, keydown listener uses the ref-latch pattern (no stale closure), and it fixes a pre-existing hardcoded aria-label. Rebased onto main and resolved the i18n + drilled-t→local-useT() merge (aligned PageView with main's new local-useT idiom). Minor to fold in later: includeMarkedContent: !readOnly so the split-view mirror pane does not emit duplicate DOM ids.
physercoe
pushed a commit
that referenced
this pull request
Jul 20, 2026
…ic-tail merges Since v0.3.79: - fix(terminal): tell xterm the pty is ConPTY on Windows so a repainting TUI's intermediate frames no longer pile up in the scrollback (2b26a16). - 8 epic-tail PRs merged: #341 terminal connect-phase + SSH split-duplicate, #342 PDF struct-tree a11y + annotation shortcuts, #343 token burn-down / plural / responsive, #344 PDF fit-page / rotation / hand-pan / ink, #345 perf (page memo, debounce, chart cap, sync dirty-tracking), #346 modal migration + dirty-close guards, #347 vault TOTP / ed25519 / coded errors, #348 read reconcile / AuthorNav / table nav / frame check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #316
The last two open items from the issue's remaining tail: expose PDF prose to screen readers, and single-key annotation-tool shortcuts.
What
PdfCanvas.tsx): pdfjs-dist 4.10's API-layerTextLayerhas no struct-tree wiring (upstream that lives in the viewer'sStructTreeLayerBuilder, which we don't bundle). This replicates its minimal core:includeMarkedContent: true, so each struct element's run is wrapped in an id'dspan.markedContent(zero-size anchors; layout, selection, copy, and the search-highlight<mark>s are unchanged —textLayer.textDivsstill yields only the text spans).page.getStructTree()is walked into a hidden span tree (faithful port of upstream's#walk: PDF role → ARIA role map,H<n>→heading/aria-level,alt→aria-label,lang, single-content-child collapse,aria-ownsonto the marked-content ids) and appended inside the<canvas>as fallback content — never painted, but exposed to assistive tech in reading order.role="img"→role="region"with a localized "Page {n}" label (like the upstream viewer):imgwould mask all descendants as presentational, hiding the prose.read.annToolTitleformat key (en(H), zh full-width(H)).Why
Trade-offs / notes
getStructTree()/includeMarkedContentcontract rather than importing the upstream viewer bundle (which would drag ~430 kB ofpdf_viewerinto the chunk for one class). Upstream's#addImageInTextLayer(positionedrole=imgspans for figures inside the text layer) is not ported — figure alt text is still exposed viaaria-labelon the struct node.role="img"page label is superseded by therole="region"label.How verified
npm run build(sync:tokens + tsc --noEmit + vite build) — green.bash ../scripts/lint-desktop-tokens.sh— clean (no new off-token/phantom tokens; CSS additions are color-free).git diff origin/main --stat— only the 3 intended files.aria-ownscontract verified against the bundled pdfjs-dist 4.10.38 sources (worker emits${pageObjId}_mc${mcid}ids on both sides). No Rust changes.