Skip to content

Commit 74d5c0c

Browse files
hackerwinsclaude
andcommitted
Fix multi-line text selection rendering in nested table cells
buildRects() now uses resolveNestedTableLayout() to find the inner LayoutTableCell and compute correct cell boundaries (cellLeftX, cellRightX) and line Y positions with nested coordinate offsets. Replaces the bounding-box fallback with proper line-by-line selection rects matching the non-nested table path. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent fa78446 commit 74d5c0c

1 file changed

Lines changed: 30 additions & 20 deletions

File tree

packages/docs/src/view/selection.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -284,30 +284,21 @@ function buildRects(
284284
// "advance midY by line height" path stepped linearly through the
285285
// cell's Y axis and painted into the empty space below row 0 when a
286286
// merged cell's line actually lived on the next page.
287-
const lb = layout.blocks.find((b) => b.block.id === startCellInfo.tableBlockId);
288-
const tl = lb?.layoutTable;
289-
if (!lb || !tl) {
290-
// Nested table cell — the direct parent table is not a top-level
291-
// layout block. Use pixel coordinates from resolvePositionPixel
292-
// (which already handles nested tables) for selection rects.
293-
if (startPixel.y === endPixel.y) {
294-
return [{
295-
x: startPixel.x,
296-
y: startPixel.y,
297-
width: endPixel.x - startPixel.x,
298-
height: startPixel.height,
299-
}];
300-
}
287+
// Resolve the table that owns this cell — may be top-level or nested
288+
const resolved = resolveNestedTableLayout(startCellInfo.tableBlockId, layout);
289+
const lb = resolved ? layout.blocks[resolved.lb.blockIndex] : undefined;
290+
const tl = resolved?.layoutTable;
291+
if (!lb || !tl || !resolved) {
301292
return [{
302-
x: Math.min(startPixel.x, endPixel.x),
293+
x: startPixel.x,
303294
y: startPixel.y,
304-
width: Math.max(startPixel.x, endPixel.x) - Math.min(startPixel.x, endPixel.x),
295+
width: endPixel.x - startPixel.x,
305296
height: endPixel.y + endPixel.height - startPixel.y,
306297
}];
307298
}
308299
const { rowIndex, colIndex } = startCellInfo;
309300
const layoutCell = tl.cells[rowIndex]?.[colIndex];
310-
const cellData = lb.block.tableData?.rows[rowIndex]?.cells[colIndex];
301+
const cellData = resolved.dataBlock.tableData?.rows[rowIndex]?.cells[colIndex];
311302
if (!layoutCell || layoutCell.merged || !cellData) {
312303
return [{
313304
x: startPixel.x,
@@ -321,9 +312,10 @@ function buildRects(
321312

322313
const pageXOffset = getPageXOffset(paginatedLayout, canvasWidth);
323314
const { margins } = paginatedLayout.pageSetup;
324-
const cellLeftX = pageXOffset + margins.left + tl.columnXOffsets[colIndex] + cellPadding;
315+
const nestedXOff = resolved.xOffset;
316+
const cellLeftX = pageXOffset + margins.left + nestedXOff + tl.columnXOffsets[colIndex] + cellPadding;
325317
const cellRightX =
326-
pageXOffset + margins.left + tl.columnXOffsets[colIndex] + layoutCell.width - cellPadding;
318+
pageXOffset + margins.left + nestedXOff + tl.columnXOffsets[colIndex] + layoutCell.width - cellPadding;
327319

328320
// Locate the cell's block containing the start/end positions and the
329321
// corresponding line indices within cell.lines.
@@ -379,8 +371,26 @@ function buildRects(
379371
tl.rowHeights,
380372
);
381373

382-
const blockIndex = layout.blocks.indexOf(lb);
374+
const blockIndex = resolved.lb.blockIndex;
375+
const nestedYOff = resolved.yOffset;
376+
const isNested = resolved.outerRowIndex >= 0;
383377
const resolveLineAbsoluteY = (ownerRow: number, runLineY: number): number | undefined => {
378+
if (isNested) {
379+
// For nested tables, find the outer row's page position and
380+
// add the accumulated Y offset + inner row offset
381+
const outerRow = resolved.outerRowIndex;
382+
for (const page of paginatedLayout.pages) {
383+
for (const pl of page.lines) {
384+
if (pl.blockIndex === blockIndex && pl.lineIndex === outerRow) {
385+
const pageY = getPageYOffset(paginatedLayout, page.pageIndex);
386+
return pageY + pl.y + nestedYOff
387+
+ tl.rowYOffsets[ownerRow]
388+
+ (runLineY - tl.rowYOffsets[ownerRow]);
389+
}
390+
}
391+
}
392+
return undefined;
393+
}
384394
for (const page of paginatedLayout.pages) {
385395
for (const pl of page.lines) {
386396
if (pl.blockIndex === blockIndex && pl.lineIndex === ownerRow) {

0 commit comments

Comments
 (0)