Skip to content

Extend outline borders across row/column insertion seam#165

Merged
hackerwins merged 1 commit into
mainfrom
feat/border-outline-extension
Apr 28, 2026
Merged

Extend outline borders across row/column insertion seam#165
hackerwins merged 1 commit into
mainfrom
feat/border-outline-extension

Conversation

@hackerwins

@hackerwins hackerwins commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Per-cell custom borders (bt/bl/br/bb) did not extend into rows/columns inserted inside an outer-bordered range, so an outline drawn on A1:B2 visibly broke when a row was inserted between rows 1 and 2.
  • After the cell shift in Sheet.shiftCells, scan the two cells flanking the insertion seam in each populated column/row and copy borders that were continuous across the seam onto the inserted cells — matching Google Sheets behavior.
  • Only populated rows/columns are scanned (via the cell index), so the extra work scales with data density, not sheet size.

Test plan

  • pnpm --filter @wafflebase/sheets test test/sheet/formatting.test.ts — 3 new tests pass (row insert, column insert, insert outside range)
  • pnpm --filter @wafflebase/sheets test — 1207 sheets tests pass
  • pnpm verify:fast — sheets 1207 + docs 622 + backend 107 + 60 other, all pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Border styles now automatically propagate across newly inserted rows and columns to maintain seamless visual continuity, aligned with standard spreadsheet applications.
  • Tests

    • Added new tests ensuring correct border continuity behavior when inserting rows and columns within bordered ranges.
  • Documentation

    • Updated design documentation with border propagation specifications.

Custom borders are stored on individual cells, so the existing
range-patch shifting did not handle them — inserting a row inside
an outer-bordered range left the new row without left/right borders
and visibly broke the outline.

After the cell shift, scan the two cells flanking the insertion seam
in each populated column (row insert) or row (column insert) and copy
the borders that ran continuously across the seam onto the inserted
cells. This matches Google Sheets behavior: an outer border on A1:B2
stays connected when a row is inserted between rows 1 and 2.

Only populated rows/columns are scanned (via the cell index), so the
extra work is bounded by data density, not sheet size.
@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This pull request implements border outline extension functionality for the Sheets model. When rows or columns are inserted, border flags from cells adjacent to the insertion seam are propagated onto the newly inserted cells, matching Google Sheets behavior and maintaining visual continuity of outlined ranges.

Changes

Cohort / File(s) Summary
Border Extension Design & Tasks
docs/design/sheets/sheet-style.md, docs/tasks/archive/2026/04/20260428-border-outline-extension-todo.md, docs/tasks/archive/README.md, docs/tasks/README.md
Documentation and task tracking for border outline extension feature, including design specification of seam-based border propagation rules and archived task entry with implementation details and test results.
Core Border Propagation
packages/sheets/src/model/worksheet/sheet.ts
New private extendBordersAcrossInsertion method added to Sheet class that runs during shiftCells when inserting rows or columns. Detects matching border flags on cells flanking the insertion seam and applies them to all newly inserted cells along that seam.
Border Extension Tests
packages/sheets/test/sheet/formatting.test.ts
Three new test cases verifying outline border continuity: row insertion between bordered cells inherits left/right borders, column insertion between bordered cells inherits top/bottom borders, and insertion outside bordered ranges does not propagate styles.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A border's kiss across the seam,
Where rows and columns split their dream—
The outline holds, unbroken, true,
As new cells inherit what came through! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Extend outline borders across row/column insertion seam' accurately describes the main change: adding logic to propagate custom border styles when inserting rows/columns inside a bordered range to match Google Sheets behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ 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 feat/border-outline-extension

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 28, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 122.0s

Lane Status Duration
sheets:build ✅ pass 14.1s
docs:build ✅ pass 8.1s
verify:fast ✅ pass 61.2s
frontend:build ✅ pass 15.7s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.8s
cli:build ✅ pass 1.8s
verify:entropy ✅ pass 15.9s

Verification: verify:integration

Result: ✅ PASS

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/sheets/test/sheet/formatting.test.ts (1)

383-505: Optional: add a count > 1 insertion case.

