EANCH-WP-0004: HtmlViewer scroll parity and viewer-shell workplan
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

Export HtmlViewerAdapter from package root, add scrollRequestKey parity,
register finished workplan, update SCOPE.
This commit is contained in:
tegwick 2026-07-09 09:58:41 +02:00
parent 49d9810c93
commit bbeba96173
4 changed files with 119 additions and 5 deletions

View file

@ -51,10 +51,9 @@ Selector *behavior* lives here; selector *type interfaces* live in
During the umbrella-first MVP these belong to the appropriate citation-evidence
subsystem. This repo may depend on **`citation-engine` only** (DependencyMap §4).
### Still deferred (beyond EANCH-WP-0002 / EANCH-WP-0003)
### Still deferred (beyond EANCH-WP-0004)
- `FragmentSelector` (export-only deep links)
- wiring `HtmlViewerAdapter` into `citation-work` / the umbrella review shell
- human-confirmation UI for ambiguous/fuzzy matches
---
@ -81,7 +80,7 @@ subsystem. This repo may depend on **`citation-engine` only** (DependencyMap §4
- Status: active — standalone package consumed by `citation-evidence`
- Implementation: PDF + HTML/Markdown selector paths, stale/orphan/fuzzy resolution,
`PdfViewerAdapter`, and `HtmlViewerAdapter` (`evidence-anchor/dom`)
- Stability: evolving — shared contracts stable; viewer wiring in the umbrella is next
- Stability: evolving — shared contracts stable; HTML/MD wired in `citation-work` ViewerShell
- Usage: internal (consumed by `citation-evidence` during MVP)
---

View file

@ -32,6 +32,11 @@ export interface HtmlViewerAdapterProps {
readonly representation: DocumentRepresentation;
readonly storedAnnotations?: readonly StoredHtmlAnnotation[];
readonly scrollToAnnotationId?: string;
/**
* Bumps when the same annotation should be re-scrolled (e.g. repeat click).
* Format is opaque typically `${annotationId}:${version}`.
*/
readonly scrollRequestKey?: string;
readonly activeAnnotationId?: string | null;
readonly debug?: HtmlViewerDebugOptions;
onSelectionCaptured?(capture: DomSelectionCapture, selectors: Selector[]): void;
@ -50,6 +55,7 @@ export function HtmlViewerAdapter(props: HtmlViewerAdapterProps): ReactNode {
representation,
storedAnnotations = [],
scrollToAnnotationId,
scrollRequestKey,
activeAnnotationId,
debug,
onSelectionCaptured,
@ -91,12 +97,13 @@ export function HtmlViewerAdapter(props: HtmlViewerAdapterProps): ReactNode {
}, [html, storedAnnotations, representation, activeAnnotationId]);
useEffect(() => {
if (!scrollToAnnotationId || !rootRef.current) return;
const requestKey = scrollRequestKey ?? scrollToAnnotationId ?? null;
if (!requestKey || !scrollToAnnotationId || !rootRef.current) return;
const mark = rootRef.current.querySelector(
`[data-highlight-id="${CSS.escape(scrollToAnnotationId)}"]`,
);
mark?.scrollIntoView({ block: "center", behavior: "smooth" });
}, [scrollToAnnotationId, renderedHtml]);
}, [scrollToAnnotationId, scrollRequestKey, renderedHtml]);
return (
<div

View file

@ -20,6 +20,20 @@ export {
type CreateSelectorsOptions,
} from "./selectors";
// DOM adapter (re-exported from the src/dom/ boundary).
export {
HtmlViewerAdapter,
resolveHtmlSelectors,
scrollToHtmlTarget,
renderHtmlHighlight,
captureFromRange,
domPathToNode,
nodeAtPath,
type HtmlViewerAdapterProps,
type HtmlViewerDebugOptions,
type StoredHtmlAnnotation,
} from "./dom";
// PDF adapter + helpers (re-exported from the src/pdf/ boundary).
export {
PdfViewerAdapter,

View file

@ -0,0 +1,94 @@
---
id: EANCH-WP-0004
type: workplan
title: "Wire HtmlViewerAdapter into the review workspace viewer shell"
domain: infotech
repo: evidence-anchor
status: finished
owner: codex
topic_slug: citation_evidence_mvp
created: "2026-07-09"
updated: "2026-07-09"
spec_refs:
- INTENT.md
- SCOPE.md
- ../citation-evidence/wiki/SharedContracts.md
- src/dom/html-viewer-adapter.tsx
---
# EANCH-WP-0004 — Viewer Shell DOM Wiring
## Goal
Connect `HtmlViewerAdapter` (`evidence-anchor/dom`) to the citation-evidence
review workspace so users can upload, view, select, annotate, and reopen
HTML/Markdown documents — not only PDFs.
## Task Breakdown
## T01 — Browser upload path for HTML/Markdown
```task
id: EANCH-WP-0004-T01
status: done
priority: high
```
Add `ingestHtmlFromFile` / `ingestMarkdownFromFile` and `resolveDomViewerHtml`
to `evidence-source/browser`, extending the byte store to hold non-PDF bytes.
## T02 — Upload dropzone accepts HTML/Markdown
```task
id: EANCH-WP-0004-T02
status: done
priority: high
depends_on: [T01]
```
Extend `citation-work` `UploadDropzone` to ingest `.html` / `.md` files via
the new browser helpers.
## T03 — ViewerShell routes by representation type
```task
id: EANCH-WP-0004-T03
status: done
priority: high
depends_on: [T02]
```
Branch `ViewerShell` on `representationType`: PDF → `PdfViewerAdapter`,
`html-dom` / `markdown-rendered``HtmlViewerAdapter`. Widen
`PendingSelection` to `SelectionCapture`.
## T04 — HtmlViewerAdapter scroll parity
```task
id: EANCH-WP-0004-T04
status: done
priority: medium
depends_on: [T03]
```
Add `scrollRequestKey` to `HtmlViewerAdapter` so repeat-click re-scroll works
like the PDF adapter.
## T05 — Verification + close-out
```task
id: EANCH-WP-0004-T05
status: done
priority: high
depends_on: [T04]
```
Tests green in `evidence-source`, `evidence-anchor`, `citation-work`, and
`citation-evidence`; `fix-consistency` clean; progress note.
**Verification (2026-07-09):**
- `evidence-source`: 82 tests (browser view-html + upload).
- `evidence-anchor`: 42 tests; `HtmlViewerAdapter` scroll parity.
- `citation-work`: 12 tests including `ViewerShell.dom.test.tsx`.
- `citation-evidence`: typecheck clean.