Skip to content

[UX] Frame-breaking layout: subagent panel title clipped; CJK ghost hints overflow editor row #68

Closed

Description

@GeekCmore

Summary

Two layout defects that corrupt the rendered frame.

UX-15 — Subagent panel title clipped. ScrollablePanel budgets body rows as screen.rows - footerRows - 4 (packages/mayfly/src/core/scrollable-panel.ts:104), assuming a 2-row status footer and ignoring the dock's 1-transcript-row reservation (terminal.ts:300) and header/bottom lane rows (terminal.ts:667-674). The dock grants the editor slot only rows - actualFooterRows - 1 - laneRows (matching editorViewport, screen.ts:206) and slices overflow from the top (terminal.ts:322). With a 1-row footer the math coincidentally fits, but MayflyStatusDefinition.row?: 1 | 2 is public API (packages/ui/src/contracts.ts:184): any plugin contributing a 2-row status entry makes the panel render one row too many, and its first row — the ╭ Subagent · <label> ─ hint ╮ title bar (scrollable-panel.ts:84-88) — is silently dropped. The panel's own inner renderer is even told a different height truth (session-transcript-panel.ts:68 uses screen.editorViewport.rows).

UX-16 — Ghost hint overflows on CJK/emoji. truncateHint measures hint.length and slices by code units (chrome.ts:108-113), and available subtracts textLength in code units (chrome.ts:145-146), while the row budget is in terminal columns. The caller passes this.editor.getText().length (components.ts:387) although the JSDoc promises "the visible length of the real editor text" (chrome.ts:125). A hint containing wide chars (e.g. <文件路径> from a host command's input.hint, editor-plus.ts:517) renders wider than the spaces it replaces, the row exceeds render(width), and the frame clamp eats the editor's right │ border; the same slice() can split a surrogate pair. Existing tests pin ASCII only (tests/core/chrome.spec.ts:381-429).

Acceptance criteria

  • Panel body budget derives from the dock's actual editor-slot grant (or editorViewport), correct for 1- and 2-row footers and open lanes; a width/height regression test covers the 2-row footer case.
  • Ghost-hint truncation measures in display columns via the grapheme-aware width helpers; CJK/emoji hints cannot overflow the row or split a grapheme; tests cover wide-char hints.

Audit reference

docs/audits/2026-09-28-ui-ux-audit-data-and-layout.md § UX-15, UX-16 (baseline 27bc188, 2026-09-28)

Activity

  1. self-assigned this
    on Sep 28, 2026
  2. GeekCmore commented on Sep 28, 2026

    @GeekCmore
    CollaboratorAuthor

    In progress (status:in-progress). Covered by the unified layout/width plan:

    • UX-15 — one editor-slot budget: MayflyTerminalRuntime exposes lane rows, screen.editorViewport subtracts them, and ScrollablePanel derives its body budget from it (no more rows - footerRows - 4 guess). The panel title survives a 2-row footer and open lanes; the transcript renderer uses the same budget.
    • UX-16 — injectGhostHint/truncateHint measure display columns via the grapheme-aware width helpers instead of UTF-16 code units; CJK/emoji hints cannot overflow render(width) or split a surrogate pair.

    Branch fix/display-layout-fidelity. Tests: tests/core/chrome.spec.ts (wide-char hints) + tests/core/scrollable-panel.spec.ts (footer/lane height regression).

  3. GeekCmore commented on Sep 28, 2026

    @GeekCmore
    CollaboratorAuthor

    部分处理中 / Partially in progress — PR #79 (feat/i18n-hardening)。

    • UX-16(CJK ghost hint):已修复 —— ghost hint 改用 visibleWidth + sliceByColumn(..., true) 按显示列截断,调用方传入编辑文本;CJK/emoji 不再溢出或劈开 grapheme,并新增宽度回归测试。
    • UX-15(subagent 面板标题被裁):不在该 PR 范围内,本 issue 保持开启直到 UX-15 处理。

    PR: #79

  4. GeekCmore commented on Sep 28, 2026

    @GeekCmore
    CollaboratorAuthor

    Implementation opened as #81 (branch fix/display-layout-fidelity). pnpm run verify:full is green (typecheck, lint, build, shots, coverage, happy smoke). Manual runtime acceptance is pending before merge.

  5. added 2 commits that reference this issue on Sep 28, 2026
  6. GeekCmore commented on Sep 29, 2026

    @GeekCmore
    CollaboratorAuthor

    Closing as fixed, verified on current main.

    • UX-15 (subagent panel title clipped): screen.editorViewport (packages/mayfly/src/core/screen.ts) subtracts the real status-footer rows plus the width-derived header/bottom lane rows (surfaceLaneRows() over measuredLaneRows(), core/terminal.ts), and panel bodies derive their budget from that grant — no frame of lag, and the 2-row-footer + open-lanes case keeps the panel title. Implemented by fix(ui): display-fidelity and layout-budget hardening (#67 #68 #73 #74) #81 (308d609); the budget survives the feat(transcript): render every conversation in the one transcript pane #85 conversation-views rework (panels now budget from editorViewport directly).
    • UX-16 (CJK ghost hints overflow): injectGhostHint/truncateHint measure display columns via the grapheme-aware helpers (visibleWidth + sliceByColumn, core/chrome.ts), so CJK/emoji hints cannot overflow render(width) or split a surrogate pair.

    Deterministic evidence re-run today on main (14e6ce7): chrome.spec.ts 58, terminal.spec.ts 81, screen.spec.ts 6, surface-manager.spec.ts 27 — all pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingstatus:in-progressWork has started on this issue

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions