* feat(editor): inline HTML attachment preview + ```html block render (MUL-2345)
* attachment-preview-modal: switch HTML iframe sandbox from "" to
"allow-scripts" so JS-driven chart libraries render. The opaque-origin
iframe still cannot touch cookies, localStorage, parent state, or
top-nav — only scripts run.
* New shared AttachmentCard wired into the three attachment surfaces
(file-card NodeView, ReadonlyContent file-card branch, comment-card
standalone AttachmentList). HTML attachments now render inline via a
sandboxed iframe pulled through the existing /content proxy; other
kinds keep the original chrome behavior.
* New HtmlBlockPreview for fenced ```html blocks in ReadonlyContent —
default preview iframe, source/Copy toggle. Two-layer code+pre unwrap
mirrors the Mermaid pattern; unwrap now matches on language-* class
because react-markdown invokes pre before the code renderer runs.
* CodeBlockView (Tiptap NodeView) renders an iframe preview for
language=html with a CSS-hidden toggle to the editable source — the
<NodeViewContent as="code"/> mount must remain in the tree.
* Shared use-attachment-html-text hook keeps inline and modal HTML
rendering on the same React Query cache.
* Vitest coverage: allow-scripts assertion, attachment-card kind
branches, readonly HTML iframe + Mermaid unwrap regression, NodeView
editable + preview/source toggle.
No backend changes; server-side text/plain + nosniff defense kept.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
* fix(editor): tighten attachment preview and pre unwrap gates (MUL-2345)
Addresses Reviewer REQUEST CHANGES on PR #2790:
1. URL-only text/html attachment cards no longer surface a dead Eye
button. `AttachmentCard` previously allowed preview when
`previewableFromUrl=true` regardless of kind, but the modal's
`tryOpen` rejects URL-only text kinds because the `/content` proxy
is ID-keyed. Drop the `previewableFromUrl` prop and gate the
no-attachmentId path strictly to URL-previewable media kinds
(pdf/video/audio).
2. Readonly `pre` unwrap now uses exact class-token matching. The
previous `className.includes("language-html")` check also fired
on `language-htmlbars`, silently stripping its `<pre>` wrapper.
Use `/(^|\s)language-(html|mermaid)(\s|$)/` so only the exact
tokens unwrap.
Regression tests:
- `report.html + no attachmentId` asserts no Preview button.
- `pdf URL-only` asserts Preview button still appears.
- `htmlbars` / `mermaidx` fences keep their `<pre><code>` wrapper.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>