Skip to content

q2 preview: hierarchical block navigator + fix breadcrumb/toolbar overlap (bd-9x3zbuj8)#345

Merged
cscheid merged 5 commits into
mainfrom
feature/bd-9x3zbuj8-preview-hierarchy-nav-overlap
Jun 25, 2026
Merged

q2 preview: hierarchical block navigator + fix breadcrumb/toolbar overlap (bd-9x3zbuj8)#345
cscheid merged 5 commits into
mainfrom
feature/bd-9x3zbuj8-preview-hierarchy-nav-overlap

Conversation

@cscheid

@cscheid cscheid commented Jun 25, 2026

Copy link
Copy Markdown
Member

Summary

Two changes to the q2 preview live block editor (tiptap rich text), strand bd-9x3zbuj8:

  1. Task 1 — bring the hierarchical block navigator to q2 preview --allow-edit. The nesting-cursor breadcrumb (◀ Dv ¶ ▶) shipped in hub-client/quarto-hub.com but was off by default in the q2 preview SPA. parseNestingCursorParam now defaults on (?nestingCursor=0 opts out), mirroring the existing richText default-on / ?richText=0 contract. It self-gates on an active edit target, so read-only previews never show it.

  2. Task 2 — fix the breadcrumb / rich-text-toolbar overlap. When a rich-text block is open, the navigator now renders inline in the toolbar row, to the right of the formatting buttons, instead of as a floating chip that overlapped them. Implemented via the user-chosen Option B (inline in the toolbar; standalone chip retained for plain/non-rich blocks).

Before (reported): ◀ Dv ¶ ▶ floating chip overlapping B I S x₂ x² 🔗.
After: single toolbar row B I S x₂ x² 🔗 │ ◀ Dv ¶ ▶ — formatting fixed on the left, navigator inline to the right, no overlap. Fixes the overlap in both hub-client and q2 preview (shared @quarto/preview-renderer).

Implementation

  • Extracted a position-agnostic BreadcrumbCrumbs from BreadcrumbChip (layout: 'standalone' | 'inline', shared ensureBreadcrumbStyles()). Standalone keeps its pivot-pinned left-spill geometry unchanged; inline sizes to natural width and flows after the toolbar buttons, so the toolbar's left edge is independent of breadcrumb width.
  • RichTextToolbar gains a trailing slot; RichTextEditor builds the inline breadcrumb from the live edit target.
  • The standalone BreadcrumbChip self-suppresses for a target whose rich editor is active, via a new leaf module richTextSupport.ts (RICHTEXT_SUPPORTED_TYPES, richTextAvailable, richEditorActiveForType) + currentSourceNodeType. Synchronous and reactive (tracks editorMode/richText); no changes to the activation path.

Verification

  • End-to-end through the real q2 binary + Chrome: clicking a paragraph nested in a callout div produced toolbar DOM B I S x₂ x² 🔗 ◀ Dv ¶ ▶ with the standalone chip absent and no overlap (screenshot inspected).
  • Tests: preview-renderer 500 unit + 515 integration; q2-preview-spa 37 unit + 75 integration + 37 real-binary Playwright e2e; hub-client 662 unit + 76 integration. cargo xtask verify --skip-hub-build green (Rust untouched); hub-client + q2-preview-spa production builds green.
  • New tests: parseNestingCursorParam.test.ts, p3-4-inline-breadcrumb.integration.test.tsx; restructured nesting-cursor.spec.ts for the new defaults.

Discovered work (filed)

  • bd-fpys25b0 (filed, not in this PR): the entire hub-client block-editing e2e suite (12 specs) has been red since rich-text went default-on (bd-j1nto6eq) — none pin richText, so they wait for a textarea the rich editor replaces. Not in default cargo xtask verify (test:e2e is opt-in). Left for a dedicated session.
  • bd-n4v4phe4 (fixed here): the equivalent edit-cell-sizing.spec.ts (q2-preview-spa e2e) — pinned ?richText=0 (the bd-038tnyqy baseline pattern).

