feat(ui): the diagram engine: one viewer for Mermaid and Graphviz with node, edge and sequence comments; ui 0.41.0, core 0.25.4 (#1560)
* feat(core): diagram anchor codec, accepted by external annotations and the feedback archive
DiagramAnchor ({ v, family, kind, id | from + to, label, sourceLine }) and its fail-closed parser live in @plannotator/core/diagram-anchor beside html-anchor. POST /api/external-annotations validates an optional diagramAnchor on plan comments in both runtimes (the module is vendored to Pi), and the feedback archive records the validated anchor as an additive field.
* feat(ui): the Workspaces diagram viewer becomes the diagram engine
MermaidBlock and GraphvizBlock keep fence parsing, diagramLanguages and the lazy-retry contract and render through one renderer slot (utils/diagram-render) and one canvas (components/diagram); their own viewBox math, applyView and zoom controls are gone, and the popout is the same DiagramViewer at full size in the PopoutDialog chrome. Graphviz gets a runtime slot beside Mermaid's (utils/graphviz, @viz-js/viz pinned 3.30.0). mermaidSvg.ts is replaced by sanitizeDiagramSvg (DOMPurify parse + in-place scrub). A comment composed on a diagram part is an Annotation with diagramAnchor and the fence's document lines: the highlighter skips it, the block restores it through the engine's finder and reports unanchored rows, the export prints its location line, share links drop it. Interaction per owner feedback: click selects, drag pans (4 px threshold), no hover targeting without the platform modifier, and an invisible 14 px hit path beside every edge.
* chore(guides-show): repin the viewer manifest (stylesheet only)
The viewer script is byte-identical (viewer.KTNT-M2b.js): the guide chain renders no fences, so the diagram engine is not in the portable bundle. Only the stylesheet hash moves (349,765 to 351,932 bytes) because the viewer's Tailwind scan covers packages/ui/components and picks up the new diagram components' classes.
* docs: the diagram engine, the diagram anchor, and four Mermaid 12 HANDOFF corrections
HANDOFF gains 'Diagram engine (0.41.0)' (every new export, the adapter props, the anchor shape, the runtime slots, the sanitizer delta, the interaction model, migration notes, publish order). The Mermaid 12 section is corrected: the sweep is 78 combinations / 12,870 text pairs / 7,410 line pairs; consumers add their own lodash-es override; state diagrams gain the barbEnd-margin marker id; ELK is the effective default through per-diagram defaults while config.layout still reads dagre.
* chore(core): @plannotator/core 0.25.4 (diagram-anchor subpath)
* chore(ui): @plannotator/ui 0.41.0 (diagram engine), pinning core 0.25.4
* feat(core): sequence family and whole-diagram kind in the diagram anchor codec
Both additive within v: 1. Sequence parts carry classes, not ids, so the codec's ids are the actor's name, msg-<n>, note-<n>, frame-<n>; sourceLine for an ordinal is the n-th statement of its kind. Kind 'diagram' has no id: it is what a click that resolves no part anchors to, exported as 'Diagram (<family>), lines a–b'.
* fix(ui): diagram engine review fixes and the owner's hands-on findings
Review blockers: the inline canvas is touch-action pan-y (only the popout is touch-none); the zoom strip and block controls never print; exportLinkedDocAnnotations and exportAnnotationEntry print the diagram location line; a WebMCP reply inherits diagramAnchor and diagrams are annotation-exclude so text restore never wraps a mark inside an svg. Nits: bare hit paths (no data-*), <style> scoped to the svg's root id (no @import, no fetching url(), no rule that can restyle the page), comments that name no diagram block resolve by anchor across blocks or list as Unanchored, label fallback only for a unique label, canvas keys ignore Meta/Ctrl/Alt, the modifier ring disarms on keyup/blur/other key, 10 px touch threshold, the wheel deltaY guard. Owner findings: measured in Chromium, the only thing covering a Mermaid edge is its own label box at its midpoint, so hit paths move to one top layer with composed transforms, a label resolves to its edge, and clicks resolve by priority over elementsFromPoint (node, edge, cluster); sequence diagrams are addressable; a click on no part comments on the whole diagram.
* chore(guides-show): repin the viewer stylesheet (script still byte-identical)
* docs: codec families, the hit layer and priority rule, the diagram kind, scoped styles, unowned anchors; HANDOFF names 0.41.0 / 0.25.4 M
Michael Ramos committed
b6c475a14bbb1abaffb071246f8be949594b237c
Parent: 1954a19
Committed by GitHub <noreply@github.com>
on 9/17/2026, 8:43:30 PM