A multi-insert variant would further lock in the index + count seam lookup and inserted-span loop behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sheets/test/sheet/formatting.test.ts` around lines 383 - 505, Add a
test that inserts more than one row/column inside a bordered range to exercise
the index+count seam logic: reuse Sheet, MemStore, selectStart/selectEnd,
setRangeBorders('outer') then call insertRows(startIndex, count>1) and
insertColumns(startIndex, count>1) and assert that (1) the newly inserted span
inherits the correct outer-edge borders across all inserted cells (e.g.,
left-edge for all inserted rows in column X or top-edge for all inserted columns
in row Y), (2) no interior top/bottom or left/right borders are spuriously set
on those inserted cells, and (3) the original bordered cells after the insertion
have been shifted by count with their original borders intact using getStyle to
verify both edge cases; place tests near the existing insertRows/insertColumns
cases to cover multi-insert behavior.
packages/sheets/src/model/worksheet/sheet.ts (1)

1162-1168: Prefer bounded seam ranges over Number.MAX_SAFE_INTEGER.

Clamping to sheet dimensions keeps the query window explicit and avoids relying on store-specific handling of very large bounds.

♻️ Suggested refactor
-    const upper = Number.MAX_SAFE_INTEGER;
-    const beforeRange: Range = axis === 'row'
-      ? [{ r: index - 1, c: 1 }, { r: index - 1, c: upper }]
-      : [{ r: 1, c: index - 1 }, { r: upper, c: index - 1 }];
-    const afterRange: Range = axis === 'row'
-      ? [{ r: index + count, c: 1 }, { r: index + count, c: upper }]
-      : [{ r: 1, c: index + count }, { r: upper, c: index + count }];
+    const maxRow = this.dimension.rows;
+    const maxCol = this.dimension.columns;
+    const beforeRange: Range = axis === 'row'
+      ? [{ r: index - 1, c: 1 }, { r: index - 1, c: maxCol }]
+      : [{ r: 1, c: index - 1 }, { r: maxRow, c: index - 1 }];
+    const afterRange: Range = axis === 'row'
+      ? [{ r: index + count, c: 1 }, { r: index + count, c: maxCol }]
+      : [{ r: 1, c: index + count }, { r: maxRow, c: index + count }];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sheets/src/model/worksheet/sheet.ts` around lines 1162 - 1168, The
ranges beforeRange and afterRange use Number.MAX_SAFE_INTEGER as an unbounded
upper coordinate; replace that with the worksheet's actual max row/column bounds
by clamping using the sheet dimensions (e.g. this.getRowCount()/this.rowCount
and this.getColCount()/this.colCount or equivalent accessors on the worksheet)
so upper is set to the appropriate max for the current axis; update the creation
of beforeRange and afterRange (which use axis, index, count and type Range) to
compute upperRow = min(this.maxRows, Number.MAX_SAFE_INTEGER) and upperCol =
min(this.maxCols, Number.MAX_SAFE_INTEGER) (or simply use the worksheet maxs)
and use those bounded values instead of Number.MAX_SAFE_INTEGER.
🤖 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/sheets/src/model/worksheet/sheet.ts`:
- Around line 1162-1168: The ranges beforeRange and afterRange use
Number.MAX_SAFE_INTEGER as an unbounded upper coordinate; replace that with the
worksheet's actual max row/column bounds by clamping using the sheet dimensions
(e.g. this.getRowCount()/this.rowCount and this.getColCount()/this.colCount or
equivalent accessors on the worksheet) so upper is set to the appropriate max
for the current axis; update the creation of beforeRange and afterRange (which
use axis, index, count and type Range) to compute upperRow = min(this.maxRows,
Number.MAX_SAFE_INTEGER) and upperCol = min(this.maxCols,
Number.MAX_SAFE_INTEGER) (or simply use the worksheet maxs) and use those
bounded values instead of Number.MAX_SAFE_INTEGER.

In `@packages/sheets/test/sheet/formatting.test.ts`:
- Around line 383-505: Add a test that inserts more than one row/column inside a
bordered range to exercise the index+count seam logic: reuse Sheet, MemStore,
selectStart/selectEnd, setRangeBorders('outer') then call insertRows(startIndex,
count>1) and insertColumns(startIndex, count>1) and assert that (1) the newly
inserted span inherits the correct outer-edge borders across all inserted cells
(e.g., left-edge for all inserted rows in column X or top-edge for all inserted
columns in row Y), (2) no interior top/bottom or left/right borders are
spuriously set on those inserted cells, and (3) the original bordered cells
after the insertion have been shifted by count with their original borders
intact using getStyle to verify both edge cases; place tests near the existing
insertRows/insertColumns cases to cover multi-insert behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc47566c-9f14-4b3e-9909-2d4d3add7e85

📥 Commits

Reviewing files that changed from the base of the PR and between f564d04 and bb1bccc.

📒 Files selected for processing (6)
  • docs/design/sheets/sheet-style.md
  • docs/tasks/README.md
  • docs/tasks/archive/2026/04/20260428-border-outline-extension-todo.md
  • docs/tasks/archive/README.md
  • packages/sheets/src/model/worksheet/sheet.ts
  • packages/sheets/test/sheet/formatting.test.ts

@codecov

codecov Bot commented Apr 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.30508% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/sheets/src/model/worksheet/sheet.ts 98.30% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@hackerwins

Copy link
Copy Markdown
Collaborator Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

@hackerwins
hackerwins merged commit b22f156 into main Apr 28, 2026
4 checks passed
@hackerwins
hackerwins deleted the feat/border-outline-extension branch April 28, 2026 12:28
@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