Add manual page break (Phase 4.2)#109
Conversation
Phase 4.2 is no longer a non-goal. Document the data model, pagination behavior, rendering, input handling, and Yorkie serialization for the page-break block type. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Content-free block type following the horizontal-rule pattern.
createBlock('page-break') produces empty inlines.
Add page-break to splitBlock, deleteBackward, and setBlockType following the same non-editable pattern as horizontal-rule. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Same 20px height as horizontal-rule, no text runs.
Page-break line is placed on the current page, then startNewPage() is called so subsequent content begins on a fresh page.
Google Docs style: gray dashed lines flanking a centered 'Page break' text label. Uses setLineDash([4,4]) with #ccc stroke color. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Ctrl+Enter (Cmd+Enter on Mac) splits the block at cursor and inserts a page-break block between the halves. Text input is blocked on page-break blocks, same as horizontal-rule.
When reading back from Yorkie Tree, page-break blocks should produce empty inlines like horizontal-rule, not a default inline.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
When the cursor is on a page-break block and the user types, call ensureEditableBlock() to split and create a paragraph rather than silently discarding the input. The old return-early caused textarea contents to leak into adjacent blocks. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Set textBaseline to 'middle' so the label sits centered on the dashed line instead of floating above it. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
📝 WalkthroughWalkthroughThis PR implements the 'page-break' block type as a non-editable control block that forces pagination to start on a new page. The feature includes design documentation, an implementation plan, and code changes across the document model, layout/rendering, pagination, editor input handling, and Yorkie serialization. The implementation mirrors the existing 'horizontal-rule' pattern throughout. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Editor as text-editor
participant DocModel as Doc Model
participant Layout as computeLayout
participant Pagination as paginateLayout
participant Canvas as doc-canvas
User->>Editor: Press Ctrl+Enter
Editor->>Editor: handlePageBreak()
Editor->>DocModel: splitBlock(currentBlock, cursor)
DocModel->>DocModel: Create paragraph after split
Editor->>DocModel: insertBlockAt(pageBreakBlock)
DocModel->>DocModel: Insert 'page-break' between halves
Editor->>Layout: computeLayout(blocks)
Layout->>Layout: Detect 'page-break' type
Layout->>Layout: Assign HR_HEIGHT=20, zero runs
Layout->>Pagination: Process layout blocks
Pagination->>Pagination: Encounter 'page-break'
Pagination->>Pagination: startNewPage()
Pagination->>Canvas: Supply paginated layout
Canvas->>Canvas: Detect 'page-break' block
Canvas->>Canvas: Draw "Page break" label
Canvas->>Canvas: Draw dashed lines left & right
Canvas->>User: Render page-break indicator
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Verification: verify:selfResult: ✅ PASS in 111.3s
Verification: verify:integrationResult: ✅ PASS |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
packages/docs/src/view/doc-canvas.ts (1)
173-184: Consider extracting hardcoded styling values to Theme constants.The font (
'9px Arial'), colors ('#aaa','#ccc'), and dash pattern ([4, 4]) are hardcoded. For consistency with other rendering code that usesTheme.*constants, these could be centralized.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/docs/src/view/doc-canvas.ts` around lines 173 - 184, Extract the hardcoded styling in the Page break render block into Theme constants and use them instead of literals: replace this.ctx.font = '9px Arial' with Theme.pageBreakFont, this.ctx.fillStyle = Theme.pageBreakTextColor, this.ctx.strokeStyle = Theme.pageBreakLineColor and this.ctx.setLineDash([4,4]) with Theme.pageBreakDash (an array); also replace the hardcoded padding added to labelWidth (+16) with Theme.pageBreakLabelPadding and ensure the label string 'Page break' can be referenced as Theme.pageBreakLabel so all values (font, text color, line color, dash pattern, label padding, label text) are centralized for consistency in the DocCanvas page break rendering code.docs/design/docs/docs-pagination.md (1)
332-396: Comprehensive design documentation for Manual Page Break.The new section thoroughly documents all aspects of the page-break feature:
- Data model following the horizontal-rule pattern
- Pagination engine behavior with clear algorithm description
- Layout and rendering specifications
- Input handling including keyboard shortcuts
- Document model operations
- Yorkie serialization approach
One minor improvement: the pseudocode block at lines 362-365 could specify a language for consistency.
,
Optional: Add language to code block
-``` +```typescript const PAGE_BREAK_HEIGHT = 20; lines = [{ runs: [], y: 0, height: PAGE_BREAK_HEIGHT, width: availableWidth }];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/design/docs/docs-pagination.md` around lines 332 - 396, The code fence for the pseudocode in the computeLayout section is missing a language specifier; update the triple-backtick block that defines PAGE_BREAK_HEIGHT and lines (the snippet containing "const PAGE_BREAK_HEIGHT = 20;" and "lines = [{ runs: [], y: 0, height: PAGE_BREAK_HEIGHT, width: availableWidth }];") to use ```typescript so syntax highlighting and consistency match the rest of the docs.docs/tasks/active/20260408-page-break-todo.md (1)
11-13: Minor: Heading level jumps from h1 to h3.The document structure skips h2 and goes directly to h3 for "Task 1". Consider using h2 (
##) for task headers for proper document hierarchy, or add a "## Tasks" section header before the task list.Suggested fix
--- +## Tasks + ### Task 1: Add `page-break` to data model and createBlockOr change all
###task headers to##.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/tasks/active/20260408-page-break-todo.md` around lines 11 - 13, The document jumps from h1 to h3 for the task header "Task 1: Add `page-break` to data model and createBlock"; update the heading hierarchy by either changing the task header "### Task 1: Add `page-break` to data model and createBlock" to an h2 (replace ### with ##) or insert a parent "## Tasks" section above the task list so all task entries remain as h3—pick one approach and apply it consistently for other task headers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@docs/design/docs/docs-pagination.md`:
- Around line 332-396: The code fence for the pseudocode in the computeLayout
section is missing a language specifier; update the triple-backtick block that
defines PAGE_BREAK_HEIGHT and lines (the snippet containing "const
PAGE_BREAK_HEIGHT = 20;" and "lines = [{ runs: [], y: 0, height:
PAGE_BREAK_HEIGHT, width: availableWidth }];") to use ```typescript so syntax
highlighting and consistency match the rest of the docs.
In `@docs/tasks/active/20260408-page-break-todo.md`:
- Around line 11-13: The document jumps from h1 to h3 for the task header "Task
1: Add `page-break` to data model and createBlock"; update the heading hierarchy
by either changing the task header "### Task 1: Add `page-break` to data model
and createBlock" to an h2 (replace ### with ##) or insert a parent "## Tasks"
section above the task list so all task entries remain as h3—pick one approach
and apply it consistently for other task headers.
In `@packages/docs/src/view/doc-canvas.ts`:
- Around line 173-184: Extract the hardcoded styling in the Page break render
block into Theme constants and use them instead of literals: replace
this.ctx.font = '9px Arial' with Theme.pageBreakFont, this.ctx.fillStyle =
Theme.pageBreakTextColor, this.ctx.strokeStyle = Theme.pageBreakLineColor and
this.ctx.setLineDash([4,4]) with Theme.pageBreakDash (an array); also replace
the hardcoded padding added to labelWidth (+16) with Theme.pageBreakLabelPadding
and ensure the label string 'Page break' can be referenced as
Theme.pageBreakLabel so all values (font, text color, line color, dash pattern,
label padding, label text) are centralized for consistency in the DocCanvas page
break rendering code.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6941c5e9-db8c-46d9-8a4d-794ee5d3b9a1
📒 Files selected for processing (14)
docs/design/docs/docs-pagination.mddocs/tasks/active/20260325-docs-wordprocessor-todo.mddocs/tasks/active/20260408-page-break-todo.mdpackages/docs/src/model/document.tspackages/docs/src/model/types.tspackages/docs/src/view/doc-canvas.tspackages/docs/src/view/layout.tspackages/docs/src/view/pagination.tspackages/docs/src/view/text-editor.tspackages/docs/test/model/document.test.tspackages/docs/test/model/types.test.tspackages/docs/test/view/layout.test.tspackages/docs/test/view/pagination.test.tspackages/frontend/src/app/docs/yorkie-doc-store.ts
Summary
page-breakBlockType — content-free block following thehorizontal-rulepatternChanges
'page-break'added toBlockTypeunion,createBlockproduces empty inlinesstartNewPage()called after page-break line placementtextBaseline: 'middle'alignmentensureEditableBlockTest plan
pnpm verify:fastpasses🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes