Quiet rendered block chrome and steady diagram previews #370
- MA
## Why
Code, diff and diagram blocks each carried a full header bar at rest (fill, hairline, language menu, `<>` toggle), while a formula's toggle floated and only showed on hover. The slash menu said "Diagram" but the header said "Mermaid". New code, diff and diagram blocks were blank boxes. Wide Mermaid diagrams were cut off at the right edge with no cue. While you typed, a large red parser panel replaced the diagram on almost every keystroke.
## What changed
- **One chrome pattern for every rendered block.** No header bar. The controls sit in the block's top-right corner, where the formula toggle already was. At rest, a named code fence shows only its language as quiet `text-xs` text. Diff, diagram, plain and formula blocks show nothing. On hover or focus-within (or while the menu or source is open), the toggle and the menu chevron fade in (`--duration-fast`, `--ease-out`). They stay focusable at rest. On touch they are always shown, in a band of their own above the content, not on top of it. The #218 language menu and toggle are the same components in a different layout. - **Keyboard order:** the source toggle precedes the language button in the new visual and DOM order. Shift+Tab from the open language menu returns to the source toggle. - **Controls never cover content.** A diagram keeps a small top margin for them. A diff's first file header reserves room so the `-1 +1` counts stay clear. A long first line of code runs under the label behind a short fade. - **"Diagram" everywhere.** The language menu entry is now "Diagram" too. Type-to-jump also checks aliases, so pressing either `d` or `m` reaches Diagram. - **Placeholders** for empty blocks, in the formula's style: "Code", "Paste a unified diff", "Mermaid, e.g. flowchart TD; A-->B". - **Diagram width.** A diagram that needs a scale of 0.75 or more is scaled to fit. A wider one keeps its drawn size and scrolls in its own keyboard scroller, with a mask fade on whichever side still has more to see. - **Diagram errors.** The last good drawing stays while you type. After 600 ms with no fix, the drawing dims to 40% and a quiet one-line error appears under it, with the caret excerpt. The parser's list of expected tokens is no longer shown.
The derived-preview invariants are unchanged. Preview and chrome still have one React owner each, unnamed fences still render as plain text, and nothing new is written into Lexical.
## Screenshots
**Document at rest.** Before:  After: 
**Hover.** Before (code):  After (code, diff, diagram):   
**Empty code, diff and diagram blocks.** Before:  After: 
**Typing an incomplete diagram line: mid-keystroke, then paused.** Before:  After: 
**Phone (390 px): code and a wide diagram.** Before:  After: 
## Verification
35 focused code-block tests, `bun run types`, `bun run ci`, and `bun run build` pass on the restacked branch. GitHub's browser suite will run on the final published head. The reviewed dynamic-owner hashes were renewed after checking the integrated source.
- MA
**Review:** Changes needed
Checked in Chromium (own headless script, fake-GitHub server) at 1440x900 and 390x844 touch: rest, hover, keyboard focus, empty blocks, long first line, long diff filename, narrow and wide diagrams, typing into a diagram. The direction is right and it looks good. Two small fixes and one nit before merge.
**Fix** 1. Type-to-jump regression. `language-menu.tsx:142-147` matches on label prefix, and the label moved from "Mermaid" to "Diagram". Pressing `m` in the open language menu now lands on Markdown (confirmed). Suggested fix: give `LANGUAGES` an optional keyword alias (for example `mermaid`) that the prefix match also checks, so both `d` and `m` reach Diagram. 2. Titled code blocks on phone: with `title="src/very/long/..."` the title is clipped at its **start** ("/very/long/path/to/..." with "src" missing), not ellipsised at the end. Cause is the chrome sitting in an absolutely positioned `min-w-0` row with the hidden-toggle slot, so the title gets squeezed from the wrong side (`styles.css` `.plan-code-title` / `.plan-code-chrome`). Suggested fix: cap the chrome with `max-inline-size: 100%` and let the title be the only shrinking child.
**Nit** 3. Diagram error appears with a roughly 60px layout shift (dim drawing plus error line pushes the source down). Acceptable since it only arrives after 600 ms, but the error line could reserve its space while source is open.
**Verified fine** - Rest state is clean: named fence shows a faint `text-xs` label only; diff, diagram, plain and formula show nothing. Unnamed fence stays plain text (no label). - Hover/focus reveals the toggle and chevron; controls stay focusable at rest and `focus-within` reveals them. Keyboard users find "Show source" by Tab (it precedes the language trigger; e2e updated to Shift+Tab). The remaining discoverability cost is first-time mouse users and sighted-keyboard users who must hover/Tab first; the same hover-reveal already exists for formulas and Notion/Linear behave similarly, so I judge this acceptable. The faint language label at rest also hints that the block is interactive. Diff and diagram have no at-rest cue; fine, they are visibly rendered output. - Long first code line fades under the label (good). Long diff filename ellipsises ahead of the reserved spacer; counts stay clear. - Touch: always-visible controls sit in their own band above content, nothing covered, targets fine. - Diagram: a 5-node LR diagram at about 537px measure keeps authored size and scrolls with a right fade (labels legible at 100%; a 0.75 scale is still readable). The fade is subtle on phone but visible. Narrow diagrams fit. - Error flow: last good drawing stays through valid and invalid keystrokes (no height flicker, preview height constant across 230 frames of typing); after 600 ms it dims to 0.4 and shows a quiet one-line error with caret excerpt; fixing it restores the drawing. - Placeholders ("Code", "Paste a unified diff", "Mermaid, e.g. ...") match the formula style. - AGENTS.md invariants intact: derived preview, one React owner, unnamed fence plain, no new Lexical writes. Read-only: `disabled` still reaches the language menu; the toggle remains for viewers.
**CI** (`gh pr checks 370`): format/lint/types/tests FAIL (only the expected design-contract hash, listed in the PR body; not edited), container pass, e2e pass.
- MA
Addressed in db869a3b. Thanks for the careful pass.
1. **Type-to-jump.** `LanguageOption` now takes optional aliases. Diagram has `["mermaid"]`. The match moved into a pure `jumpTo()` in `code.ts`, which checks the label and the aliases, then the next match, and wraps round. New unit tests in `code.test.ts` cover `d` and `M` reaching Diagram, the next match and wrap, and no match. In the browser, pressing `m` in the open menu now lands on Diagram, and pressing it again moves on to Markdown. 2. **Long titles on phone.** The chrome host and the chrome row are capped at `max-inline-size: 100%`. Every child except the title has `flex-shrink: 0`, so the title ellipsises at its end. At 390×844, `src/very/long/path/to/some/deeply/nest…` now shows its start, with the toggle and `ts ▾` intact. 3. **Error shift.** While the source is open, a drawn diagram's preview reserves the error line's height, and the error has the same minimum height (both 20 spacing units). Measured in Chromium: the source's top stays at 623px between typing and the paused error, so the shift is 0px (it was about 60px).
The checks pass except the design-contract hash, which now covers `language-menu.tsx` too. Its new hash is in the PR body.
MaggieAppletonhead-ref-force-pushed 27c435fbdb36last month on GitHub
- MA
Follow-up: the branch had conflicts with main after #292 (Tab key) landed, so I rebased it. #292 adds an "Esc then Tab to leave" hint to the block header; it now sits at the start of the new corner chrome. The caret lives in the editor root, so `:focus-within` never matches a block being typed in. The chrome now gets `data-editing` while its block is being edited, which keeps the controls and the hint visible as you type. Checked in Chromium. CI: e2e and container pass. format/lint/types/tests fails only on the two design-contract hashes listed in the PR body (`code-view.tsx` and `language-menu.tsx`, unchanged by the rebase).
MaggieAppletonreferenced this in Open rendered code, diff and diagram blocks by clicking or arrowing in #388last month on GitHub
MaggieAppletonhead-ref-force-pushed c2d2b346a68elast month on GitHub
MaggieAppletonmerged 9ed4bbf31809last month on GitHub
MaggieAppletonhead-ref-deletedlast month on GitHub