Skip to content

Unify cell paragraph layout with body layoutBlock#167

Merged
hackerwins merged 6 commits into
mainfrom
cell-paragraph-layout-unification
Apr 30, 2026
Merged

Unify cell paragraph layout with body layoutBlock#167
hackerwins merged 6 commits into
mainfrom
cell-paragraph-layout-unification

Conversation

@hackerwins

@hackerwins hackerwins commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Indent (Tab) on a non-list paragraph inside a table cell silently no-op'd before this branch — applyBlockStyle({ marginLeft }) updated the model, but layoutCellInlines ignored block.style.marginLeft. Bullets worked because list indent took a separate listLevel path.
  • Replace the duplicated layoutCellInlines (175 lines of word-wrap + line-height + image handling) with a call to the body-side layoutBlock + new assignLineHeights helper. Cells now honor marginLeft, textIndent, lineHeight, and heading/title/subtitle defaults the same way body paragraphs do.
  • Net deletion of ~220 lines in table-layout.ts plus a 4-test regression suite covering each newly honored style.
  • Fix the cell caret on empty list-item lines: the cell branch of resolvePositionPixel was missing the empty-line fallback that the body branch already had, leaving the caret at cell origin (x=0) instead of after the bullet/number marker.

Test plan

  • pnpm verify:fast — 36 docs test files / 629 tests pass
  • Browser smoke on a shared doc with mixed body + cell list-items: paragraph indent inside cell honors Tab/Shift+Tab; bullet/number markers and text positions match body parity; clicking on an empty bullet line in a cell places the caret right after the marker
  • Reviewer: please re-verify on a fresh doc — pre-existing documents with stale marginLeft values that were silently ignored by the old cell layout will now visibly indent. Outdent (Shift+Tab) cleans them up.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Table cells now properly apply paragraph styling, including indentation, text spacing, line height, and heading defaults.
  • Documentation

    • Updated design documentation describing cell layout behavior.
    • Added documentation notes on layout implementation lessons and task completion.
  • Tests

    • Added test coverage for cell paragraph styling and line height computation.

hackerwins and others added 6 commits May 1, 2026 07:16
Captures the duplicated layoutCellInlines / layoutBlock split that causes
Increase Indent to silently no-op on paragraphs inside table cells.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Prepare for cell paragraph layout unification by sharing the body
layout primitives. No behavior change on body paragraphs.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Pin the indent-in-cell bug and three related missing behaviors
(marginLeft, textIndent, lineHeight, heading defaults) before
unifying cell and body paragraph layout in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
layoutCellBlocks now reuses layoutBlock + assignLineHeights, so cells
honor block.style.marginLeft, textIndent, lineHeight, and heading/
title/subtitle defaults — same semantics as body paragraphs. Fixes
Increase Indent having no effect on paragraphs inside table cells.

The previous duplicated layoutCellInlines + splitWords are removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Records the design note in docs-tables.md, captures the duplicated-
layout lesson, and archives the task per the project workflow.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The cell branch of resolvePositionPixel left cursorX at 0 when the
target line had no runs (empty list-item or empty paragraph with
marginLeft). The caret then rendered at the cell content origin
instead of after the bullet/number marker, mismatching the body-side
behavior.

Mirror layout.ts's body fallback: when the resolved cell line has no
runs, place the caret at the block's effective marginLeft (plus list
indent for list-items). For an empty bullet at level 0 this puts the
caret immediately to the right of the marker, where typed text would
appear once the user starts typing.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR consolidates table cell paragraph layout with the shared body paragraph layout pipeline by exporting layoutBlock, extracting a reusable assignLineHeights helper, and rewriting cell block layout to merge list indentation into marginLeft so cells honor consistent block-level styling.

Changes

Cohort / File(s) Summary
Design & Task Documentation
docs/design/docs/docs-tables.md, docs/tasks/README.md, docs/tasks/archive/README.md, docs/tasks/archive/2026/04/*
Updated design documentation to describe cell content layout computation via shared layoutBlock() pipeline; created archived task documents (lessons and todo) explaining layout regression and unification plan; incremented archived task count and removed legacy pre-todo subsections.
Layout Pipeline Refactoring
packages/docs/src/view/layout.ts
Exported previously internal layoutBlock() function and extracted assignLineHeights() helper from computeLayout() to enable reusable line-height computation across both body and cell content layout.
Table Cell Layout Unification
packages/docs/src/view/table-layout.ts
Replaced custom inline-wrapping layout logic (~186 lines) with reusable block layout pipeline; list-item indentation is now merged into block.style.marginLeft before layoutBlock() call, ensuring cells honor marginLeft, textIndent, lineHeight, and heading defaults consistently.
Peer Cursor Empty-Line Handling
packages/docs/src/view/peer-cursor.ts
Added marginLeft computation for table cell lines with no text runs (empty bullets/paragraphs), incorporating list indentation when applicable before resolving final cursor position.
Cell Layout Test Coverage
packages/docs/test/view/table-layout.test.ts
Added four new test cases verifying marginLeft run positioning, textIndent first-line offset, paragraph lineHeight scaling, and heading font-size defaults in cell layout.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Cells once strayed from their block-bound kin,
With tangled indents buried deep within,
But now they share one layout's way,
Where marginLeft and lineHeight play—
No more duplication's winding road,
Just one true path that all can load!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: unifying cell paragraph layout with the body layoutBlock pipeline, which is the core objective.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cell-paragraph-layout-unification

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 121.2s

Lane Status Duration
sheets:build ✅ pass 13.5s
docs:build ✅ pass 8.2s
verify:fast ✅ pass 61.7s
frontend:build ✅ pass 15.6s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.8s
cli:build ✅ pass 1.8s
verify:entropy ✅ pass 15.3s

Verification: verify:integration

Result: ✅ PASS

@codecov

codecov Bot commented Apr 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 47.61905% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/docs/src/view/peer-cursor.ts 0.00% 11 Missing ⚠️
packages/docs/src/view/table-layout.ts 64.51% 11 Missing ⚠️

📢 Thoughts on this report? Let us know!

@hackerwins
hackerwins merged commit 5290548 into main Apr 30, 2026
4 checks passed
@hackerwins
hackerwins deleted the cell-paragraph-layout-unification branch April 30, 2026 23:24
hackerwins added a commit that referenced this pull request May 1, 2026
Two issues surfaced in DOCX-imported documents after #167 unified the
cell paragraph layout with the body's layoutBlock.

1. Cells with stored `lineHeight: 0.7` (planted by docx-style-map's
   unconditional `line / 240` mapping for `<w:spacing w:line=...>`
   regardless of `lineRule`) collapsed every line below the font's
   own pixel height once cells started honoring the value, so
   characters from adjacent lines overlapped. Floor the multiplier at
   1.0 inside `assignLineHeights` so a sub-1.0 value can never crash
   text into the line below. The DOCX `lineRule` mishandling is the
   underlying data bug; that import fix is left as a follow-up.

2. The cell text baseline used `runLineY + line.height * 0.75`, which
   places the glyph's ascent ~5% of the font size above the line's
   declared top whenever lineHeight is tight (≈ 1.0). At a paginated
   row split this leaked a sliver of the next page's first line into
   the previous page's clip region — the same line then rendered
   fully on the next page, producing a visible double-draw at the
   boundary. Switch to the centered formula already used by the body
   path in doc-canvas and the list-marker path in the same file:
   `(line.height + fontSize * 0.8) / 2`. The glyph ascent now sits
   inside the line box for any lineHeight ≥ 1.0, so the page-split
   clip cleanly excludes it.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
@hackerwins hackerwins mentioned this pull request May 1, 2026
3 tasks
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