Add block type extensions for docs word processor (Phase 1)#83
Conversation
Co-Authored-By: Claude Opus 4.6 <[email protected]>
When createBlock('heading') is called without opts, headingLevel now
defaults to 1 instead of being left undefined. Added tests for
list-item and heading defaults without opts, plus parameterized
coverage for all six heading levels via getHeadingDefaults.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Heading Enter creates a paragraph. List Enter inherits list type. Empty list Enter exits the list. HR Enter creates a paragraph after. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Heading blocks now render with their default font size and weight. The resolveBlockInlines() helper merges heading defaults as a base layer before measurement, so explicit inline styles still override. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Apply list-level-based left margin indent in computeLayout() for list-item blocks. Render bullet/number markers in DocCanvas on the first line of each list-item block, using UNORDERED_MARKERS for bullets and placeholder numbering for ordered lists. Co-Authored-By: Claude Opus 4.6 <[email protected]>
HR blocks get a fixed 20px height with no text runs in layout, and render as a thin horizontal line spanning the content area. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Enter on heading creates paragraph. Tab/Shift+Tab changes list level. Enter on empty list exits list. HR blocks prevent text input. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add three new methods to the EditorAPI interface and implementation so the toolbar and external code can query and mutate block types. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add block-type controls to the docs formatting toolbar: - Heading dropdown with Normal text and Heading 1-6 options - Bulleted list toggle button - Numbered list toggle button Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
All five Phase 1 items done: heading (H1-H6), lists (ordered/unordered), horizontal rule, layout engine branching, and Yorkie serialization. Co-Authored-By: Claude Opus 4.6 <[email protected]>
When a list-item block has no text, resolvePositionPixel() fell back to pageX + margins.left, ignoring the block's marginLeft (which includes the list indent). The cursor appeared before the bullet marker instead of after it. Add blockMarginLeft to the empty-line fallback. Co-Authored-By: Claude Opus 4.6 <[email protected]>
When a list-item block has no text, resolvePositionPixel() fell back to pageX + margins.left, ignoring the list indent. The LayoutBlock stores the original block (not the effectiveBlock with added marginLeft), so we must compute the list indent directly using LIST_INDENT_PX. Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add 'title' and 'subtitle' to BlockType union - Title defaults: 26pt, no bold. Subtitle defaults: 15pt, gray (#666666) - resolveBlockInlines() applies title/subtitle defaults like headings - Toolbar dropdown redesigned: shows current style name, styled previews for Normal text, Title, Subtitle, Heading 1-3 Co-Authored-By: Claude Opus 4.6 <[email protected]>
Call editor.focus() after style dropdown, list toggle, alignment, and text color changes so the user can keep typing without clicking back into the canvas. Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add indent() and outdent() to EditorAPI (36px step, matching list indent) - Add decrease/increase indent buttons to toolbar with focus return Co-Authored-By: Claude Opus 4.6 <[email protected]>
Toolbar now groups as: Undo/Redo | Styles | Font Styles | Block Styles, matching Google Docs toolbar organization for better discoverability. Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add backgroundColor to InlineStyle for text highlighting - Render highlight as filled rect behind text in doc-canvas - Replace strikethrough toolbar button with highlight color picker - Fix indent/outdent for list items to change listLevel instead of marginLeft, so the bullet marker moves with the text Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughAdds multi-block types (title, subtitle, heading, list-item, horizontal-rule), inline highlight/backgroundColor, list indentation and counters, type-aware split/merge and setBlockType APIs, layout/rendering updates (justify, HR, list markers), editor keyboard/toolbar controls, Yorkie serialization for new fields, and matching tests and docs updates. Changes
Sequence DiagramsequenceDiagram
participant User
participant TextEditor
participant EditorAPI
participant Doc
participant YorkieStore
participant Layout
participant DocCanvas
User->>TextEditor: keyboard / toolbar input
TextEditor->>EditorAPI: request (setBlockType / toggleList / indent / outdent / getBlockType)
EditorAPI->>Doc: apply mutation (setBlockType / split / indent logic)
Doc->>YorkieStore: snapshot & persist changes
YorkieStore-->>Doc: persist confirmed
EditorAPI->>Layout: computeLayout(blocks)
Layout->>Layout: computeListCounters(...)
EditorAPI->>DocCanvas: render(pagination, layout)
DocCanvas->>DocCanvas: resolveBlockInlines, render runs, markers, HRs
DocCanvas->>User: updated canvas
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 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 105.0s
Verification: verify:integrationResult: ✅ PASS |
- Cmd+Shift+7: toggle numbered list - Cmd+Shift+8: toggle bulleted list - Cmd+]: increase indent - Cmd+[: decrease indent - Show shortcut hints in toolbar tooltips for all new buttons Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (7)
packages/frontend/src/app/docs/docs-formatting-toolbar.tsx (1)
165-170: Avoid callinggetBlockType()twice.
editor.getBlockType()is invoked twice in adjacent lines. Store the result in a variable to avoid redundant computation.♻️ Proposed fix
<span className="truncate"> - {editor ? getBlockLabel( - editor.getBlockType().type, - editor.getBlockType().headingLevel, - ) : "Normal text"} + {editor ? (() => { + const blockType = editor.getBlockType(); + return getBlockLabel(blockType.type, blockType.headingLevel); + })() : "Normal text"} </span>Alternatively, compute this outside the JSX for better readability:
const currentBlockType = editor?.getBlockType(); const blockLabel = currentBlockType ? getBlockLabel(currentBlockType.type, currentBlockType.headingLevel) : "Normal text";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frontend/src/app/docs/docs-formatting-toolbar.tsx` around lines 165 - 170, The JSX calls editor.getBlockType() twice; cache its result to avoid redundant calls by creating a local variable (e.g., currentBlockType) before the return and use that when computing the label via getBlockLabel(currentBlockType.type, currentBlockType.headingLevel) or falling back to "Normal text"; update the span to use the cached blockLabel/currentBlockType instead of calling editor.getBlockType() again so only one getBlockType() invocation occurs.packages/docs/src/view/text-editor.ts (1)
724-739: Extract max list level to a named constant.The maximum list level of
8appears as a magic number. Consider defining it as a constant (possibly inmodel/types.tsalongsideLIST_INDENT_PX) for consistency witheditor.tswhich also needs this bound.♻️ Proposed improvement
+const MAX_LIST_LEVEL = 8; + private handleTab(shift: boolean): void { const block = this.doc.getBlock(this.cursor.position.blockId); if (block.type !== 'list-item') return; this.saveSnapshot(); const currentLevel = block.listLevel ?? 0; - const newLevel = shift ? Math.max(0, currentLevel - 1) : Math.min(8, currentLevel + 1); + const newLevel = shift ? Math.max(0, currentLevel - 1) : Math.min(MAX_LIST_LEVEL, currentLevel + 1); if (newLevel === currentLevel) return;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/docs/src/view/text-editor.ts` around lines 724 - 739, Replace the magic number 8 in handleTab with a named constant: define e.g. LIST_MAX_LEVEL (or MAX_LIST_LEVEL) next to LIST_INDENT_PX in model/types.ts, export it, and import it into packages/docs/src/view/text-editor.ts; then use LIST_MAX_LEVEL in the Math.min call when computing newLevel and update any other places (like editor.ts) that currently use 8 to reference the same exported constant so the bound is consistent across the codebase.packages/docs/src/view/doc-canvas.ts (3)
272-286: Remove unusedlineXparameter.The
lineXparameter is passed torenderListMarkerbut never used in the function body. Either remove it or document why it's reserved for future use.♻️ Proposed fix
private renderListMarker( block: Block, - lineX: number, lineY: number, lineHeight: number, markerX: number, markerText: string, ): void {And update the call site at line 164:
- this.renderListMarker(block, pageX + pl.x, pageY + pl.y, pl.line.height, markerX, marker); + this.renderListMarker(block, pageY + pl.y, pl.line.height, markerX, marker);🤖 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 272 - 286, The renderListMarker function signature includes an unused parameter lineX; remove lineX from the parameter list in renderListMarker and update every call site that passes lineX to instead pass only the remaining parameters (ensure calls to renderListMarker now match the new signature: (block, lineY, lineHeight, markerX, markerText)); after changes, run the TypeScript build to catch any missed call sites and adjust any affected variable names or argument ordering accordingly.
160-160: Document the magic number in marker positioning.The
-4offset in the marker X calculation lacks explanation. Consider extracting it to a named constant or adding a comment explaining its purpose (e.g., visual centering adjustment).📝 Suggested improvement
+ const MARKER_OFFSET_ADJUSTMENT = 4; // Fine-tune horizontal centering of marker glyph - const markerX = pageX + margins.left + LIST_INDENT_PX * level + LIST_INDENT_PX / 2 - 4; + const markerX = pageX + margins.left + LIST_INDENT_PX * level + LIST_INDENT_PX / 2 - MARKER_OFFSET_ADJUSTMENT;🤖 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` at line 160, The marker X position uses a unexplained magic offset (-4) in the calculation for markerX; replace this literal with a clearly named constant (e.g., MARKER_CENTER_OFFSET_PX or LIST_MARKER_VISUAL_ADJUST_PX) or add an inline comment explaining it is a visual centering adjustment, and update the expression where markerX is computed so the constant name (or comment) documents purpose; ensure the new constant is colocated near related layout constants (like LIST_INDENT_PX) for discoverability.
68-68: Consider caching list counters during layout computation.
computeListCountersis called on every render frame. For documents with many list items, this may introduce unnecessary overhead. Since list counters only change when document structure changes, consider computing them once duringcomputeLayoutand including them inDocumentLayout.🤖 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` at line 68, computeListCounters is being recomputed on every render (call at doc-canvas: listCounters = computeListCounters(layout.blocks.map(b => b.block))), causing unnecessary work; move its computation into computeLayout and store the result on the returned DocumentLayout so renders reuse it. Update computeLayout (and the DocumentLayout type) to produce a listCounters Map<string,string> alongside existing layout data, remove the computeListCounters call from render (doc-canvas) and read layout.listCounters instead, and ensure any code paths that mutate document structure trigger a recompute via computeLayout so the cached counters stay correct.packages/docs/src/view/layout.ts (1)
161-163: Consider extractingHR_HEIGHTas a module-level constant.The horizontal rule height is defined inline. If this value is needed elsewhere (e.g., for cursor positioning or rendering), extracting it would improve maintainability.
♻️ Proposed improvement
+/** Fixed height for horizontal-rule blocks in pixels. */ +const HR_HEIGHT = 20; + // In computeLayout: if (block.type === 'horizontal-rule') { - const HR_HEIGHT = 20; lines = [{ runs: [], y: 0, height: HR_HEIGHT, width: availableWidth }];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/docs/src/view/layout.ts` around lines 161 - 163, Extract the inline HR_HEIGHT constant used in the horizontal-rule branch into a module-level (and exported if used elsewhere) constant like HORIZONTAL_RULE_HEIGHT so other code (cursor positioning or render logic) can reuse it; update the branch where block.type === 'horizontal-rule' to reference the new module-level constant (instead of the local HR_HEIGHT) and adjust any other places that need the same value to import/use that constant to keep a single source of truth.packages/docs/src/view/editor.ts (1)
576-580: Consider sharingINDENT_STEPconstant withLIST_INDENT_PX.
INDENT_STEP = 36is defined locally and matchesLIST_INDENT_PXfrommodel/types.ts. Using the shared constant would ensure they stay synchronized.♻️ Proposed fix
Add to imports:
-import type { InlineStyle, BlockStyle, BlockType, HeadingLevel } from '../model/types.js'; +import type { InlineStyle, BlockStyle, BlockType, HeadingLevel } from '../model/types.js'; +import { LIST_INDENT_PX } from '../model/types.js';Then use it:
} else { - const INDENT_STEP = 36; doc.applyBlockStyle(block.id, { - marginLeft: (block.style.marginLeft ?? 0) + INDENT_STEP, + marginLeft: (block.style.marginLeft ?? 0) + LIST_INDENT_PX, }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/docs/src/view/editor.ts` around lines 576 - 580, Replace the local INDENT_STEP = 36 with the shared constant LIST_INDENT_PX from the model types so the indent step stays synchronized; import LIST_INDENT_PX and use it in the doc.applyBlockStyle call (referencing block.id and block.style.marginLeft) instead of defining INDENT_STEP locally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/docs/src/model/document.ts`:
- Around line 158-169: The Backspace merge path allows merging a text paragraph
into a non-text block (e.g., 'horizontal-rule'), causing the paragraph text to
be lost; modify deleteBackward() and/or mergeBlocks() to guard against merging
into non-text blocks by checking the target block's type (e.g., block.type ===
'horizontal-rule') and either (a) refuse the merge and return early, or (b)
convert the non-text block into a text-capable block (create a paragraph block
with inlines) before merging; update the logic in mergeBlocks() and the caller
deleteBackward() to detect non-text block types and handle them explicitly so
text never gets merged into a non-text block.
- Around line 272-296: When changing a block's type in setBlockType, also
normalize block.inlines to maintain the invariant: if the new type is
'horizontal-rule' set block.inlines = [] (dropping any hidden text), and if
switching from 'horizontal-rule' to an editable type ensure block.inlines =
[{type: 'text', text: ''}] (a single empty inline) so methods like insertText()
and resolveOffset() can operate safely; update block.inlines before calling
this.store.updateBlock(blockId, block) and this.refresh().
In `@packages/docs/src/view/editor.ts`:
- Around line 567-584: The indent() method can increase list nesting without an
upper bound; update indent() to cap the computed newLevel to the same maximum
used by handleTab() (e.g., 8) before calling doc.setBlockType for list-item
blocks; locate the indent() function and the doc.setBlockType call and clamp
newLevel = Math.min(newLevel, MAX_LIST_LEVEL) (or equivalent) so toolbar
indentation and text-editor.handleTab() use the same limit; no changes needed
for INDENT_STEP branch.
In `@packages/docs/test/model/document.test.ts`:
- Around line 282-328: Add two regression tests inside the existing "splitBlock
— type-aware" describe: one that creates a horizontal-rule then a paragraph (use
Doc.create(), setBlockType(...,'horizontal-rule'), splitBlock(...,0) or insert a
following paragraph) and then simulates backspace at the start of that paragraph
(call the model's deleteBackward / backspace API on the new paragraph at offset
0) asserting the rule is preserved/merged correctly and no invalid state occurs;
and a second test that exercises paragraph ↔ horizontal-rule transitions
(setBlockType to 'horizontal-rule' then convert back to 'paragraph' and
vice‑versa, using splitBlock, setBlockType and insertText) and asserts there is
no leftover hidden text or an empty-inline invalid state (inspect
block.inlineChildren or block.content and block.type invariants). Reference
Doc.create, setBlockType, splitBlock, insertText and the model's
deleteBackward/backspace method to locate where to add the checks.
In `@packages/frontend/src/app/docs/yorkie-doc-store.ts`:
- Around line 149-164: The deserializer always synthesizes a single empty inline
into block.inlines, which turns non-text blocks like
createBlock('horizontal-rule') (which should have inlines: []) back into
text-bearing blocks; update the block construction so the inlines fallback is
only applied for text-bearing block types (e.g.,
paragraph/heading/code/blockquote or whatever set your app treats as text
blocks). Concretely, change the inlines initialization in the block object (the
local variable block in yorkie-doc-store.ts) to test attrs.type (or the computed
block.type) and only set inlines: [{ text: '', style: {} }] when the type is a
text block; leave inlines as [] for non-text types (so
createBlock('horizontal-rule') remains line-less). Ensure subsequent
headingLevel/listKind/listLevel handling is unchanged.
---
Nitpick comments:
In `@packages/docs/src/view/doc-canvas.ts`:
- Around line 272-286: The renderListMarker function signature includes an
unused parameter lineX; remove lineX from the parameter list in renderListMarker
and update every call site that passes lineX to instead pass only the remaining
parameters (ensure calls to renderListMarker now match the new signature:
(block, lineY, lineHeight, markerX, markerText)); after changes, run the
TypeScript build to catch any missed call sites and adjust any affected variable
names or argument ordering accordingly.
- Line 160: The marker X position uses a unexplained magic offset (-4) in the
calculation for markerX; replace this literal with a clearly named constant
(e.g., MARKER_CENTER_OFFSET_PX or LIST_MARKER_VISUAL_ADJUST_PX) or add an inline
comment explaining it is a visual centering adjustment, and update the
expression where markerX is computed so the constant name (or comment) documents
purpose; ensure the new constant is colocated near related layout constants
(like LIST_INDENT_PX) for discoverability.
- Line 68: computeListCounters is being recomputed on every render (call at
doc-canvas: listCounters = computeListCounters(layout.blocks.map(b =>
b.block))), causing unnecessary work; move its computation into computeLayout
and store the result on the returned DocumentLayout so renders reuse it. Update
computeLayout (and the DocumentLayout type) to produce a listCounters
Map<string,string> alongside existing layout data, remove the
computeListCounters call from render (doc-canvas) and read layout.listCounters
instead, and ensure any code paths that mutate document structure trigger a
recompute via computeLayout so the cached counters stay correct.
In `@packages/docs/src/view/editor.ts`:
- Around line 576-580: Replace the local INDENT_STEP = 36 with the shared
constant LIST_INDENT_PX from the model types so the indent step stays
synchronized; import LIST_INDENT_PX and use it in the doc.applyBlockStyle call
(referencing block.id and block.style.marginLeft) instead of defining
INDENT_STEP locally.
In `@packages/docs/src/view/layout.ts`:
- Around line 161-163: Extract the inline HR_HEIGHT constant used in the
horizontal-rule branch into a module-level (and exported if used elsewhere)
constant like HORIZONTAL_RULE_HEIGHT so other code (cursor positioning or render
logic) can reuse it; update the branch where block.type === 'horizontal-rule' to
reference the new module-level constant (instead of the local HR_HEIGHT) and
adjust any other places that need the same value to import/use that constant to
keep a single source of truth.
In `@packages/docs/src/view/text-editor.ts`:
- Around line 724-739: Replace the magic number 8 in handleTab with a named
constant: define e.g. LIST_MAX_LEVEL (or MAX_LIST_LEVEL) next to LIST_INDENT_PX
in model/types.ts, export it, and import it into
packages/docs/src/view/text-editor.ts; then use LIST_MAX_LEVEL in the Math.min
call when computing newLevel and update any other places (like editor.ts) that
currently use 8 to reference the same exported constant so the bound is
consistent across the codebase.
In `@packages/frontend/src/app/docs/docs-formatting-toolbar.tsx`:
- Around line 165-170: The JSX calls editor.getBlockType() twice; cache its
result to avoid redundant calls by creating a local variable (e.g.,
currentBlockType) before the return and use that when computing the label via
getBlockLabel(currentBlockType.type, currentBlockType.headingLevel) or falling
back to "Normal text"; update the span to use the cached
blockLabel/currentBlockType instead of calling editor.getBlockType() again so
only one getBlockType() invocation occurs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e091d336-faa1-45c4-b6de-3ad344212e22
📒 Files selected for processing (14)
docs/tasks/active/20260325-docs-wordprocessor-todo.mdpackages/docs/src/index.tspackages/docs/src/model/document.tspackages/docs/src/model/types.tspackages/docs/src/view/doc-canvas.tspackages/docs/src/view/editor.tspackages/docs/src/view/layout.tspackages/docs/src/view/peer-cursor.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/frontend/src/app/docs/docs-formatting-toolbar.tsxpackages/frontend/src/app/docs/yorkie-doc-store.ts
- Cmd+Shift+L/E/R/J: left/center/right/justify alignment - Add justify alignment to BlockStyle and layout engine - Show shortcut hints in style and alignment dropdown items - Cmd+Shift+7/8: numbered/bulleted list (from prior commit) Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/frontend/src/app/docs/docs-formatting-toolbar.tsx (1)
165-170: Minor optimization: avoid duplicategetBlockType()call.
editor.getBlockType()is called twice. Consider destructuring once for slightly cleaner code:♻️ Proposed refactor
- {editor ? getBlockLabel( - editor.getBlockType().type, - editor.getBlockType().headingLevel, - ) : "Normal text"} + {editor + ? (() => { + const { type, headingLevel } = editor.getBlockType(); + return getBlockLabel(type, headingLevel); + })() + : "Normal text"}Or extract to a local variable before the JSX.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frontend/src/app/docs/docs-formatting-toolbar.tsx` around lines 165 - 170, The JSX calls editor.getBlockType() twice; to avoid the duplicate call, read and destructure the block type once into a local variable (e.g., const blockType = editor.getBlockType()) before the return/JSX and then pass blockType.type and blockType.headingLevel into getBlockLabel; update the span to use that local variable and keep the fallback "Normal text" when editor is falsy.packages/docs/src/view/text-editor.ts (1)
780-796: Inconsistent max indent level between Tab and Cmd+].
handleTabcaps the list level at 8 (line 754:Math.min(8, currentLevel + 1)), buthandleIndenthas no upper bound (line 787:(block.listLevel ?? 0) + 1). This allows unbounded nesting via Cmd+] while Tab is constrained.Consider applying the same cap for consistency:
♻️ Proposed fix to add consistent max level
private handleIndent(): void { const INDENT_STEP = 36; + const MAX_LIST_LEVEL = 8; const block = this.doc.getBlock(this.cursor.position.blockId); this.saveSnapshot(); if (block.type === 'list-item') { + const newLevel = Math.min(MAX_LIST_LEVEL, (block.listLevel ?? 0) + 1); this.doc.setBlockType(block.id, 'list-item', { listKind: block.listKind, - listLevel: (block.listLevel ?? 0) + 1, + listLevel: newLevel, }); } else {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/docs/src/view/text-editor.ts` around lines 780 - 796, handleIndent currently increases list nesting without an upper bound causing inconsistency with handleTab; update handleIndent to cap the list level the same way (use Math.min(8, (block.listLevel ?? 0) + 1)) when calling this.doc.setBlockType for list-item blocks, and ensure non-list indentation remains unchanged (INDENT_STEP logic for applyBlockStyle stays as-is); locate handleIndent, INDENT_STEP, getBlock, saveSnapshot, setBlockType, and applyBlockStyle to make the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/docs/src/view/text-editor.ts`:
- Around line 780-796: handleIndent currently increases list nesting without an
upper bound causing inconsistency with handleTab; update handleIndent to cap the
list level the same way (use Math.min(8, (block.listLevel ?? 0) + 1)) when
calling this.doc.setBlockType for list-item blocks, and ensure non-list
indentation remains unchanged (INDENT_STEP logic for applyBlockStyle stays
as-is); locate handleIndent, INDENT_STEP, getBlock, saveSnapshot, setBlockType,
and applyBlockStyle to make the change.
In `@packages/frontend/src/app/docs/docs-formatting-toolbar.tsx`:
- Around line 165-170: The JSX calls editor.getBlockType() twice; to avoid the
duplicate call, read and destructure the block type once into a local variable
(e.g., const blockType = editor.getBlockType()) before the return/JSX and then
pass blockType.type and blockType.headingLevel into getBlockLabel; update the
span to use that local variable and keep the fallback "Normal text" when editor
is falsy.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a3126b73-6beb-4df6-ab57-60730e242110
📒 Files selected for processing (2)
packages/docs/src/view/text-editor.tspackages/frontend/src/app/docs/docs-formatting-toolbar.tsx
Phase 1 fully complete with additional items: Title/Subtitle, justify alignment, highlight color, keyboard shortcuts with toolbar hints. Mark Phase 2.2 (highlight) as done early. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Address CodeRabbit review feedback: - Guard deleteBackward from merging text into horizontal-rule blocks - Normalize inlines in setBlockType (HR gets [], text types get [empty]) - Cap list indent level at 8 in both editor.ts and text-editor.ts - Fix Yorkie deserialization to keep HR blocks inline-free - Add regression tests for HR edge cases Co-Authored-By: Claude Opus 4.6 <[email protected]>
toggleStyle was always applying { bold: true } etc. instead of
checking the current style and flipping it. Now reads the inline
style at cursor position and inverts boolean properties.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Remove unused lineX parameter from renderListMarker, remove unused imports, and add missing textIndent/marginLeft fields to BlockStyle test fixtures. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace pattern-tiling with Google Sheets-style OLS (Ordinary Least Squares) regression for numeric cell autofill. When 2+ numeric cells exist along the fill axis, compute y = mx + b and extrapolate the trend. Mixed content (formulas, text, empty) falls back to existing tiling behavior. Use single-fraction computation with toPrecision(15) to minimize IEEE 754 floating-point drift, matching Excel/Google Sheets precision. Also fix docs package build and frontend test failures introduced by PR #83/#84: refactor TypeScript parameter properties and const enum unsupported by Node's --experimental-strip-types, remove unused parameters/imports, and add missing BlockStyle fields in test fixtures. Co-authored-by: Claude Opus 4.6 <[email protected]>
Summary
Test plan
pnpm verify:fastpasses (lint + all unit tests)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation