MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-2039

Work-item description: a Markdown TABLE overflows the description card and paints across the right rail — `.motir-prose` has no `table` rules at all (no scroll container, no borders)

Done
Description

Type: Bug (code) · UI / layout — the horizontal-overflow bug class (a wide child with no containment), sibling of MOTIR-448, MOTIR-1307, MOTIR-1329, MOTIR-1483.

Parent: MOTIR-1464 — the open "Planner self-improvement · auto-reported quality bugs" epic, the de-facto home for agent-discovered quality bugs (Yue's call, 2026-08-03; filed at root first). NOT parented by where the defective code lives: that would be the Markdown render stack (MOTIR-45 · MarkdownView) and Story 5.8 (MOTIR-1399) under Epic 5 (MOTIR-263) — both done, so per the bug-parent rule the bug is not re-attached into a sealed epic. Nothing open is blocked by it.

Discovered in: out-of-band manual dogfooding (screenshot of the live MOTIR-1981 detail page, 2026-08-03). Reported symptom: "the content of the item overflows."

Symptom (observed)

On MOTIR-1981 the description contains a GFM table (symptom | measured | why). In the rendered read view:

  • The table's width is set by its content, so it runs past the right edge of the description card, past the 1fr main column, under the right-rail cards (Priority / Assignee / Reporter / Parent / Labels / Components) and off the right edge of the viewport. The third column (why…) is only visible in the gutters between the rail cards — the rest is unreachable: no horizontal scrollbar, no clipping, no wrap.
  • The internal-link chip for MOTIR-1974 sits inside one of those table cells and overflows with it — its max-w-full (the MOTIR-1483 fix) resolves against the already-unbounded table cell, so the fix is defeated. This is a consequence, not a second defect.
  • Secondary, same root cause: the table renders with no borders, no header rule, no row separators and no cell padding — it reads as loose floating text, not a table.

Root cause (VERIFIED against origin/main @ c4ec51b1)

  1. lib/markdown/render.tsx:115 runs remarkPlugins={[remarkGfm]}, so GFM tables do parse and emit real <table>/<thead>/<tr>/<td> into MarkdownView (components/ui/MarkdownView.tsx:45, className="wmde-markdown motir-prose").
  2. components/ui/markdown-editor.css (the entire .motir-prose block, 218 lines) has zero table / thead / tr / th / td rules. grep -nE 'table|th|td' components/ui/markdown-editor.css returns nothing but comment text. There is no @tailwindcss/typography plugin and no global table rule in app/globals.css either, so nothing else supplies them.
  3. The only element in .motir-prose that is taught to contain itself is pre (overflow-x: auto, line 63-67) and img (max-width: 100%, line 73). A bare <table> does neither: it is not a scroll container, and min-width: 0 on the grid cell does not shrink it.
  4. app/(authed)/items/[key]/page.tsx:406-413 already documents the intended contract — <main className="min-w-0 …"> floors the 1fr track's min-content "so a wide child scrolls inside its own block (.motir-prose pre has overflow-x:auto)". min-w-0 on the track is necessary but not sufficient: it only works for children that scroll themselves. Tables were never given that block, so the escape lands exactly where MOTIR-448 landed.

This is a pure implementation gap — table support was enabled at the parser (remark-gfm) but never at the stylesheet. No design/plan defect, so no notes.html entry.

Reproduce

  1. Put a Markdown table with 3+ columns and long cell text (a fenced-code span or a MOTIR-N reference in a cell makes it worse) in a work item's description. MOTIR-1981's live description is a ready-made repro.
  2. Open that item's detail page (/items/<key>) at a normal desktop width.
  3. Expected: the table stays inside the Description card and scrolls horizontally inside its own block if it is wider than the column; it renders with visible header/row rules.
  4. Actual: the table paints across and behind the right rail and off the viewport; the overflowing columns are unreachable; there are no rules or padding.

Fix direction (for the close-out subtask)

  • Give the table its own scroll block, so min-w-0 on the <main> track can do its job — either wrap <table> in an overflow-x: auto element via a components: { table: … } override in lib/markdown/render.tsx (preferred: keeps real table column sizing), or .motir-prose table { display: block; overflow-x: auto; max-width: 100% } (simpler, but display:block costs column auto-sizing). Whichever is chosen, the table must never exceed the description column width, and the overflow must be reachable (scrollable), not clipped.
  • Add the missing table typography in the same pass: header weight + bottom rule, row separators, cell padding — colours from --el-border / --el-text* only, radii/spacing from the element-semantic tokens (no invented colours, no hardcoded border-style).
  • The same .motir-prose styles are shared with the WYSIWYG editor surface, so verify BOTH the read view (MarkdownView) and the editor.
  • Also re-check the chip inside a table cell after the fix — .wi-chip { max-w-full } should truncate correctly once the cell has a bounded width.
  • Regression test: measure rendered geometry (scrollWidth <= clientWidth + 1 on the description card, plus the card's right edge vs. the rail's left edge) in E2E — happy-dom returns all-zero geometry, so the component test can only assert structure. Write the FAILING repro first.

Resolution: (open — the close-out subtask fills this)