Skip to content

Commit e6fcf95

Browse files
cscheidclaude
andcommitted
feat(revealjs): hoist captioned figure image to section level for auto-stretch
Port Q1's applyStretch figure branch as an AST transform (bd-38ioql41, Case 1). On a single-image reveal slide, a captioned markdown figure (`![caption](x)` -> Block::Figure) rendered the stretched <img class=r-stretch> inside a <figure>, which reveal's `section > .r-stretch` selector cannot size. RevealAutoStretchTransform now replaces the Block::Figure with a Plain[Image] (carrying .r-stretch, with the figure id transferred onto the img for @fig-id parity) followed by a caption Paragraph whose trailing Inline::Attr{.caption} makes the writers emit <p class="caption"> (capability bd-itqcfxc3). Result: section > img.r-stretch + sibling <p class=caption>, matching Q1 -- all at the AST level, no DOM postprocessor. Caption uses <p class=caption> (option c). Centering deferred (flush-left, consistent with the shipped bare-image case). The crossref figure case (::: {#fig-id}) stays un-stretched (Option 2A, deferred): it is a plain Div at auto-stretch time and the crossref render is excluded from the preview pipeline, so there is no single AST shape common to render and preview; @fig-id still resolves. Tests (TDD): 3 unit tests in auto_stretch.rs + 1 render-path test in revealjs_format.rs (failed first, pass now). Full quarto-core+pampa suites and cargo xtask verify green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5a21249 commit e6fcf95

3 files changed

Lines changed: 391 additions & 47 deletions

File tree

claude-notes/plans/2026-06-17-revealjs-autostretch-figures.md

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# RevealJS auto-stretch — captioned & cross-referenceable figures
22

33
**Strand:** bd-38ioql41 (follow-up to bd-zkstclhl)
4-
**Date:** 2026-06-17
5-
**Status:** investigation complete, design options open — **iterating, not yet implementing**
4+
**Date:** 2026-06-17 (Case 1 implemented 2026-06-18)
5+
**Status:** **Case 1 implemented** (markdown captioned figure hoist, with
6+
`<p class="caption">` via bd-itqcfxc3). Case 2 (crossref figures) deferred —
7+
Option 2A. Centering deferred (flush-left, consistent with the bare-image case).
68

79
## Overview
810

@@ -174,11 +176,59 @@ in a dedicated strand.
174176

175177
## Proposed scope for THIS strand (to confirm with user)
176178

177-
- [ ] Implement **Case 1** (markdown captioned figure) — early AST unwrap.
178-
- [ ] Decide caption representation + centering (Open Questions).
179-
- [ ] **Case 2**: pick Option 2A / 2B / 2C. If 2A, file a new strand and
180-
document the divergence (in README + a `log`/comment).
181-
- [ ] Example fixture `13-figure-stretch` (done — created).
179+
- [x] Implement **Case 1** (markdown captioned figure) — early AST unwrap.
180+
`RevealAutoStretchTransform`'s Figure branch now replaces the `Block::Figure`
181+
with `Plain[Image]` (`.r-stretch`, figure `id` transferred onto the img)
182+
followed by `caption_paragraph(...)` — a `Paragraph` with a trailing
183+
`Inline::Attr{.caption}`. See `hoist_figure` / `figure_caption_inlines` /
184+
`caption_paragraph` in `auto_stretch.rs`.
185+
- [x] Decide caption representation + centering. **Caption:** option (c) —
186+
`<p class="caption">` via the merged bd-itqcfxc3 capability (no longer a
187+
plain `<p>`). **Centering:** deferred — bare stretched img is flush-left,
188+
consistent with the shipped bare-image case; matches Q1 only when Q2 grows
189+
a figure-alignment story (then revisit `quarto-figure-center`).
190+
- [x] **Case 2**: **Option 2A** (defer). Crossref figures stay un-stretched on
191+
single-image slides — render≡preview (neither stretches them), so no *new*
192+
divergence. Documented in the `auto_stretch.rs` module doc-comment and here.
193+
A dedicated strand for 2B/2C can be filed when a figure-alignment milestone
194+
arrives.
195+
- [x] Example fixture `13-figure-stretch` (done — created).
196+
197+
## Implementation results (2026-06-18) — Case 1 PASS
198+
199+
**Tests (TDD):** added 3 unit tests in `auto_stretch.rs`
200+
(`lone_figure_becomes_plain_image_plus_caption`, `figure_id_transferred_onto_image`,
201+
`nostretch_figure_left_intact`) + 1 render-path test in `revealjs_format.rs`
202+
(`revealjs_auto_stretch_figure_hoists_image_and_caption`). Confirmed the 3 new
203+
behavior tests failed first (`<figure>`/`<figcaption>` retained), then passed
204+
after the implementation. Full `quarto-core` + `pampa` suites green (6352
205+
tests); `cargo xtask verify` all 14 steps green (incl. lint + WASM/hub-client).
206+
207+
**End-to-end (render path), inspected:**
208+
```bash
209+
cargo run --bin q2 -- render examples/presentations/13-figure-stretch/slides.qmd
210+
```
211+
Slide 1 (`![This is a caption.](diagram.svg)`) — the figure is hoisted exactly
212+
like Q1:
213+
```html
214+
<section id="captioned-figure-markdown-syntax" class="section">
215+
<h2>Captioned figure (markdown syntax)</h2>
216+
<p>A figure written with the markdown image+caption syntax. …</p>
217+
<img src="diagram.svg" alt="This is a caption." class="r-stretch" />
218+
<p class="caption">This is a caption.</p>
219+
</section>
220+
```
221+
Slide 3 (`{.nostretch}`) — left intact as `<figure>`, no `r-stretch` (opt-out
222+
honored). Slide 2 (crossref `::: {#fig-diagram}`) — unchanged, no `r-stretch`,
223+
`@fig-diagram` still resolves to "Figure 1" (Case 2 deferred as designed).
224+
225+
**Preview transport (feeds the React reveal renderer), verified:** the caption
226+
`Paragraph[…, Attr{.caption}]` serializes through the JSON writer as a Para with
227+
the safe `attr` key `["",["caption"],[]]` and round-trips to `<p class="caption">`
228+
(the json.rs → React Para.tsx channel proven in #310). The structural hoist
229+
(`Plain[Image]`) uses only standard nodes. **Not run in a live browser** this
230+
session — the transport that feeds preview is verified, but a visual browser
231+
check of the q2-preview reveal renderer was not performed.
182232

183233
## Open questions for the user
184234

0 commit comments

Comments
 (0)