Plan: claude-notes/plans/2026-06-25-q2-preview-hierarchy-nav-and-overlap.md

🤖 Generated with Claude Code

cscheid and others added 5 commits June 25, 2026 09:12
…ich-text toolbar (bd-9x3zbuj8 Task 2)

When the rich-text editor is showing for the active target (Para/Header in rich
mode), the hierarchy navigator now renders INLINE in the toolbar row, to the
right of the formatting buttons, instead of as a separate floating chip that
overlapped them (the overlap the user reported in hub-client/quarto-hub.com).

- Extract a position-agnostic `BreadcrumbCrumbs` (◀ · band · ▶ · future) from
  `BreadcrumbChip`, with a `layout: 'standalone' | 'inline'` prop and a shared
  `ensureBreadcrumbStyles()` injector. Standalone keeps the pivot-pinned
  left-spill geometry (unchanged); inline sizes to natural width and flows after
  the toolbar buttons, so the toolbar's left edge is independent of breadcrumb
  width.
- `RichTextToolbar` gains a `trailing` slot (after a separator); `RichTextEditor`
  builds the inline breadcrumb from the live edit target and passes it in.
- The standalone `BreadcrumbChip` self-suppresses for a target whose rich editor
  is active, so the two never double up. Suppression reuses the dispatcher's
  predicate via a new leaf module `richTextSupport.ts`
  (`RICHTEXT_SUPPORTED_TYPES`, `richTextAvailable`, `richEditorActiveForType`)
  plus `currentSourceNodeType` (resolves the active node's type from the source
  index). Fully synchronous and reactive (tracks editorMode/richText), with no
  changes to the activation path. For plain/non-rich blocks (lists, code, divs,
  or plain mode) the standalone floating chip is unchanged.

New test: p3-4-inline-breadcrumb.integration.test.tsx (inline crumbs in the
toolbar + standalone suppressed for a rich Para; standalone retained for a
CodeBlock). Existing breadcrumb geometry/integration suites unchanged and green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…zbuj8 Task 1)

Brings the nesting-cursor breadcrumb navigator to `q2 preview --allow-edit`,
matching hub-client (which already defaults the `unlockNestingCursor` preference
on). The SPA previously defaulted it off, enabling it only via `?nestingCursor=1`.

`parseNestingCursorParam` now defaults ON, with `?nestingCursor=0` as the opt-out
— mirroring the existing `richText` default-on / `?richText=0` contract. Exported
for direct unit testing. Safe to default globally: the navigator self-gates on an
active edit target, so a read-only preview (no --allow-edit) never shows it.

- New unit test parseNestingCursorParam.test.ts (default-on / =0 opt-out).
- p3-2-nesting-cursor-spa.integration.test.tsx: no-param case now expects
  unlockNestingCursor=true.
- nesting-cursor.spec.ts (real-binary e2e) restructured for the new defaults:
  default boot → unlocked, rich editor + inline navigator, standalone chip
  suppressed; ?richText=0 → clean textarea buffer; ?nestingCursor=0 → locked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sts (bd-n4v4phe4)

These no-reflow tests use the textarea as the activation baseline
(assertNoReflowOnActivation waits for a <textarea>), but rich-text is the
q2-preview default since bd-j1nto6eq, so Para/Header open in the rich editor and
no textarea mounts — the 3 paragraph/heading tests timed out. Pin ?richText=0,
matching the textarea-baseline pattern established for hub-client e2e in
bd-038tnyqy. Pre-existing breakage, surfaced while running the spa e2e suite for
bd-9x3zbuj8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… default-on (bd-9x3zbuj8)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cscheid cscheid merged commit b6b1a31 into main Jun 25, 2026
5 checks passed
@cscheid cscheid deleted the feature/bd-9x3zbuj8-preview-hierarchy-nav-overlap branch June 25, 2026 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant